Merge pull request #77 from kanthoney/joystick_configurator
Joystick configurator
This commit is contained in:
commit
1aa6022982
@ -175,6 +175,7 @@ OOLITE_ENTITY_FILES = \
|
||||
PlayerEntityScriptMethods.m \
|
||||
PlayerEntitySound.m \
|
||||
PlayerEntityStickMapper.m \
|
||||
PlayerEntityStickProfile.m \
|
||||
ProxyPlayerEntity.m \
|
||||
OOBreakPatternEntity.m \
|
||||
ShipEntity.m \
|
||||
@ -385,6 +386,7 @@ OOLITE_MISC_FILES = \
|
||||
GameController.m \
|
||||
GameController+SDLFullScreen.m \
|
||||
OOJoystickManager.m \
|
||||
OOJoystickProfile.m \
|
||||
OOSDLJoystickManager.m \
|
||||
main.m \
|
||||
MyOpenGLView.m \
|
||||
|
@ -37,6 +37,7 @@ MA 02110-1301, USA.
|
||||
@class GuiDisplayGen, OOTrumble, MyOpenGLView, HeadUpDisplay, ShipEntity;
|
||||
@class OOSound, OOSoundSource, OOSoundReferencePoint;
|
||||
@class OOJoystickManager, OOTexture, OOLaserShotEntity;
|
||||
@class StickProfileScreen;
|
||||
|
||||
#define ALLOW_CUSTOM_VIEWS_WHILE_PAUSED 1
|
||||
#define SCRIPT_TIMER_INTERVAL 10.0
|
||||
@ -612,6 +613,8 @@ typedef enum
|
||||
|
||||
ShipEntity *demoShip; // Used while docked to maintain demo ship rotation.
|
||||
OOLaserShotEntity *lastShot; // used to correctly position laser shots on first frame of firing
|
||||
|
||||
StickProfileScreen *stickProfileScreen;
|
||||
}
|
||||
|
||||
+ (PlayerEntity *) sharedPlayer;
|
||||
|
@ -80,6 +80,7 @@ MA 02110-1301, USA.
|
||||
|
||||
#import "OOJoystickManager.h"
|
||||
#import "PlayerEntityStickMapper.h"
|
||||
#import "PlayerEntityStickProfile.h"
|
||||
|
||||
|
||||
#define PLAYER_DEFAULT_NAME @"Jameson"
|
||||
@ -1740,6 +1741,8 @@ static GLfloat sBaseMass = 0.0;
|
||||
demoShip = nil;
|
||||
|
||||
[[OOMusicController sharedController] justStop];
|
||||
[stickProfileScreen release];
|
||||
stickProfileScreen = [[StickProfileScreen alloc] init];
|
||||
return YES;
|
||||
}
|
||||
|
||||
@ -2626,6 +2629,7 @@ static GLfloat sBaseMass = 0.0;
|
||||
case GUI_SCREEN_SAVE:
|
||||
case GUI_SCREEN_SAVE_OVERWRITE:
|
||||
case GUI_SCREEN_STICKMAPPER:
|
||||
case GUI_SCREEN_STICKPROFILE:
|
||||
case GUI_SCREEN_MISSION:
|
||||
case GUI_SCREEN_REPORT:
|
||||
return;
|
||||
|
@ -29,6 +29,7 @@ MA 02110-1301, USA.
|
||||
#import "PlayerEntitySound.h"
|
||||
#import "PlayerEntityLoadSave.h"
|
||||
#import "PlayerEntityStickMapper.h"
|
||||
#import "PlayerEntityStickProfile.h"
|
||||
|
||||
#import "ShipEntityAI.h"
|
||||
#import "StationEntity.h"
|
||||
@ -1428,7 +1429,7 @@ static NSTimeInterval time_last_frame;
|
||||
[self pollCustomViewControls]; // allow custom views during pause
|
||||
#endif
|
||||
|
||||
if (gui_screen == GUI_SCREEN_OPTIONS || gui_screen == GUI_SCREEN_GAMEOPTIONS || gui_screen == GUI_SCREEN_STICKMAPPER)
|
||||
if (gui_screen == GUI_SCREEN_OPTIONS || gui_screen == GUI_SCREEN_GAMEOPTIONS || gui_screen == GUI_SCREEN_STICKMAPPER || gui_screen == GUI_SCREEN_STICKPROFILE )
|
||||
{
|
||||
if ([UNIVERSE pauseMessageVisible]) [[UNIVERSE messageGUI] leaveLastLine];
|
||||
else [[UNIVERSE messageGUI] clear];
|
||||
@ -1903,7 +1904,7 @@ static NSTimeInterval time_last_frame;
|
||||
if (from_function < 0) from_function = 0;
|
||||
|
||||
[self setGuiToStickMapperScreen:from_function];
|
||||
if ([[UNIVERSE gui] selectedRow] < 0)
|
||||
if ([[UNIVERSE gui] selectedRow] < GUI_ROW_FUNCSTART)
|
||||
{
|
||||
[[UNIVERSE gui] setSelectedRow: GUI_ROW_FUNCSTART];
|
||||
}
|
||||
@ -1914,6 +1915,10 @@ static NSTimeInterval time_last_frame;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GUI_SCREEN_STICKPROFILE:
|
||||
[self stickProfileInputHandler: gui view: gameView];
|
||||
break;
|
||||
|
||||
case GUI_SCREEN_GAMEOPTIONS:
|
||||
[self handleGameOptionsScreenKeys];
|
||||
|
@ -32,10 +32,11 @@ MA 02110-1301, USA.
|
||||
#define MAX_ROWS_FUNCTIONS 12
|
||||
|
||||
#define GUI_ROW_STICKNAME 1
|
||||
#define GUI_ROW_HEADING 3
|
||||
#define GUI_ROW_FUNCSTART 4
|
||||
#define GUI_ROW_STICKPROFILE 2
|
||||
#define GUI_ROW_HEADING 4
|
||||
#define GUI_ROW_FUNCSTART 5
|
||||
#define GUI_ROW_FUNCEND (GUI_ROW_FUNCSTART + MAX_ROWS_FUNCTIONS - 1)
|
||||
#define GUI_ROW_INSTRUCT 17
|
||||
#define GUI_ROW_INSTRUCT 18
|
||||
|
||||
// Dictionary keys
|
||||
#define KEY_GUIDESC @"guiDesc"
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
PlayerEntityStickMapper.h
|
||||
PlayerEntityStickMapper.m
|
||||
|
||||
Oolite
|
||||
Copyright (C) 2004-2013 Giles C Williams and contributors
|
||||
@ -24,11 +24,11 @@ MA 02110-1301, USA.
|
||||
|
||||
#import "PlayerEntityStickMapper.h"
|
||||
#import "PlayerEntityControls.h"
|
||||
#import "PlayerEntityStickProfile.h"
|
||||
#import "OOJoystickManager.h"
|
||||
#import "OOTexture.h"
|
||||
#import "OOCollectionExtractors.h"
|
||||
|
||||
|
||||
@interface PlayerEntity (StickMapperInternal)
|
||||
|
||||
- (void) removeFunction:(int)selFunctionIdx;
|
||||
@ -68,13 +68,15 @@ MA 02110-1301, USA.
|
||||
nil]
|
||||
forRow:i + GUI_ROW_STICKNAME];
|
||||
}
|
||||
|
||||
|
||||
[gui setArray: [NSArray arrayWithObjects: @"Edit Axis Profiles", nil] forRow: GUI_ROW_STICKPROFILE];
|
||||
[gui setKey: GUI_KEY_OK forRow: GUI_ROW_STICKPROFILE];
|
||||
[self displayFunctionList:gui skip:skip];
|
||||
|
||||
[gui setArray:[NSArray arrayWithObject:@"Select a function and press Enter to modify or 'u' to unset."]
|
||||
forRow:GUI_ROW_INSTRUCT];
|
||||
|
||||
[gui setSelectedRow: selFunctionIdx + GUI_ROW_FUNCSTART];
|
||||
[gui setSelectedRow: GUI_ROW_STICKPROFILE];
|
||||
[[UNIVERSE gameView] supressKeysUntilKeyUp];
|
||||
[gui setForegroundTextureKey:[self status] == STATUS_DOCKED ? @"docked_overlay" : @"paused_overlay"];
|
||||
[gui setBackgroundTextureKey:@"settings"];
|
||||
@ -85,7 +87,7 @@ MA 02110-1301, USA.
|
||||
view:(MyOpenGLView *)gameView
|
||||
{
|
||||
OOJoystickManager *stickHandler = [OOJoystickManager sharedStickHandler];
|
||||
|
||||
|
||||
// Don't do anything if the user is supposed to be selecting
|
||||
// a function - other than look for Escape.
|
||||
if(waitingForStickCallback)
|
||||
@ -105,6 +107,12 @@ MA 02110-1301, USA.
|
||||
|
||||
[self handleGUIUpDownArrowKeys];
|
||||
|
||||
if ([gui selectedRow] == GUI_ROW_STICKPROFILE && [gameView isDown: 13])
|
||||
{
|
||||
[self setGuiToStickProfileScreen: gui];
|
||||
return;
|
||||
}
|
||||
|
||||
NSString* key = [gui keyForRow: [gui selectedRow]];
|
||||
if ([key hasPrefix:@"Index:"])
|
||||
selFunctionIdx=[[[key componentsSeparatedByString:@":"] objectAtIndex: 1] intValue];
|
||||
@ -360,7 +368,7 @@ MA 02110-1301, USA.
|
||||
i++;
|
||||
}
|
||||
|
||||
[gui setSelectableRange: NSMakeRange(GUI_ROW_FUNCSTART, i + start_row - GUI_ROW_FUNCSTART)];
|
||||
[gui setSelectableRange: NSMakeRange(GUI_ROW_STICKPROFILE, i + start_row - GUI_ROW_STICKPROFILE)];
|
||||
}
|
||||
|
||||
}
|
||||
@ -594,7 +602,7 @@ MA 02110-1301, USA.
|
||||
[guiDict setObject: [NSNumber numberWithInt: butfn]
|
||||
forKey: KEY_BUTTONFN];
|
||||
return guiDict;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
62
src/Core/Entities/PlayerEntityStickProfile.h
Normal file
62
src/Core/Entities/PlayerEntityStickProfile.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
|
||||
PlayerEntityStickProfile.h
|
||||
|
||||
GUI for managing joystick profile settings
|
||||
|
||||
Oolite
|
||||
Copyright (C) 2004-2013 Giles C Williams and contributors
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#import "PlayerEntity.h"
|
||||
#import "GuiDisplayGen.h"
|
||||
#import "MyOpenGLView.h"
|
||||
#import "OOJoystickProfile.h"
|
||||
#import "Universe.h"
|
||||
|
||||
@interface PlayerEntity (StickProfile)
|
||||
|
||||
- (void) setGuiToStickProfileScreen: (GuiDisplayGen *) gui;
|
||||
- (void) stickProfileInputHandler: (GuiDisplayGen *) gui view: (MyOpenGLView *) gameView;
|
||||
- (void) stickProfileGraphAxisProfile: (GLfloat) alpha screenAt: (Vector) screenAt screenSize: (NSSize) screenSize;
|
||||
|
||||
@end
|
||||
|
||||
@interface StickProfileScreen: NSObject
|
||||
{
|
||||
@private
|
||||
OOJoystickManager *stickHandler;
|
||||
int current_axis;
|
||||
OOJoystickAxisProfile *profiles[3][2];
|
||||
GuiDisplayGen *gui;
|
||||
NSRect graphRect;
|
||||
int selected_control_point;
|
||||
int dragged_control_point;
|
||||
int double_click_control_point;
|
||||
}
|
||||
|
||||
- (id) init;
|
||||
- (void) dealloc;
|
||||
- (void) startGui: (GuiDisplayGen *) gui_display_gen;
|
||||
- (void) mouseDown: (NSPoint) position;
|
||||
- (void) mouseUp;
|
||||
- (void) deleteSelected;
|
||||
|
||||
@end
|
||||
|
663
src/Core/Entities/PlayerEntityStickProfile.m
Normal file
663
src/Core/Entities/PlayerEntityStickProfile.m
Normal file
@ -0,0 +1,663 @@
|
||||
/*
|
||||
|
||||
PlayerEntityStickProfile.m
|
||||
|
||||
Oolite
|
||||
Copyright (C) 2004-2013 Giles C Williams and contributors
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#import "PlayerEntity.h"
|
||||
#import "PlayerEntityStickProfile.h"
|
||||
#import "PlayerEntityStickMapper.h"
|
||||
#import "OOJoystickManager.h"
|
||||
#import "OOJoystickProfile.h"
|
||||
#import "PlayerEntityControls.h"
|
||||
#import "PlayerEntitySound.h"
|
||||
#import "OOOpenGL.h"
|
||||
#import "OOMacroOpenGL.h"
|
||||
|
||||
#define GUI_ROW_STICKPROFILE_BACK 18
|
||||
#define GUI_ROW_STICKPROFILE_AXIS 1
|
||||
#define GUI_ROW_STICKPROFILE_DEADZONE 2
|
||||
#define GUI_ROW_STICKPROFILE_PROFILE_TYPE 3
|
||||
#define GUI_ROW_STICKPROFILE_POWER 4
|
||||
#define GUI_ROW_STICKPROFILE_PARAM 5
|
||||
|
||||
static BOOL stickProfileArrow_pressed;
|
||||
|
||||
@interface StickProfileScreen (StickProfileInternal)
|
||||
|
||||
- (void) showScreen;
|
||||
- (void) nextAxis;
|
||||
- (NSString *) currentAxis;
|
||||
- (void) previousAxis;
|
||||
- (void) increaseDeadzone;
|
||||
- (void) decreaseDeadzone;
|
||||
- (void) nextProfileType;
|
||||
- (void) previousProfileType;
|
||||
- (void) IncreasePower;
|
||||
- (BOOL) currentProfileIsSpline;
|
||||
- (void) DecreasePower;
|
||||
- (void) IncreaseParam;
|
||||
- (void) DecreaseParam;
|
||||
- (void) saveSettings;
|
||||
- (void) graphProfile: (GLfloat) alpha at: (Vector) at size: (NSSize) size;
|
||||
- (void) startEdit;
|
||||
- (NSString *) profileType;
|
||||
|
||||
@end
|
||||
|
||||
@implementation PlayerEntity (StickProfile)
|
||||
|
||||
- (void) setGuiToStickProfileScreen: (GuiDisplayGen *) gui
|
||||
{
|
||||
gui_screen = GUI_SCREEN_STICKPROFILE;
|
||||
[stickProfileScreen startGui: gui];
|
||||
return;
|
||||
}
|
||||
|
||||
- (void) stickProfileInputHandler: (GuiDisplayGen *) gui
|
||||
view: (MyOpenGLView *) gameView
|
||||
{
|
||||
if ([gameView isDown: gvMouseLeftButton])
|
||||
{
|
||||
NSPoint mouse_position = NSMakePoint(
|
||||
[gameView virtualJoystickPosition].x * [gui size].width,
|
||||
[gameView virtualJoystickPosition].y * [gui size].height );
|
||||
[stickProfileScreen mouseDown: mouse_position];
|
||||
}
|
||||
else
|
||||
{
|
||||
[stickProfileScreen mouseUp];
|
||||
}
|
||||
if ([gameView isDown: gvDeleteKey])
|
||||
{
|
||||
[stickProfileScreen deleteSelected];
|
||||
}
|
||||
[self handleGUIUpDownArrowKeys];
|
||||
|
||||
if ([gameView isDown:13] && [gui selectedRow] == GUI_ROW_STICKPROFILE_BACK)
|
||||
{
|
||||
[stickProfileScreen saveSettings];
|
||||
[self setGuiToStickMapperScreen: 0];
|
||||
}
|
||||
switch ([gui selectedRow])
|
||||
{
|
||||
case GUI_ROW_STICKPROFILE_AXIS:
|
||||
if ([gameView isDown:key_gui_arrow_left])
|
||||
{
|
||||
if (!stickProfileArrow_pressed && ![gameView isDown: key_gui_arrow_right])
|
||||
{
|
||||
[stickProfileScreen previousAxis];
|
||||
stickProfileArrow_pressed = YES;
|
||||
}
|
||||
}
|
||||
else if ([gameView isDown: key_gui_arrow_right])
|
||||
{
|
||||
if (!stickProfileArrow_pressed && ![gameView isDown: key_gui_arrow_left])
|
||||
{
|
||||
[stickProfileScreen nextAxis];
|
||||
stickProfileArrow_pressed = YES;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stickProfileArrow_pressed = NO;
|
||||
}
|
||||
break;
|
||||
|
||||
case GUI_ROW_STICKPROFILE_DEADZONE:
|
||||
if ([gameView isDown:key_gui_arrow_left])
|
||||
{
|
||||
if (!stickProfileArrow_pressed && ![gameView isDown: key_gui_arrow_right])
|
||||
{
|
||||
[stickProfileScreen decreaseDeadzone];
|
||||
stickProfileArrow_pressed = YES;
|
||||
}
|
||||
}
|
||||
else if ([gameView isDown: key_gui_arrow_right])
|
||||
{
|
||||
if (!stickProfileArrow_pressed && ![gameView isDown: key_gui_arrow_left])
|
||||
{
|
||||
[stickProfileScreen increaseDeadzone];
|
||||
stickProfileArrow_pressed = YES;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stickProfileArrow_pressed = NO;
|
||||
}
|
||||
break;
|
||||
|
||||
case GUI_ROW_STICKPROFILE_PROFILE_TYPE:
|
||||
if ([gameView isDown:key_gui_arrow_left])
|
||||
{
|
||||
if (!stickProfileArrow_pressed && ![gameView isDown: key_gui_arrow_right])
|
||||
{
|
||||
[stickProfileScreen previousProfileType];
|
||||
stickProfileArrow_pressed = YES;
|
||||
}
|
||||
}
|
||||
else if ([gameView isDown: key_gui_arrow_right])
|
||||
{
|
||||
if (!stickProfileArrow_pressed && ![gameView isDown: key_gui_arrow_left])
|
||||
{
|
||||
[stickProfileScreen nextProfileType];
|
||||
stickProfileArrow_pressed = YES;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stickProfileArrow_pressed = NO;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (![stickProfileScreen currentProfileIsSpline])
|
||||
{
|
||||
if ([gui selectedRow] == GUI_ROW_STICKPROFILE_POWER)
|
||||
{
|
||||
if ([gameView isDown:key_gui_arrow_left])
|
||||
{
|
||||
if (!stickProfileArrow_pressed && ![gameView isDown: key_gui_arrow_right])
|
||||
{
|
||||
[stickProfileScreen DecreasePower];
|
||||
stickProfileArrow_pressed = YES;
|
||||
}
|
||||
}
|
||||
else if ([gameView isDown: key_gui_arrow_right])
|
||||
{
|
||||
if (!stickProfileArrow_pressed && ![gameView isDown: key_gui_arrow_left])
|
||||
{
|
||||
[stickProfileScreen IncreasePower];
|
||||
stickProfileArrow_pressed = YES;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stickProfileArrow_pressed = NO;
|
||||
}
|
||||
}
|
||||
else if ([gui selectedRow] == GUI_ROW_STICKPROFILE_PARAM)
|
||||
{
|
||||
if ([gameView isDown:key_gui_arrow_left])
|
||||
{
|
||||
if (!stickProfileArrow_pressed && ![gameView isDown: key_gui_arrow_right])
|
||||
{
|
||||
[stickProfileScreen DecreaseParam];
|
||||
stickProfileArrow_pressed = YES;
|
||||
}
|
||||
}
|
||||
else if ([gameView isDown: key_gui_arrow_right])
|
||||
{
|
||||
if (!stickProfileArrow_pressed && ![gameView isDown: key_gui_arrow_left])
|
||||
{
|
||||
[stickProfileScreen IncreaseParam];
|
||||
stickProfileArrow_pressed = YES;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stickProfileArrow_pressed = NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
- (void) stickProfileGraphAxisProfile: (GLfloat) alpha screenAt: (Vector) screenAt screenSize: (NSSize) screenSize
|
||||
{
|
||||
|
||||
[stickProfileScreen graphProfile: alpha at: make_vector(screenAt.x - screenSize.width/2.0, screenAt.y - 40, screenAt.z) size: NSMakeSize(screenSize.width,150)];
|
||||
return;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation StickProfileScreen
|
||||
|
||||
- (id) init
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if ((self = [super init]))
|
||||
{
|
||||
stickHandler = [OOJoystickManager sharedStickHandler];
|
||||
current_axis = AXIS_ROLL;
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
for (j = 0; j < 2; j++)
|
||||
{
|
||||
profiles[i][j] = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
int i, j;
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
for (j = 0; j < 2; j++)
|
||||
{
|
||||
[profiles[i][j] release];
|
||||
}
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
- (void) startGui: (GuiDisplayGen *) gui_display_gen
|
||||
{
|
||||
gui = gui_display_gen;
|
||||
[self startEdit];
|
||||
[gui clear];
|
||||
[gui setTitle: [NSString stringWithFormat: @"Joystick Profile"]];
|
||||
[self showScreen];
|
||||
[gui setSelectedRow: GUI_ROW_STICKPROFILE_AXIS];
|
||||
return;
|
||||
}
|
||||
|
||||
- (void) mouseDown: (NSPoint) position
|
||||
{
|
||||
OOJoystickAxisProfile *profile = [stickHandler getProfileForAxis: current_axis];
|
||||
OOJoystickSplineAxisProfile *spline_profile;
|
||||
NSPoint spline_position;
|
||||
|
||||
if (![profile isKindOfClass: [OOJoystickSplineAxisProfile class]])
|
||||
{
|
||||
return;
|
||||
}
|
||||
spline_profile = (OOJoystickSplineAxisProfile *)profile;
|
||||
spline_position.x = (position.x - graphRect.origin.x - 10) / (graphRect.size.width - 20);
|
||||
spline_position.y = (-position.y - graphRect.origin.y - 10) / (graphRect.size.height - 20);
|
||||
if (spline_position.x >= 0.0 && spline_position.x <= 1.0 && spline_position.y >= 0.0 && spline_position.y <= 1.0)
|
||||
{
|
||||
if (dragged_control_point < 0)
|
||||
{
|
||||
selected_control_point = [spline_profile addControl: spline_position];
|
||||
dragged_control_point = selected_control_point;
|
||||
double_click_control_point = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
[spline_profile moveControl: dragged_control_point point: spline_position];
|
||||
}
|
||||
[stickHandler saveStickSettings];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
- (void) mouseUp
|
||||
{
|
||||
if (selected_control_point >= 0)
|
||||
{
|
||||
double_click_control_point = selected_control_point;
|
||||
}
|
||||
dragged_control_point = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
- (void) deleteSelected
|
||||
{
|
||||
OOJoystickAxisProfile *profile = [stickHandler getProfileForAxis: current_axis];
|
||||
OOJoystickSplineAxisProfile *spline_profile;
|
||||
if ([profile isKindOfClass: [OOJoystickSplineAxisProfile class]] && selected_control_point >= 0)
|
||||
{
|
||||
spline_profile = (OOJoystickSplineAxisProfile *)profile;
|
||||
[spline_profile removeControl: selected_control_point];
|
||||
selected_control_point = -1;
|
||||
dragged_control_point = -1;
|
||||
[stickHandler saveStickSettings];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@implementation StickProfileScreen (StickProfileInternal)
|
||||
|
||||
|
||||
- (void) nextAxis
|
||||
{
|
||||
if (current_axis == AXIS_ROLL)
|
||||
current_axis = AXIS_PITCH;
|
||||
else if (current_axis == AXIS_PITCH)
|
||||
current_axis = AXIS_YAW;
|
||||
[self showScreen];
|
||||
return;
|
||||
}
|
||||
|
||||
- (void) previousAxis
|
||||
{
|
||||
if (current_axis == AXIS_PITCH)
|
||||
current_axis = AXIS_ROLL;
|
||||
else if (current_axis == AXIS_YAW)
|
||||
current_axis = AXIS_PITCH;
|
||||
[self showScreen];
|
||||
return;
|
||||
}
|
||||
|
||||
- (NSString *) currentAxis
|
||||
{
|
||||
switch (current_axis)
|
||||
{
|
||||
case AXIS_ROLL:
|
||||
return @"Roll";
|
||||
|
||||
case AXIS_PITCH:
|
||||
return @"Pitch";
|
||||
|
||||
case AXIS_YAW:
|
||||
return @"Yaw";
|
||||
}
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (void) increaseDeadzone
|
||||
{
|
||||
OOJoystickAxisProfile *profile = [stickHandler getProfileForAxis: current_axis];
|
||||
if (profile)
|
||||
{
|
||||
[profile setDeadzone: [profile deadzone] + STICK_MAX_DEADZONE / 20];
|
||||
}
|
||||
[self showScreen];
|
||||
return;
|
||||
}
|
||||
|
||||
- (void) decreaseDeadzone
|
||||
{
|
||||
OOJoystickAxisProfile *profile = [stickHandler getProfileForAxis: current_axis];
|
||||
if (profile)
|
||||
{
|
||||
[profile setDeadzone: [profile deadzone] - STICK_MAX_DEADZONE / 20];
|
||||
}
|
||||
[self showScreen];
|
||||
return;
|
||||
}
|
||||
|
||||
- (void) nextProfileType
|
||||
{
|
||||
OOJoystickAxisProfile *profile = [stickHandler getProfileForAxis: current_axis];
|
||||
|
||||
if ([profile isKindOfClass: [OOJoystickStandardAxisProfile class]])
|
||||
{
|
||||
[profiles[current_axis][0] release];
|
||||
profiles[current_axis][0] = [profile retain];
|
||||
if (!profiles[current_axis][1])
|
||||
{
|
||||
profiles[current_axis][1] = [[OOJoystickSplineAxisProfile alloc] init];
|
||||
}
|
||||
[stickHandler setProfile: profiles[current_axis][1] forAxis: current_axis];
|
||||
[stickHandler saveStickSettings];
|
||||
}
|
||||
[self showScreen];
|
||||
return;
|
||||
}
|
||||
|
||||
- (void) previousProfileType
|
||||
{
|
||||
OOJoystickAxisProfile *profile = [stickHandler getProfileForAxis: current_axis];
|
||||
|
||||
if ([profile isKindOfClass: [OOJoystickSplineAxisProfile class]])
|
||||
{
|
||||
[profiles[current_axis][1] release];
|
||||
profiles[current_axis][1] = [profile retain];
|
||||
if (!profiles[current_axis][0])
|
||||
{
|
||||
profiles[current_axis][0] = [[OOJoystickStandardAxisProfile alloc] init];
|
||||
}
|
||||
[stickHandler setProfile: profiles[current_axis][0] forAxis: current_axis];
|
||||
[stickHandler saveStickSettings];
|
||||
}
|
||||
[self showScreen];
|
||||
return;
|
||||
}
|
||||
|
||||
- (BOOL) currentProfileIsSpline
|
||||
{
|
||||
if ([[stickHandler getProfileForAxis: current_axis] isKindOfClass: [OOJoystickSplineAxisProfile class]])
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void) IncreasePower
|
||||
{
|
||||
OOJoystickAxisProfile *profile = [stickHandler getProfileForAxis: current_axis];
|
||||
OOJoystickStandardAxisProfile *standard_profile;
|
||||
|
||||
if (profile && [profile isKindOfClass: [OOJoystickStandardAxisProfile class]])
|
||||
{
|
||||
standard_profile = (OOJoystickStandardAxisProfile *) profile;
|
||||
[standard_profile setPower: [standard_profile power] + STICKPROFILE_MAX_POWER / 20];
|
||||
[stickHandler saveStickSettings];
|
||||
}
|
||||
[self showScreen];
|
||||
return;
|
||||
}
|
||||
|
||||
- (void) DecreasePower
|
||||
{
|
||||
OOJoystickAxisProfile *profile = [stickHandler getProfileForAxis: current_axis];
|
||||
OOJoystickStandardAxisProfile *standard_profile;
|
||||
|
||||
if (profile && [profile isKindOfClass: [OOJoystickStandardAxisProfile class]])
|
||||
{
|
||||
standard_profile = (OOJoystickStandardAxisProfile *) profile;
|
||||
[standard_profile setPower: [standard_profile power] - STICKPROFILE_MAX_POWER / 20];
|
||||
[stickHandler saveStickSettings];
|
||||
}
|
||||
[self showScreen];
|
||||
return;
|
||||
}
|
||||
|
||||
- (void) IncreaseParam
|
||||
{
|
||||
OOJoystickAxisProfile *profile = [stickHandler getProfileForAxis: current_axis];
|
||||
OOJoystickStandardAxisProfile *standard_profile;
|
||||
|
||||
if (profile && [profile isKindOfClass: [OOJoystickStandardAxisProfile class]])
|
||||
{
|
||||
standard_profile = (OOJoystickStandardAxisProfile *) profile;
|
||||
[standard_profile setParameter: [standard_profile parameter] + 0.05];
|
||||
[stickHandler saveStickSettings];
|
||||
}
|
||||
[self showScreen];
|
||||
return;
|
||||
}
|
||||
|
||||
- (void) DecreaseParam
|
||||
{
|
||||
OOJoystickAxisProfile *profile = [stickHandler getProfileForAxis: current_axis];
|
||||
OOJoystickStandardAxisProfile *standard_profile;
|
||||
|
||||
if (profile && [profile isKindOfClass: [OOJoystickStandardAxisProfile class]])
|
||||
{
|
||||
standard_profile = (OOJoystickStandardAxisProfile *) profile;
|
||||
[standard_profile setParameter: [standard_profile parameter] - 0.05];
|
||||
[stickHandler saveStickSettings];
|
||||
}
|
||||
[self showScreen];
|
||||
return;
|
||||
}
|
||||
|
||||
- (void) graphProfile: (GLfloat) alpha at: (Vector) at size: (NSSize) size
|
||||
{
|
||||
OOJoystickAxisProfile *profile = [stickHandler getProfileForAxis: current_axis];
|
||||
OOJoystickSplineAxisProfile *spline_profile;
|
||||
int i;
|
||||
NSPoint point;
|
||||
NSArray *control_points;
|
||||
|
||||
if (!profile) return;
|
||||
graphRect = NSMakeRect(at.x, at.y, size.width, size.height);
|
||||
OO_ENTER_OPENGL();
|
||||
OOGL(glColor4f(0.2,0.2,0.5,alpha));
|
||||
OOGLBEGIN(GL_QUADS);
|
||||
glVertex3f(at.x,at.y,at.z);
|
||||
glVertex3f(at.x + size.width,at.y,at.z);
|
||||
glVertex3f(at.x + size.width,at.y + size.height,at.z);
|
||||
glVertex3f(at.x,at.y + size.height,at.z);
|
||||
OOGLEND();
|
||||
OOGL(glColor4f(0.9,0.9,0.9,alpha));
|
||||
OOGL(GLScaledLineWidth(2.0f));
|
||||
OOGLBEGIN(GL_LINE_STRIP);
|
||||
for (i = 0; i <= size.width - 20; i++)
|
||||
{
|
||||
glVertex3f(at.x+i+10,at.y+10+(size.height-20)*[profile rawValue:((float)i)/(size.width-20)],at.z);
|
||||
}
|
||||
OOGLEND();
|
||||
OOGL(glColor4f(0.5,0.0,0.5,alpha));
|
||||
GLDrawFilledOval(at.x+10,at.y+10,at.z,NSMakeSize(4,4),20);
|
||||
GLDrawFilledOval(at.x+size.width-10,at.y+size.height-10,at.z,NSMakeSize(4,4),20);
|
||||
if ([profile isKindOfClass: [OOJoystickSplineAxisProfile class]])
|
||||
{
|
||||
spline_profile = (OOJoystickSplineAxisProfile *)profile;
|
||||
control_points = [spline_profile controlPoints];
|
||||
for (i = 0; i < [control_points count]; i++)
|
||||
{
|
||||
if (i == selected_control_point)
|
||||
{
|
||||
OOGL(glColor4f(1.0,0.0,0.0,alpha));
|
||||
}
|
||||
else
|
||||
{
|
||||
OOGL(glColor4f(0.0,1.0,0.0,alpha));
|
||||
}
|
||||
point = [[control_points objectAtIndex: i] pointValue];
|
||||
GLDrawFilledOval(at.x+10+point.x*(size.width - 20),at.y+10+point.y*(size.height-20),at.z,NSMakeSize(4,4),20);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
- (void) startEdit
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
for (j = 0; j < 2; j++)
|
||||
{
|
||||
[profiles[i][j] release];
|
||||
profiles[i][j] = nil;
|
||||
}
|
||||
}
|
||||
current_axis = AXIS_ROLL;
|
||||
selected_control_point = -1;
|
||||
dragged_control_point = -1;
|
||||
double_click_control_point = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
- (void) saveSettings
|
||||
{
|
||||
[stickHandler saveStickSettings];
|
||||
return;
|
||||
}
|
||||
|
||||
- (void) showScreen
|
||||
{
|
||||
OOJoystickAxisProfile *profile = [stickHandler getProfileForAxis: current_axis];
|
||||
OOJoystickStandardAxisProfile *standard_profile;
|
||||
NSString *v1 = @"||||||||||||||||||||";
|
||||
NSString *v2 = @"....................";
|
||||
int bars;
|
||||
double value;
|
||||
double power;
|
||||
|
||||
OOGUITabStop tabStop[GUI_MAX_COLUMNS];
|
||||
tabStop[0] = 50;
|
||||
tabStop[1] = 140;
|
||||
[gui setTabStops:tabStop];
|
||||
[gui setText: @"Back" forRow: GUI_ROW_STICKPROFILE_BACK];
|
||||
[gui setKey: GUI_KEY_OK forRow: GUI_ROW_STICKPROFILE_BACK];
|
||||
[gui setArray: [NSArray arrayWithObjects: @"Axis:", [self currentAxis], nil ] forRow: GUI_ROW_STICKPROFILE_AXIS];
|
||||
[gui setKey: GUI_KEY_OK forRow: GUI_ROW_STICKPROFILE_AXIS];
|
||||
value = [profile deadzone];
|
||||
bars = 20 * value / STICK_MAX_DEADZONE;
|
||||
[gui setArray: [NSArray arrayWithObjects: @"Deadzone:",
|
||||
[NSString stringWithFormat:
|
||||
@"%@%@ (%0.4f)",
|
||||
[v1 substringToIndex: bars],
|
||||
[v2 substringToIndex: 20 - bars],
|
||||
value,
|
||||
nil],
|
||||
nil] forRow: GUI_ROW_STICKPROFILE_DEADZONE];
|
||||
[gui setKey: GUI_KEY_OK forRow: GUI_ROW_STICKPROFILE_DEADZONE];
|
||||
[gui setArray: [NSArray arrayWithObjects: @"Profile Type:", [self profileType], nil ] forRow: GUI_ROW_STICKPROFILE_PROFILE_TYPE];
|
||||
[gui setKey: GUI_KEY_OK forRow: GUI_ROW_STICKPROFILE_PROFILE_TYPE];
|
||||
if ([profile isKindOfClass:[OOJoystickStandardAxisProfile class]])
|
||||
{
|
||||
standard_profile = (OOJoystickStandardAxisProfile*) profile;
|
||||
power = [standard_profile power];
|
||||
bars = 20*power / STICKPROFILE_MAX_POWER;
|
||||
if (bars < 0) bars = 0;
|
||||
if (bars > 20) bars = 20;
|
||||
[gui setArray: [NSArray arrayWithObjects: @"Power:",
|
||||
[NSString stringWithFormat: @"%@%@ (%.1f) ", [v1 substringToIndex: bars], [v2 substringToIndex: 20 - bars], power],
|
||||
nil] forRow: GUI_ROW_STICKPROFILE_POWER];
|
||||
[gui setKey: GUI_KEY_OK forRow: GUI_ROW_STICKPROFILE_POWER];
|
||||
value = [standard_profile parameter];
|
||||
bars = 20*value;
|
||||
if (bars < 0) bars = 0;
|
||||
if (bars > 20) bars = 20;
|
||||
[gui setArray: [NSArray arrayWithObjects: @"Parameter:",
|
||||
[NSString stringWithFormat: @"%@%@ (%0.2f) ", [v1 substringToIndex: bars], [v2 substringToIndex: 20 - bars], value],
|
||||
nil] forRow: GUI_ROW_STICKPROFILE_PARAM];
|
||||
[gui setKey: GUI_KEY_OK forRow: GUI_ROW_STICKPROFILE_PARAM];
|
||||
[gui setColor:[OOColor yellowColor] forRow: GUI_ROW_STICKPROFILE_PARAM];
|
||||
}
|
||||
else
|
||||
{
|
||||
[gui setText: @"" forRow: GUI_ROW_STICKPROFILE_POWER];
|
||||
[gui setKey: GUI_KEY_SKIP forRow: GUI_ROW_STICKPROFILE_POWER];
|
||||
[gui setText: @"Click and Drag to set control points. Select and <Del> to delete points." forRow: GUI_ROW_STICKPROFILE_PARAM];
|
||||
[gui setKey: GUI_KEY_SKIP forRow: GUI_ROW_STICKPROFILE_PARAM];
|
||||
[gui setColor:[OOColor magentaColor] forRow: GUI_ROW_STICKPROFILE_PARAM];
|
||||
}
|
||||
[gui setText: @"Back" forRow: GUI_ROW_STICKPROFILE_BACK];
|
||||
[gui setKey: GUI_KEY_OK forRow: GUI_ROW_STICKPROFILE_BACK];
|
||||
[gui setSelectableRange: NSMakeRange(1, GUI_ROW_STICKPROFILE_BACK)];
|
||||
[[UNIVERSE gameView] supressKeysUntilKeyUp];
|
||||
[gui setForegroundTextureKey:[PLAYER status] == STATUS_DOCKED ? @"docked_overlay" : @"paused_overlay"];
|
||||
[gui setBackgroundTextureKey: @"settings"];
|
||||
return;
|
||||
}
|
||||
|
||||
- (NSString *) profileType
|
||||
{
|
||||
OOJoystickAxisProfile *profile = [stickHandler getProfileForAxis: current_axis];
|
||||
|
||||
if ([profile isKindOfClass: [OOJoystickStandardAxisProfile class]])
|
||||
{
|
||||
return @"Standard";
|
||||
}
|
||||
if ([profile isKindOfClass: [OOJoystickSplineAxisProfile class]])
|
||||
{
|
||||
return @"Spline";
|
||||
}
|
||||
return @"Standard";
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -36,7 +36,7 @@ MA 02110-1301, USA.
|
||||
#import "OOCollectionExtractors.h"
|
||||
#import "OOTexture.h"
|
||||
#import "OOJavaScriptEngine.h"
|
||||
|
||||
#import "PlayerEntityStickProfile.h"
|
||||
|
||||
OOINLINE BOOL RowInRange(OOGUIRow row, NSRange range)
|
||||
{
|
||||
@ -1252,6 +1252,10 @@ static OOTextureSprite *NewTextureSpriteWithDescriptor(NSDictionary *descriptor)
|
||||
{
|
||||
[self drawEquipmentList:[player equipmentList] z:z];
|
||||
}
|
||||
if ([player guiScreen] == GUI_SCREEN_STICKPROFILE)
|
||||
{
|
||||
[player stickProfileGraphAxisProfile: alpha screenAt: make_vector(x,y,z) screenSize: size_in_pixels];
|
||||
}
|
||||
}
|
||||
|
||||
if (fade_sign)
|
||||
|
@ -112,6 +112,9 @@ enum {
|
||||
#define STICK_DEADZONE 0.05
|
||||
#endif
|
||||
|
||||
#define STICK_MAX_DEADZONE (STICK_DEADZONE * 2)
|
||||
|
||||
|
||||
// Kind of stick device (these are bits - if any more are added,
|
||||
// the next one is 4 and so on).
|
||||
#define HW_AXIS 1
|
||||
@ -128,9 +131,9 @@ enum {
|
||||
#define STICK_NUMBER @"stickNum" // Stick number 0 to 4
|
||||
#define STICK_AXBUT @"stickAxBt" // Axis or button number
|
||||
#define STICK_FUNCTION @"stickFunc" // Function of axis/button
|
||||
#define STICK_DEADZONE_SETTING @"JoystickAxesDeadzone" // Deadzone setting double 0.0 to 1.0.
|
||||
#define STICK_PRECISION_SETTING @"JoystickPrecision" // Precision mode
|
||||
#define STICK_NONLINEAR_PARAMETER @"JoystickNonlinear" // Nonlinear parameter double from 0.0 to 1.0
|
||||
#define STICK_ROLL_AXIS_PROFILE_SETTING @"RollAxisProfile" // Joystick Profiles
|
||||
#define STICK_PITCH_AXIS_PROFILE_SETTING @"PitchAxisProfile" // Joystick Profiles
|
||||
#define STICK_YAW_AXIS_PROFILE_SETTING @"YawAxisProfile" // Joystick Profiles
|
||||
// shortcut to make code more readable when using enum as key for
|
||||
// an NSDictionary
|
||||
#define ENUMKEY(x) [NSString stringWithFormat: @"%d", x]
|
||||
@ -219,6 +222,8 @@ typedef struct
|
||||
#endif //OOLITE_SDL
|
||||
|
||||
|
||||
#import "OOJoystickProfile.h"
|
||||
|
||||
@interface OOJoystickManager: NSObject
|
||||
{
|
||||
@private
|
||||
@ -229,6 +234,9 @@ typedef struct
|
||||
BOOL butstate[BUTTON_end];
|
||||
uint8_t hatstate[MAX_STICKS][MAX_HATS];
|
||||
BOOL precisionMode;
|
||||
OOJoystickAxisProfile *roll_profile;
|
||||
OOJoystickAxisProfile *pitch_profile;
|
||||
OOJoystickAxisProfile *yaw_profile;
|
||||
|
||||
// Handle callbacks - the object, selector to call
|
||||
// the desired function, and the hardware (axis or button etc.)
|
||||
@ -236,12 +244,7 @@ typedef struct
|
||||
SEL cbSelector;
|
||||
char cbHardware;
|
||||
BOOL invertPitch;
|
||||
double deadzone;
|
||||
|
||||
// parameter for nonlinear settings. This is a double between 0.0 and 1.0. 1.0 - nonlinear_parameter is the
|
||||
// gradient of the transform function at zero. 0.0 means the gradient is 1.0, which makes the stick linear.
|
||||
// Higher values reduce the stick response for more accuracy at the centre.
|
||||
double nonlinear_parameter;
|
||||
}
|
||||
|
||||
+ (id) sharedStickHandler;
|
||||
@ -273,8 +276,11 @@ typedef struct
|
||||
- (double) getAxisState:(int)function;
|
||||
- (double) getSensitivity;
|
||||
|
||||
// Transform raw axis state into actual axis state
|
||||
- (double) axisTransform: (double)axisvalue;
|
||||
// Axis profile handling
|
||||
- (void) setProfile: (OOJoystickAxisProfile *) profile forAxis:(int) axis;
|
||||
- (OOJoystickAxisProfile *) getProfileForAxis: (int) axis;
|
||||
- (void) saveProfileForAxis: (int) axis;
|
||||
- (void) loadProfileForAxis: (int) axis;
|
||||
|
||||
// This one just returns a pointer to the entire state array to
|
||||
// allow for multiple lookups with only one objc_sendMsg
|
||||
|
@ -86,8 +86,8 @@ static id sSharedStickHandler = nil;
|
||||
// Make some sensible mappings. This also ensures unassigned
|
||||
// axes and buttons are set to unassigned (STICK_NOFUNCTION).
|
||||
[self loadStickSettings];
|
||||
|
||||
invertPitch = NO;
|
||||
precisionMode = NO;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@ -127,9 +127,32 @@ static id sSharedStickHandler = nil;
|
||||
switch (function)
|
||||
{
|
||||
case AXIS_ROLL:
|
||||
if (precisionMode)
|
||||
{
|
||||
return [roll_profile value:axstate[function]] / STICK_PRECISIONFAC;
|
||||
}
|
||||
else
|
||||
{
|
||||
return [roll_profile value:axstate[function]];
|
||||
}
|
||||
case AXIS_PITCH:
|
||||
if (precisionMode)
|
||||
{
|
||||
return [pitch_profile value:axstate[function]] / STICK_PRECISIONFAC;
|
||||
}
|
||||
else
|
||||
{
|
||||
return [pitch_profile value:axstate[function]];
|
||||
}
|
||||
case AXIS_YAW:
|
||||
return [self axisTransform:axstate[function]];
|
||||
if (precisionMode)
|
||||
{
|
||||
return [yaw_profile value:axstate[function]] / STICK_PRECISIONFAC;
|
||||
}
|
||||
else
|
||||
{
|
||||
return [yaw_profile value:axstate[function]];
|
||||
}
|
||||
default:
|
||||
return axstate[function];
|
||||
}
|
||||
@ -141,52 +164,160 @@ static id sSharedStickHandler = nil;
|
||||
return precisionMode ? STICK_PRECISIONFAC : 1.0;
|
||||
}
|
||||
|
||||
- (double) deadZone
|
||||
- (void) setProfile: (OOJoystickAxisProfile *) profile forAxis: (int) axis
|
||||
{
|
||||
return deadzone;
|
||||
switch (axis)
|
||||
{
|
||||
case AXIS_ROLL:
|
||||
[roll_profile release];
|
||||
roll_profile = [profile retain];
|
||||
break;
|
||||
|
||||
case AXIS_PITCH:
|
||||
[pitch_profile release];
|
||||
pitch_profile = [profile retain];
|
||||
break;
|
||||
|
||||
case AXIS_YAW:
|
||||
[yaw_profile release];
|
||||
yaw_profile = [profile retain];
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
- (OOJoystickAxisProfile *) getProfileForAxis: (int) axis
|
||||
{
|
||||
switch (axis)
|
||||
{
|
||||
case AXIS_ROLL:
|
||||
return roll_profile;
|
||||
case AXIS_PITCH:
|
||||
return pitch_profile;
|
||||
case AXIS_YAW:
|
||||
return yaw_profile;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (void) setDeadZone: (double)newValue
|
||||
- (void) saveProfileForAxis: (int) axis
|
||||
{
|
||||
deadzone = newValue;
|
||||
}
|
||||
|
||||
|
||||
// axisTransform is an increasing function that maps the interval [-1,1] onto [-1,1] such that -1 -> -1, 0 -> 0 and 1 -> 1
|
||||
// By using a function with a shallow gradient at the origin, we can make the stick less sensitive at the centre (and hence
|
||||
// easier to make fine adjustments). The functions I've used below are ax^n+bx where a+b=1 and n in an odd power.
|
||||
|
||||
- (double) axisTransform: (double)axisvalue
|
||||
{
|
||||
if (fabs(axisvalue) < deadzone) return 0.0;
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
|
||||
OOJoystickAxisProfile *profile;
|
||||
OOJoystickStandardAxisProfile *standard_profile;
|
||||
OOJoystickSplineAxisProfile *spline_profile;
|
||||
NSArray *controlPoints;
|
||||
NSMutableArray *points;
|
||||
NSPoint point;
|
||||
int i;
|
||||
|
||||
// since we're mucking around with nonlinear stuff, we may as well throw in a smooth transition
|
||||
// from deadzone to non-deadzone
|
||||
if (axisvalue < 0.0) axisvalue = -(-axisvalue - deadzone)/(1 - deadzone);
|
||||
else axisvalue = (axisvalue - deadzone)/(1 - deadzone);
|
||||
|
||||
// apply non-linearity
|
||||
axisvalue = axisvalue*((1.0-nonlinear_parameter) + nonlinear_parameter*axisvalue*axisvalue);
|
||||
// apply precision mode if needed
|
||||
if (precisionMode)
|
||||
profile = [self getProfileForAxis: axis];
|
||||
if (!profile) return;
|
||||
[dict setObject: [NSNumber numberWithDouble: [profile deadzone]] forKey: @"Deadzone"];
|
||||
if ([profile isKindOfClass: [OOJoystickStandardAxisProfile class]])
|
||||
{
|
||||
axisvalue /= STICK_PRECISIONFAC;
|
||||
standard_profile = (OOJoystickStandardAxisProfile *) profile;
|
||||
[dict setObject: @"Standard" forKey: @"Type"];
|
||||
[dict setObject: [NSNumber numberWithDouble: [standard_profile power]] forKey: @"Power"];
|
||||
[dict setObject: [NSNumber numberWithDouble: [standard_profile parameter]] forKey: @"Parameter"];
|
||||
}
|
||||
return axisvalue;
|
||||
|
||||
/*
|
||||
// these original settings caused problems for test pilots due to
|
||||
// expectation that precisionmode would also reduce full-axis turn
|
||||
// rate.
|
||||
if (precisionMode)
|
||||
else if ([profile isKindOfClass: [OOJoystickSplineAxisProfile class]])
|
||||
{
|
||||
return axisvalue*((1.0-nonlinear_parameter) + nonlinear_parameter*axisvalue*axisvalue);
|
||||
spline_profile = (OOJoystickSplineAxisProfile *) profile;
|
||||
[dict setObject: @"Spline" forKey: @"Type"];
|
||||
controlPoints = [NSArray arrayWithArray: [spline_profile controlPoints]];
|
||||
points = [[NSMutableArray alloc] initWithCapacity: [controlPoints count]];
|
||||
for (i = 0; i < [controlPoints count]; i++)
|
||||
{
|
||||
point = [[controlPoints objectAtIndex: i] pointValue];
|
||||
[points addObject: [NSArray arrayWithObjects:
|
||||
[NSNumber numberWithFloat: point.x],
|
||||
[NSNumber numberWithFloat: point.y],
|
||||
nil ]];
|
||||
}
|
||||
[dict setObject: points forKey: @"ControlPoints"];
|
||||
}
|
||||
return axisvalue; */
|
||||
else
|
||||
{
|
||||
[dict setObject: @"Standard" forKey: @"Type"];
|
||||
}
|
||||
if (axis == AXIS_ROLL)
|
||||
{
|
||||
[defaults setObject: dict forKey: STICK_ROLL_AXIS_PROFILE_SETTING];
|
||||
}
|
||||
else if (axis == AXIS_PITCH)
|
||||
{
|
||||
[defaults setObject: dict forKey: STICK_PITCH_AXIS_PROFILE_SETTING];
|
||||
}
|
||||
else if (axis == AXIS_YAW)
|
||||
{
|
||||
[defaults setObject: dict forKey: STICK_YAW_AXIS_PROFILE_SETTING];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (void) loadProfileForAxis: (int) axis
|
||||
{
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
NSDictionary *dict;
|
||||
OOJoystickStandardAxisProfile *standard_profile;
|
||||
OOJoystickSplineAxisProfile *spline_profile;
|
||||
|
||||
if (axis == AXIS_ROLL)
|
||||
{
|
||||
dict = [defaults objectForKey: STICK_ROLL_AXIS_PROFILE_SETTING];
|
||||
}
|
||||
else if (axis == AXIS_PITCH)
|
||||
{
|
||||
dict = [defaults objectForKey: STICK_PITCH_AXIS_PROFILE_SETTING];
|
||||
}
|
||||
else if (axis == AXIS_YAW)
|
||||
{
|
||||
dict = [defaults objectForKey: STICK_YAW_AXIS_PROFILE_SETTING];
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *type = [dict objectForKey: @"Type"];
|
||||
if ([type isEqualToString: @"Standard"])
|
||||
{
|
||||
standard_profile = [[OOJoystickStandardAxisProfile alloc] init];
|
||||
[standard_profile setDeadzone: [[dict objectForKey: @"Deadzone"] doubleValue]];
|
||||
[standard_profile setPower: [[dict objectForKey: @"Power"] doubleValue]];
|
||||
[standard_profile setParameter: [[dict objectForKey: @"Parameter"] doubleValue]];
|
||||
[self setProfile: [standard_profile autorelease] forAxis: axis];
|
||||
}
|
||||
else if([type isEqualToString: @"Spline"])
|
||||
{
|
||||
spline_profile = [[OOJoystickSplineAxisProfile alloc] init];
|
||||
[spline_profile setDeadzone: [[dict objectForKey: @"Deadzone"] doubleValue]];
|
||||
NSArray *points = [dict objectForKey: @"ControlPoints"], *pointArray;
|
||||
NSPoint point;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < [points count]; i++)
|
||||
{
|
||||
pointArray = [points objectAtIndex: i];
|
||||
if ([pointArray count] >= 2)
|
||||
{
|
||||
point = NSMakePoint([[pointArray objectAtIndex: 0] floatValue], [[pointArray objectAtIndex: 1] floatValue]);
|
||||
[spline_profile addControl: point];
|
||||
}
|
||||
}
|
||||
[self setProfile: [spline_profile autorelease] forAxis: axis];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self setProfile: [[[OOJoystickStandardAxisProfile alloc] init] autorelease] forAxis: axis];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)listSticks
|
||||
{
|
||||
NSUInteger i, stickCount = [self joystickCount];
|
||||
@ -423,7 +554,7 @@ static id sSharedStickHandler = nil;
|
||||
if(cbObject && (cbHardware & HW_AXIS))
|
||||
{
|
||||
// ...then check if axis moved more than AXCBTHRESH - (fix for BUG #17482)
|
||||
if(axisvalue > AXCBTHRESH)
|
||||
if(axisvalue > AXCBTHRESH)
|
||||
{
|
||||
NSDictionary *fnDict = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSNumber numberWithBool: YES], STICK_ISAXIS,
|
||||
@ -516,7 +647,6 @@ static id sSharedStickHandler = nil;
|
||||
bs = YES;
|
||||
if(function == BUTTON_PRECISION)
|
||||
precisionMode = !precisionMode;
|
||||
[[NSUserDefaults standardUserDefaults] setBool: precisionMode forKey: STICK_PRECISION_SETTING];
|
||||
}
|
||||
|
||||
if (function >= 0)
|
||||
@ -527,24 +657,24 @@ static id sSharedStickHandler = nil;
|
||||
}
|
||||
|
||||
|
||||
- (void) decodeHatEvent:(JoyHatEvent *)evt
|
||||
{
|
||||
// HACK: handle this as a set of buttons
|
||||
int i;
|
||||
JoyButtonEvent btn;
|
||||
- (void) decodeHatEvent:(JoyHatEvent *)evt
|
||||
{
|
||||
// HACK: handle this as a set of buttons
|
||||
int i;
|
||||
JoyButtonEvent btn;
|
||||
|
||||
btn.which = evt->which;
|
||||
|
||||
btn.which = evt->which;
|
||||
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
if ((evt->value ^ hatstate[evt->which][evt->hat]) & (1 << i))
|
||||
{
|
||||
btn.type = (evt->value & (1 << i)) ? JOYBUTTONDOWN : JOYBUTTONUP;
|
||||
btn.button = MAX_REAL_BUTTONS + i + evt->which * 4;
|
||||
btn.state = (evt->value & (1 << i)) ? JOYBUTTON_PRESSED : JOYBUTTON_RELEASED;
|
||||
[self decodeButtonEvent:&btn];
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
if ((evt->value ^ hatstate[evt->which][evt->hat]) & (1 << i))
|
||||
{
|
||||
btn.type = (evt->value & (1 << i)) ? JOYBUTTONDOWN : JOYBUTTONUP;
|
||||
btn.button = MAX_REAL_BUTTONS + i + evt->which * 4;
|
||||
btn.state = (evt->value & (1 << i)) ? JOYBUTTON_PRESSED : JOYBUTTON_RELEASED;
|
||||
[self decodeButtonEvent:&btn];
|
||||
}
|
||||
}
|
||||
|
||||
hatstate[evt->which][evt->hat] = evt->value;
|
||||
}
|
||||
@ -559,13 +689,14 @@ static id sSharedStickHandler = nil;
|
||||
- (void) saveStickSettings
|
||||
{
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
|
||||
[defaults setObject:[self axisFunctions]
|
||||
forKey:AXIS_SETTINGS];
|
||||
[defaults setObject:[self buttonFunctions]
|
||||
forKey:BUTTON_SETTINGS];
|
||||
[defaults setFloat: deadzone forKey: STICK_DEADZONE_SETTING];
|
||||
[defaults setFloat: nonlinear_parameter forKey: STICK_NONLINEAR_PARAMETER];
|
||||
[defaults setBool: !!precisionMode forKey: STICK_PRECISION_SETTING];
|
||||
[self saveProfileForAxis: AXIS_ROLL];
|
||||
[self saveProfileForAxis: AXIS_PITCH];
|
||||
[self saveProfileForAxis: AXIS_YAW];
|
||||
[defaults synchronize];
|
||||
}
|
||||
|
||||
@ -573,7 +704,7 @@ static id sSharedStickHandler = nil;
|
||||
- (void) loadStickSettings
|
||||
{
|
||||
unsigned i;
|
||||
[self clearMappings];
|
||||
[self clearMappings];
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
NSDictionary *axisSettings = [defaults objectForKey: AXIS_SETTINGS];
|
||||
NSDictionary *buttonSettings = [defaults objectForKey: BUTTON_SETTINGS];
|
||||
@ -602,13 +733,9 @@ static id sSharedStickHandler = nil;
|
||||
// Nothing to load - set useful defaults
|
||||
[self setDefaultMapping];
|
||||
}
|
||||
deadzone = [defaults oo_doubleForKey:STICK_DEADZONE_SETTING defaultValue:STICK_DEADZONE];
|
||||
if (deadzone < 0 || deadzone > 1)
|
||||
{
|
||||
deadzone = STICK_DEADZONE;
|
||||
}
|
||||
nonlinear_parameter = OOClamp_0_1_d( [defaults oo_doubleForKey: STICK_NONLINEAR_PARAMETER defaultValue: 1.0] );
|
||||
precisionMode = [defaults oo_boolForKey: STICK_PRECISION_SETTING defaultValue:NO];
|
||||
[self loadProfileForAxis: AXIS_ROLL];
|
||||
[self loadProfileForAxis: AXIS_PITCH];
|
||||
[self loadProfileForAxis: AXIS_YAW];
|
||||
}
|
||||
|
||||
// These get overidden by subclasses
|
||||
|
92
src/Core/OOJoystickProfile.h
Normal file
92
src/Core/OOJoystickProfile.h
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
|
||||
OOJoystickProfile.h
|
||||
|
||||
JoystickProfile maintains settings such as deadzone and the mapping
|
||||
from joystick movement to response.
|
||||
|
||||
JoystickSpline manages the mapping of the physical joystick movements
|
||||
to the joystick response. It holds a series of control points, with
|
||||
the points (0,0) and (1,1) being assumed. It then interpolates
|
||||
splines between the set of control points - the segment between (0,0)
|
||||
and the first control point is linear, the remaining segments
|
||||
quadratic with the gradients matching at the control point.
|
||||
|
||||
Oolite
|
||||
Copyright (C) 2004-2013 Giles C Williams and contributors
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#define STICKPROFILE_TYPE_STANDARD 1
|
||||
#define STICKPROFILE_TYPE_SPLINE 2
|
||||
#define STICKPROFILE_MAX_POWER 10.0
|
||||
|
||||
@interface OOJoystickAxisProfile : NSObject <NSCopying>
|
||||
{
|
||||
@private
|
||||
double deadzone;
|
||||
}
|
||||
|
||||
- (id) init;
|
||||
- (id) copyWithZone: (NSZone *) zone;
|
||||
- (double) rawValue: (double) x;
|
||||
- (double) value: (double) x;
|
||||
- (double) deadzone;
|
||||
- (void) setDeadzone: (double) newValue;
|
||||
|
||||
@end
|
||||
|
||||
@interface OOJoystickStandardAxisProfile: OOJoystickAxisProfile
|
||||
{
|
||||
@private
|
||||
double power;
|
||||
double parameter;
|
||||
}
|
||||
|
||||
- (id) init;
|
||||
- (id) copyWithZone: (NSZone *) zone;
|
||||
- (void) setPower: (double) newValue;
|
||||
- (double) power;
|
||||
- (void) setParameter: (double) newValue;
|
||||
- (double) parameter;
|
||||
- (double) rawValue: (double) x;
|
||||
|
||||
@end
|
||||
|
||||
@interface OOJoystickSplineAxisProfile: OOJoystickAxisProfile
|
||||
{
|
||||
@private
|
||||
NSMutableArray *controlPoints;
|
||||
NSArray *segments;
|
||||
}
|
||||
|
||||
- (id) init;
|
||||
- (void) dealloc;
|
||||
- (id) copyWithZone: (NSZone *) zone;
|
||||
- (int) addControl: (NSPoint) point;
|
||||
- (NSPoint) pointAtIndex: (int) index;
|
||||
- (int) countPoints;
|
||||
- (void) removeControl: (int) index;
|
||||
- (void) clearControlPoints;
|
||||
- (void) moveControl: (int) index point: (NSPoint) point;
|
||||
- (double) rawValue: (double) x;
|
||||
- (double) gradient: (double) x;
|
||||
- (NSArray *) controlPoints;
|
||||
|
||||
@end
|
||||
|
628
src/Core/OOJoystickProfile.m
Normal file
628
src/Core/OOJoystickProfile.m
Normal file
@ -0,0 +1,628 @@
|
||||
/*
|
||||
|
||||
OOJoystickProfile.m
|
||||
|
||||
Oolite
|
||||
Copyright (C) 2004-2013 Giles C Williams and contributors
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#import "OOJoystickManager.h"
|
||||
#import "OOJoystickProfile.h"
|
||||
#import "OOMaths.h"
|
||||
#import "OOLoggingExtended.h"
|
||||
#import "Universe.h"
|
||||
|
||||
#define SPLINE_POINT_MIN_SPACING 0.02
|
||||
|
||||
@interface OOJoystickSplineSegment: NSObject <NSCopying>
|
||||
{
|
||||
@private
|
||||
double start;
|
||||
double end;
|
||||
double a[4];
|
||||
}
|
||||
|
||||
- (id) init;
|
||||
|
||||
// Linear spline from left point to right point. Returns nil if right.x - left.x <= 0.0.
|
||||
- (id) initWithData: (NSPoint) left right: (NSPoint) right;
|
||||
|
||||
// Quadratic spline from left point to right point, with gradient specified at left. returns nil if right.x - left.x <= 0.0.
|
||||
- (id) initWithData: (NSPoint) left right: (NSPoint) right gradientleft: (double) gradientleft;
|
||||
|
||||
// Quadratic spline from left point to right point, with gradient specified at right. returns nil if right.x - left.x <= 0.0.
|
||||
- (id) initWithData: (NSPoint) left right: (NSPoint) right gradientright: (double) gradientright;
|
||||
|
||||
// Cubic spline from left point to right point, with gradients specified at end points. returns nil if right.x - left.x <= 0.0.
|
||||
- (id) initWithData: (NSPoint) left right: (NSPoint) right gradientleft: (double) gradientleft gradientright: (double) gradientright;
|
||||
|
||||
// Linear spline from left point to right point. Returns nil if right.x - left.x <= 0.0.
|
||||
+ (id) segmentWithData: (NSPoint) left right: (NSPoint) right;
|
||||
|
||||
// Quadratic spline from left point to right point, with gradient specified at left. returns nil if right.x - left.x <= 0.0.
|
||||
+ (id) segmentWithData: (NSPoint) left right: (NSPoint) right gradientleft: (double) gradientleft;
|
||||
|
||||
// Quadratic spline from left point to right point, with gradient specified at right. returns nil if right.x - left.x <= 0.0.
|
||||
+ (id) segmentWithData: (NSPoint) left right: (NSPoint) right gradientright: (double) gradientright;
|
||||
|
||||
// Cubic spline from left point to right point, with gradients specified at end points. returns nil if right.x - left.x <= 0.0.
|
||||
+ (id) segmentWithData: (NSPoint) left right: (NSPoint) right gradientleft: (double) gradientleft gradientright: (double) gradientright;
|
||||
|
||||
- (id) copyWithZone: (NSZone *) zone;
|
||||
- (double) start;
|
||||
- (double) end;
|
||||
- (double) value: (double) t;
|
||||
- (double) gradient: (double) t;
|
||||
|
||||
@end
|
||||
|
||||
@interface OOJoystickSplineAxisProfile (Private)
|
||||
|
||||
// Create the segments from the control points. If there's a problem, e.g. control points not in order or overlapping,
|
||||
// leave segments as they are and return NO. Otherwise return YES.
|
||||
- (BOOL) makeSegments;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation OOJoystickAxisProfile
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
deadzone = STICK_DEADZONE;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id) copyWithZone: (NSZone *) zone
|
||||
{
|
||||
OOJoystickAxisProfile *copy = [[[self class] alloc] init];
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
- (double) rawValue: (double) x
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
- (double) value: (double) x
|
||||
{
|
||||
if (fabs(x) < deadzone)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
return x < 0 ? -[self rawValue: (-x-deadzone)/(1.0-deadzone)] : [self rawValue: (x-deadzone)/(1.0-deadzone)];
|
||||
}
|
||||
|
||||
- (double) deadzone
|
||||
{
|
||||
return deadzone;
|
||||
}
|
||||
|
||||
- (void) setDeadzone: (double) newValue
|
||||
{
|
||||
deadzone = OOClamp_0_1_d(newValue);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation OOJoystickStandardAxisProfile
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
power = 1.0;
|
||||
parameter = 1.0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id) copyWithZone: (NSZone *) zone
|
||||
{
|
||||
OOJoystickStandardAxisProfile *copy = [[[self class] alloc] init];
|
||||
copy->power = power;
|
||||
copy->parameter = parameter;
|
||||
return copy;
|
||||
}
|
||||
|
||||
- (void) setPower: (double) newValue
|
||||
{
|
||||
if (newValue < 1.0)
|
||||
{
|
||||
power = 1.0;
|
||||
}
|
||||
else if (newValue > STICKPROFILE_MAX_POWER)
|
||||
{
|
||||
power = STICKPROFILE_MAX_POWER;
|
||||
}
|
||||
else
|
||||
{
|
||||
power = newValue;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
- (double) power
|
||||
{
|
||||
return power;
|
||||
}
|
||||
|
||||
|
||||
- (void) setParameter: (double) newValue
|
||||
{
|
||||
parameter = OOClamp_0_1_d(newValue);
|
||||
return;
|
||||
}
|
||||
|
||||
- (double) parameter
|
||||
{
|
||||
return parameter;
|
||||
}
|
||||
|
||||
|
||||
- (double) rawValue: (double) x
|
||||
{
|
||||
if (x < 0)
|
||||
{
|
||||
return -OOClamp_0_1_d(parameter * pow(-x,power)-(parameter - 1.0)*(-x));
|
||||
}
|
||||
return OOClamp_0_1_d(parameter * pow(x,power)-(parameter - 1.0)*(x));
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation OOJoystickSplineSegment
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
start = 0.0;
|
||||
end = 1.0;
|
||||
a[0] = 0.0;
|
||||
a[1] = 1.0;
|
||||
a[2] = 0.0;
|
||||
a[3] = 0.0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id) copyWithZone: (NSZone *) zone
|
||||
{
|
||||
OOJoystickSplineSegment *copy = [[OOJoystickSplineSegment allocWithZone: zone] init];
|
||||
copy->start = start;
|
||||
copy->end = end;
|
||||
copy->a[0] = a[0];
|
||||
copy->a[1] = a[1];
|
||||
copy->a[2] = a[2];
|
||||
copy->a[3] = a[3];
|
||||
return copy;
|
||||
}
|
||||
|
||||
- (id) initWithData: (NSPoint) left right: (NSPoint) right
|
||||
{
|
||||
double dx = right.x - left.x;
|
||||
if (dx <= 0.0)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
if ((self = [super init]))
|
||||
{
|
||||
start = left.x;
|
||||
end = right.x;
|
||||
a[1] = (right.y - left.y)/dx;
|
||||
a[0] = left.y-a[1]*left.x;
|
||||
a[2] = 0.0;
|
||||
a[3] = 0.0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id) initWithData:(NSPoint) left right: (NSPoint) right gradientleft: (double) gradientleft
|
||||
{
|
||||
double dx = right.x - left.x;
|
||||
if (dx <= 0.0)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
if ((self = [super init]))
|
||||
{
|
||||
start = left.x;
|
||||
end = right.x;
|
||||
a[0] = left.y*right.x*(right.x - 2*left.x)/(dx*dx) + right.y*left.x*left.x/(dx*dx) - gradientleft*left.x*right.x/dx;
|
||||
a[1] = 2*left.x*(left.y-right.y)/(dx*dx) + gradientleft*(left.x+right.x)/dx;
|
||||
a[2] = (right.y-left.y)/(dx*dx) - gradientleft/dx;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id) initWithData: (NSPoint) left right: (NSPoint) right gradientright: (double) gradientright
|
||||
{
|
||||
double dx = right.x - left.x;
|
||||
if (dx <= 0.0)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
if ((self = [super init]))
|
||||
{
|
||||
start = left.x;
|
||||
end = right.x;
|
||||
a[0] = (left.y*right.x*right.x + right.y*left.x*(left.x-2*right.x))/(dx*dx) + gradientright*left.x*right.x/dx;
|
||||
a[1] = 2*right.x*(right.y-left.y)/(dx*dx) - gradientright*(left.x+right.x)/dx;
|
||||
a[2] = (left.y-right.y)/(dx*dx) + gradientright/dx;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id) initWithData: (NSPoint) left right: (NSPoint) right gradientleft: (double) gradientleft gradientright: (double) gradientright
|
||||
{
|
||||
double dx = right.x - left.x;
|
||||
if (dx <= 0.0)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
if ((self = [super init]))
|
||||
{
|
||||
start = left.x;
|
||||
end = right.x;
|
||||
a[0] = (left.y*right.x*right.x*(right.x-3*left.x) - right.y*left.x*left.x*(left.x-3*right.x))/(dx*dx*dx) - (gradientleft*right.x + gradientright*left.x)*left.x*right.x/(dx*dx);
|
||||
a[1] = 6*left.x*right.x*(left.y-right.y)/(dx*dx*dx) + (gradientleft*right.x*(right.x+2*left.x) + gradientright*left.x*(left.x+2*right.x))/(dx*dx);
|
||||
a[2] = 3*(left.x+right.x)*(right.y-left.y)/(dx*dx*dx) - (gradientleft*(2*right.x+left.x)+gradientright*(2*left.x+right.x))/(dx*dx);
|
||||
a[3] = 2*(left.y-right.y)/(dx*dx*dx) + (gradientleft+gradientright)/(dx*dx);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id) segmentWithData: (NSPoint) left right: (NSPoint) right
|
||||
{
|
||||
OOJoystickSplineSegment *segment = [[OOJoystickSplineSegment alloc] initWithData: left right:right];
|
||||
return [segment autorelease];
|
||||
}
|
||||
|
||||
|
||||
+ (id) segmentWithData: (NSPoint) left right: (NSPoint) right gradientleft: (double) gradientleft
|
||||
{
|
||||
OOJoystickSplineSegment *segment = [[OOJoystickSplineSegment alloc] initWithData: left right:right gradientleft:gradientleft];
|
||||
return [segment autorelease];
|
||||
}
|
||||
|
||||
|
||||
+ (id) segmentWithData: (NSPoint) left right: (NSPoint) right gradientright: (double) gradientright
|
||||
{
|
||||
OOJoystickSplineSegment *segment = [[OOJoystickSplineSegment alloc] initWithData: left right:right gradientright:gradientright];
|
||||
return [segment autorelease];
|
||||
}
|
||||
|
||||
|
||||
+ (id) segmentWithData: (NSPoint) left right: (NSPoint) right gradientleft: (double) gradientleft gradientright: (double) gradientright
|
||||
{
|
||||
OOJoystickSplineSegment *segment = [[OOJoystickSplineSegment alloc] initWithData: left right:right gradientleft:gradientleft gradientright:gradientright];
|
||||
return [segment autorelease];
|
||||
}
|
||||
|
||||
- (double) start
|
||||
{
|
||||
return start;
|
||||
}
|
||||
|
||||
|
||||
- (double) end
|
||||
{
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
- (double) value: (double) x
|
||||
{
|
||||
return a[0] + (a[1] + (a[2] + a[3]*x)*x)*x;
|
||||
}
|
||||
|
||||
- (double) gradient: (double) x
|
||||
{
|
||||
return a[1]+(2*a[2] + 3*a[3]*x)*x;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation OOJoystickSplineAxisProfile
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
controlPoints = [[NSMutableArray alloc] initWithCapacity: 2];
|
||||
segments = nil;
|
||||
[self makeSegments];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[controlPoints release];
|
||||
[segments release];
|
||||
[super dealloc];
|
||||
return;
|
||||
}
|
||||
|
||||
- (id) copyWithZone: (NSZone *) zone
|
||||
{
|
||||
OOJoystickSplineAxisProfile *copy = [[[self class] alloc] init];
|
||||
copy->controlPoints = [controlPoints copyWithZone: zone];
|
||||
copy->segments = [segments copyWithZone: zone];
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
- (int) addControl: (NSPoint) point
|
||||
{
|
||||
NSPoint left, right;
|
||||
int i;
|
||||
|
||||
if (point.x <= SPLINE_POINT_MIN_SPACING || point.x >= 1 - SPLINE_POINT_MIN_SPACING )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
left.x = 0.0;
|
||||
left.y = 0.0;
|
||||
for (i = 0; i <= [controlPoints count]; i++ )
|
||||
{
|
||||
if (i < [controlPoints count])
|
||||
{
|
||||
right = [[controlPoints objectAtIndex: i] pointValue];
|
||||
}
|
||||
else
|
||||
{
|
||||
right = NSMakePoint(1.0,1.0);
|
||||
}
|
||||
if ((point.x - left.x) < SPLINE_POINT_MIN_SPACING)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
[controlPoints replaceObjectAtIndex: i - 1 withObject: [NSValue valueWithPoint: point]];
|
||||
[self makeSegments];
|
||||
return i - 1;
|
||||
}
|
||||
if ((right.x - point.x) >= SPLINE_POINT_MIN_SPACING)
|
||||
{
|
||||
[controlPoints insertObject: [NSValue valueWithPoint: point] atIndex: i];
|
||||
[self makeSegments];
|
||||
return i;
|
||||
}
|
||||
left = right;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
- (NSPoint) pointAtIndex: (int) index
|
||||
{
|
||||
NSPoint point;
|
||||
if (index < 0)
|
||||
{
|
||||
point.x = 0.0;
|
||||
point.y = 0.0;
|
||||
}
|
||||
else if (index >= [controlPoints count])
|
||||
{
|
||||
point.x = 1.0;
|
||||
point.y = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
point = [[controlPoints objectAtIndex: index] pointValue];
|
||||
}
|
||||
return point;
|
||||
}
|
||||
|
||||
- (int) countPoints
|
||||
{
|
||||
return [controlPoints count];
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *) controlPoints
|
||||
{
|
||||
return [NSArray arrayWithArray: controlPoints];
|
||||
}
|
||||
|
||||
// Calculate segments from control points
|
||||
- (BOOL) makeSegments
|
||||
{
|
||||
int i;
|
||||
NSPoint left, right, next;
|
||||
double gradientleft, gradientright;
|
||||
OOJoystickSplineSegment* segment;
|
||||
BOOL first_segment = YES;
|
||||
NSMutableArray *new_segments = [NSMutableArray arrayWithCapacity: ([controlPoints count] + 1)];
|
||||
|
||||
left.x = 0.0;
|
||||
left.y = 0.0;
|
||||
if ([controlPoints count] == 0)
|
||||
{
|
||||
right.x = 1.0;
|
||||
right.y = 1.0;
|
||||
segment = [OOJoystickSplineSegment segmentWithData: left right: right];
|
||||
[new_segments addObject:segment];
|
||||
}
|
||||
else
|
||||
{
|
||||
gradientleft = 1.0;
|
||||
right = [[controlPoints objectAtIndex: 0] pointValue];
|
||||
for (i = 0; i < [controlPoints count]; i++)
|
||||
{
|
||||
next = [self pointAtIndex: i + 1];
|
||||
if (next.x - left.x > 0.0)
|
||||
{
|
||||
// we make the gradient at right equal to the gradient of a straight line between the neighcouring points
|
||||
gradientright = (next.y - left.y)/(next.x - left.x);
|
||||
if (first_segment)
|
||||
{
|
||||
segment = [OOJoystickSplineSegment segmentWithData: left right: right gradientright: gradientright];
|
||||
}
|
||||
else
|
||||
{
|
||||
segment = [OOJoystickSplineSegment segmentWithData: left right: right gradientleft: gradientleft gradientright: gradientright];
|
||||
}
|
||||
if (segment == nil)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
[new_segments addObject: segment];
|
||||
gradientleft = gradientright;
|
||||
first_segment = NO;
|
||||
left = right;
|
||||
}
|
||||
}
|
||||
right = next;
|
||||
}
|
||||
right.x = 1.0;
|
||||
right.y = 1.0;
|
||||
segment = [OOJoystickSplineSegment segmentWithData: left right: right gradientleft: gradientleft];
|
||||
if (segment == nil)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
[new_segments addObject: segment];
|
||||
}
|
||||
[segments release];
|
||||
segments = [[NSArray arrayWithArray: new_segments] retain];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void) removeControl: (int) index
|
||||
{
|
||||
if (index >= 0 && index < [controlPoints count])
|
||||
{
|
||||
[controlPoints removeObjectAtIndex: index];
|
||||
[self makeSegments];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
- (void) clearControlPoints
|
||||
{
|
||||
[controlPoints removeAllObjects];
|
||||
[self makeSegments];
|
||||
}
|
||||
|
||||
- (void) moveControl: (int) index point: (NSPoint) point
|
||||
{
|
||||
NSPoint left, right;
|
||||
|
||||
point.x = OOClamp_0_1_d(point.x);
|
||||
point.y = OOClamp_0_1_d(point.y);
|
||||
if (index < 0 || index >= [controlPoints count])
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (index == 0)
|
||||
{
|
||||
left.x = 0.0;
|
||||
right.x = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
left = [[controlPoints objectAtIndex: (index-1)] pointValue];
|
||||
}
|
||||
if (index == [controlPoints count] - 1)
|
||||
{
|
||||
right.x = 1.0;
|
||||
right.y = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
right = [[controlPoints objectAtIndex: (index+1)] pointValue];
|
||||
}
|
||||
// preserve order of control points - if we attempt to move this control point beyond
|
||||
// either of its neighbours, move it back inside. Also keep neighbours a distance of at least SPLINE_POINT_MIN_SPACING apart
|
||||
if (point.x - left.x < SPLINE_POINT_MIN_SPACING)
|
||||
{
|
||||
point.x = left.x + SPLINE_POINT_MIN_SPACING;
|
||||
if (right.x - point.x < SPLINE_POINT_MIN_SPACING)
|
||||
{
|
||||
point.x = (left.x + right.x)/2;
|
||||
}
|
||||
}
|
||||
else if (right.x - point.x < SPLINE_POINT_MIN_SPACING)
|
||||
{
|
||||
point.x = right.x - SPLINE_POINT_MIN_SPACING;
|
||||
if (point.x - left.x < SPLINE_POINT_MIN_SPACING)
|
||||
{
|
||||
point.x = (left.x + right.x)/2;
|
||||
}
|
||||
}
|
||||
[controlPoints replaceObjectAtIndex: index withObject: [NSValue valueWithPoint: point]];
|
||||
[self makeSegments];
|
||||
return;
|
||||
}
|
||||
|
||||
- (double) rawValue: (double) x
|
||||
{
|
||||
int i;
|
||||
OOJoystickSplineSegment *segment;
|
||||
double sign;
|
||||
|
||||
if (x < 0)
|
||||
{
|
||||
sign = -1.0;
|
||||
x = -x;
|
||||
}
|
||||
else
|
||||
{
|
||||
sign = 1.0;
|
||||
}
|
||||
for (i = 0; i < [segments count]; i++)
|
||||
{
|
||||
segment = [segments objectAtIndex: i];
|
||||
if ([segment end] > x)
|
||||
{
|
||||
return sign * OOClamp_0_1_d([segment value:x]);
|
||||
}
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
- (double) gradient: (double) x
|
||||
{
|
||||
int i;
|
||||
OOJoystickSplineSegment *segment;
|
||||
for (i = 0; i < [segments count]; i++)
|
||||
{
|
||||
segment = [segments objectAtIndex: i];
|
||||
if ([segment end] > x)
|
||||
{
|
||||
return [segment gradient:x];
|
||||
}
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
@ -18,6 +18,7 @@ ENTRY(GUI_SCREEN_LOAD, -1)
|
||||
ENTRY(GUI_SCREEN_SAVE, -1)
|
||||
ENTRY(GUI_SCREEN_SAVE_OVERWRITE, -1)
|
||||
ENTRY(GUI_SCREEN_STICKMAPPER, -1)
|
||||
ENTRY(GUI_SCREEN_STICKPROFILE, -1)
|
||||
ENTRY(GUI_SCREEN_MISSION, -1)
|
||||
ENTRY(GUI_SCREEN_REPORT, -1)
|
||||
ENTRY(GUI_SCREEN_INTERFACES, -1)
|
||||
|
Loading…
x
Reference in New Issue
Block a user