diff options
Diffstat (limited to 'game/code/input')
48 files changed, 9563 insertions, 0 deletions
diff --git a/game/code/input/FEMouse.cpp b/game/code/input/FEMouse.cpp new file mode 100644 index 0000000..4a31ea6 --- /dev/null +++ b/game/code/input/FEMouse.cpp @@ -0,0 +1,338 @@ +#include <input/FEMouse.h> +#include <presentation/gui/guimanager.h> +#include <presentation/gui/guisystem.h> +#include <presentation/gui/guiuserinputhandler.h> +#include <gameflow/gameflow.h> +#include <contexts/contextenum.h> +#include <contexts/gameplay/gameplaycontext.h> +#include <main/win32platform.h> + +#ifdef ENABLE_DYNA_LOADED_IMAGES +const char* DYNAMIC_RESOURCES_DIR = "art\\frontend\\dynaload\\images\\"; +#endif + +const float WIN_TO_P3D_POINT_SCALE_FACTOR = 2.0f; + +/****************************************************************************** + Construction/Destruction +*****************************************************************************/ + +FEMouse::FEMouse() +: m_bMoved( false ), + m_bClickable( true ), + m_bSelectable( true ), + m_bMovable( true ), + m_oldPositionX(0), + m_oldPositionY(0), + m_hotSpotType( HOTSPOT_BUTTON ), + m_horzDir( NO_HORZ_MOVEMENT ), + m_bClickAndStop(false), + m_bInGame( false ), + m_bInGameOverride( false ), + m_inGamePosX( 0 ), + m_inGamePosY( 0 ), + m_buttonDownSelection( 0 ) +{ + m_pCursor = new MouseCursor(); + memset( m_button, 0, sizeof(m_button)); +} + +FEMouse::~FEMouse() +{ + delete m_pCursor; + m_pCursor = NULL; +} + +void FEMouse::InitMouseCursor( tDrawable* pCursor ) +{ + m_pCursor->Set( pCursor ); +} + +eFEMouseHorzDir FEMouse::OnSliderHorizontalClickDrag() const +{ + if (IsLeftButtonDown() && + m_hotSpotType == HOTSPOT_SLIDER && + m_horzDir != NO_HORZ_MOVEMENT && + m_bMoved == true ) + { + return m_horzDir; + } + else return NO_HORZ_MOVEMENT; +} + +bool FEMouse::DidWeMove( int newX, int newY ) const +{ + return ( (newX != m_oldPositionX) || (newY != m_oldPositionY) ); +} + +void FEMouse::Move( int mouseX, int mouseY, long screenWidth, long screenHeight ) +{ + if( !m_bMovable ) return; + m_bMoved = true; + + // let us know what direction it moved horizontally. + if( m_oldPositionX < mouseX ) m_horzDir = MDIR_RIGHT; + else if( m_oldPositionX > mouseX ) m_horzDir = MDIR_LEFT; + else m_horzDir = NO_HORZ_MOVEMENT; + + + m_oldPositionX = mouseX; + m_oldPositionY = mouseY; + + // Normalize the windows mouse coordinates that are in pixel units, to 2d world units. + // From ( -1 to 1 ) on the major axis and ( -height/width to -height/width ) on the minor. + // We must scale the incoming coordinates and offset them to the center. + // We must also handle the difference in width and height, to compensate for the aspect + // ratio of the display. + + const float ASPECT = (float)screenWidth/(float)screenHeight; // The screen aspect ratio. + + float deltaX = ( (mouseX/( screenWidth/WIN_TO_P3D_POINT_SCALE_FACTOR )) - 1.0f ); + float deltaY = ( 1.0f - (mouseY/(screenHeight/WIN_TO_P3D_POINT_SCALE_FACTOR)))/ASPECT; + + m_pCursor->SetPos( deltaX/WIN_TO_P3D_POINT_SCALE_FACTOR, deltaY/WIN_TO_P3D_POINT_SCALE_FACTOR ); + //rDebugPrintf("Mouse moved to X: %g Y: %g \n", deltaX, deltaY); +} + +void FEMouse::Update() +{ + bool ingame = m_bInGame && ! m_bInGameOverride; + bool bLoading = (GetGameFlow()->GetCurrentContext() == CONTEXT_LOADING_GAMEPLAY) || + (GetGameFlow()->GetCurrentContext() == CONTEXT_LOADING_SUPERSPRINT) || + (GetGameFlow()->GetCurrentContext() == CONTEXT_EXIT); + if( ingame || bLoading ) return; + if( !m_pCursor->IsVisible() ) return; + + CGuiWindow* pCurrentWindow = GetGuiSystem()->GetCurrentManager()->GetCurrentWindow(); + CGuiMenu* pCurrentMenu = pCurrentWindow->HasMenu(); + if( !pCurrentMenu || (pCurrentMenu && !pCurrentMenu->HasSelectionBeenMade()) )//m_bSelectable ) + { + + // Dusit here, + // Took out the update only on mouse moved test. + // This is a problem when a new front-end screen item appears underneath + // the mouse cursor, but the mouse hasn't moved yet, so it can't click + // on the front-end item. So we either need to get notified when that + // happens and manually update the mouse focus via callback, or just + // do it every frame. I think it's reasonable to do it every frame; otherwise, if + // the call is really expensive, we'd end up with low framerate while mouse is + // moving and good framerate when mouse is stationary (which is not + // a good optimization). + // + //if( m_bMoved ) //Only update the hotspot checking if the mouse moved! + //{ + // + m_hotSpotType = pCurrentWindow->CheckCursorAgainstHotspots( m_pCursor->XPos()*WIN_TO_P3D_POINT_SCALE_FACTOR, + m_pCursor->YPos()*WIN_TO_P3D_POINT_SCALE_FACTOR); + if( m_hotSpotType == HOTSPOT_NONE ) + { + // if the user is still holding onto the button, don't tamper with its state. + // we deal with that case later (just below). + if( m_button[ BUTTON_LEFT ] != BUTTON_CLICKHOLD ) + { + m_button[ BUTTON_LEFT ] = BUTTON_IDLE; + } + } + m_bMoved = false; + rAssert( !m_bMoved ); + + if( pCurrentMenu ) + { + if( m_button[ BUTTON_LEFT ] == BUTTON_CLICKHOLD ) + { + // deal with highlighting the hotspot... + CGuiUserInputHandler* userInputHandler = GetGuiSystem()->GetUserInputHandler( 0 ); + switch( m_hotSpotType ) + { + case HOTSPOT_BUTTON: + if( m_buttonDownSelection == pCurrentMenu->GetSelection() && m_bClickable ) + { + pCurrentMenu->HandleMessage( GUI_MSG_MOUSE_LCLICKHOLD, 1 ); + } + break; + case HOTSPOT_NONE: + if( m_bClickable ) + { + pCurrentMenu->HandleMessage( GUI_MSG_MOUSE_LCLICKHOLD, 0 ); + } + break; + default: break; + } + } + else + { + // If nothing is being held down we should eliminate the highlighting. + // This fixes the problem where if you hold down LMB then right-click to + // escape to previous screen, when you go back to the first screen, the + // highlighting will still be in effect. + // + if( m_bClickable && m_bSelectable ) + { + pCurrentMenu->HandleMessage( GUI_MSG_MOUSE_LCLICKHOLD, 0 ); + } + } + } + } + m_pCursor->Render(); +} + +void FEMouse::ButtonDown( eFEMouseButton buttonType ) +{ + // don't allow clicking when selectable not on + CGuiMenu* pCurrentMenu = GetGuiSystem()->GetCurrentManager()->GetCurrentWindow()->HasMenu(); + if( !(!pCurrentMenu || (pCurrentMenu && !pCurrentMenu->HasSelectionBeenMade())) )//!m_bSelectable ) + { + return; + } + + m_button[buttonType] = BUTTON_CLICKHOLD; + + // what follows concerns only left mouse button + if( buttonType != BUTTON_LEFT ) + { + return; + } + + // remember what menu item it was that we pressed down on... + m_buttonDownSelection = pCurrentMenu ? pCurrentMenu->GetSelection() : -1; + + // deal with highlighting the hotspot... + if( pCurrentMenu ) + { + CGuiUserInputHandler* userInputHandler = GetGuiSystem()->GetUserInputHandler( 0 ); + switch( m_hotSpotType ) + { + case HOTSPOT_BUTTON: + if( m_bClickable ) + { + pCurrentMenu->HandleMessage( GUI_MSG_MOUSE_LCLICKHOLD, 1 ); + } + break; + case HOTSPOT_NONE: + if( m_bClickable ) + { + pCurrentMenu->HandleMessage( GUI_MSG_MOUSE_LCLICKHOLD, 0 ); + } + break; + default: break; + } + } +} + +void FEMouse::ButtonUp( enum eFEMouseButton buttonType ) +{ + // don't allow clicking when selectable not on + CGuiMenu* pCurrentMenu = GetGuiSystem()->GetCurrentManager()->GetCurrentWindow()->HasMenu(); + if( !(!pCurrentMenu || (pCurrentMenu && !pCurrentMenu->HasSelectionBeenMade())) )//!m_bSelectable ) + { + return; + } + + m_button[ buttonType ] = BUTTON_CLICKED; + + // what follows concerns only left mouse button + if( buttonType != BUTTON_LEFT ) + { + return; + } + + ///////////////////////////////////////////////////////////////// + // Deal with the consequence of left-clicking a menu button + + // + // if we release mouse button on something other than the item we + // were on when we pressed the mouse button, we don't do anything + // + int currSelection = pCurrentMenu ? pCurrentMenu->GetSelection() : -1; + if( currSelection != m_buttonDownSelection ) + { + return; + } + + // at this point, the hotspot we're currently on matches the + // one we were at when we pressed the left mouse button... so click! + CGuiUserInputHandler* userInputHandler = GetGuiSystem()->GetUserInputHandler( 0 ); + switch( m_hotSpotType ) + { + case HOTSPOT_BUTTON: + userInputHandler->Select(); + m_bSelectable = false; // need to disable selectable IMMEDIATELY (not when screen exits) + break; + case HOTSPOT_ARROWLEFT: + userInputHandler->Left(); + break; + case HOTSPOT_ARROWRIGHT: + userInputHandler->Right(); + break; + case HOTSPOT_ARROWUP: + userInputHandler->Up(); + break; + case HOTSPOT_ARROWDOWN: + userInputHandler->Down(); + break; + case HOTSPOT_LTRIGGER: + userInputHandler->L1(); + break; + case HOTSPOT_RTRIGGER: + userInputHandler->R1(); + break; + default: break; + } + + // reset left button state + m_button[ BUTTON_LEFT ] = BUTTON_IDLE; +} + +void FEMouse::SetInGameMode( bool ingame ) +{ + m_bInGame = ingame; + SetupInGameMode(); +} + +void FEMouse::SetInGameOverride( bool override ) +{ + m_bInGameOverride = override; + SetupInGameMode(); +} + +void FEMouse::SetupInGameMode() +{ + bool ingame = m_bInGame && ! m_bInGameOverride; + + m_pCursor->SetVisible( !ingame ); + + if( ingame ) + { + RECT windowRect; + GetWindowRect( Win32Platform::GetInstance()->GetHwnd(), &windowRect ); + + // Save the old cursor position. + POINT oldPos; + GetCursorPos( & oldPos ); + m_inGamePosX = oldPos.x; + m_inGamePosY = oldPos.y; + + // Center the cursor. + SetCursorPos( ( windowRect.left + windowRect.right ) / 2, + ( windowRect.top + windowRect.bottom ) / 2 ); + + // Set up the clipping rectangle. + windowRect.top += 30; + windowRect.bottom -= 10; + windowRect.left += 10; + windowRect.right -= 10; + ClipCursor( &windowRect ); + } + else + { + // Remove the clipping rectangle. + ClipCursor( NULL ); + + // Restore the old cursor position. + if( m_inGamePosX != -1 ) + { + SetCursorPos( m_inGamePosX, m_inGamePosY ); + m_inGamePosX = -1; + } + } +}
\ No newline at end of file diff --git a/game/code/input/FEMouse.h b/game/code/input/FEMouse.h new file mode 100644 index 0000000..1298f80 --- /dev/null +++ b/game/code/input/FEMouse.h @@ -0,0 +1,109 @@ +/****************************************************************************** + File: FEMouse.h + Desc: Interface for the Frontend Mouse class. + - Uses the windows mouse functionality. + + Date: June 13, 2003 + History: +*****************************************************************************/ + +#ifndef FEMOUSE_H +#define FEMOUSE_H + +#include <input/MouseCursor.h> + +enum eFEMouseButton +{ + BUTTON_LEFT, + BUTTON_RIGHT, + NUM_BUTTON_TYPES +}; + +enum eFEMouseHorzDir +{ + MDIR_LEFT, + MDIR_RIGHT, + NUM_MOUSE_HORZ_DIRECTIONS, + NO_HORZ_MOVEMENT +}; + +enum eFEHotspotType +{ + HOTSPOT_BUTTON, + HOTSPOT_ARROWLEFT, + HOTSPOT_ARROWRIGHT, + HOTSPOT_ARROWUP, + HOTSPOT_ARROWDOWN, + HOTSPOT_SLIDER, + HOTSPOT_LTRIGGER, + HOTSPOT_RTRIGGER, + NUM_HOTSPOT_TYPES, + HOTSPOT_NONE +}; + +enum eFEButtonStates +{ + BUTTON_IDLE, + BUTTON_CLICKHOLD, + BUTTON_CLICKED, + NUM_BUTTON_STATES +}; + +class FEMouse +{ +public: + FEMouse(); + ~FEMouse(); + + MouseCursor* getCursor() const { return m_pCursor; } + bool Moved() const { return m_bMoved; } + bool IsClickable() const { return m_bClickable; } + eFEMouseHorzDir MovedHorizontally() const { return m_horzDir; } + bool IsLeftButtonDown() const { return (m_button[BUTTON_LEFT]==BUTTON_CLICKHOLD); } + eFEHotspotType LeftButtonDownOn() const + { + return ((m_button[BUTTON_LEFT]==BUTTON_CLICKHOLD) ? m_hotSpotType : HOTSPOT_NONE); + } + bool IsRightButtonDown() const { return (m_button[BUTTON_RIGHT]==BUTTON_CLICKHOLD); } + + void InitMouseCursor( tDrawable* pCursor ); + void SetClickable( bool bClickable ) { m_bClickable = bClickable; } + void SetSelectable( bool bSelectable ) { m_bSelectable = bSelectable; } + void SetClickStopMode( bool bClickAndStop ) { m_bClickAndStop = bClickAndStop; } + void ButtonDown( eFEMouseButton buttonType ); + void ButtonUp( eFEMouseButton buttonType ); + + eFEMouseHorzDir OnSliderHorizontalClickDrag() const; //Is on a slider clicking and dragging horizontally. + bool DidWeMove( int newX, int newY ) const; + void Move( int mouseX, int mouseY, long screenWidth, long screenHeight ); + void Update(); + + void SetInGameMode( bool ingame ); + void SetInGameOverride( bool override ); + +private: + void SetupInGameMode(); + +private: + MouseCursor* m_pCursor; + bool m_bMoved; + bool m_bClickable; + bool m_bSelectable; + bool m_bMovable; + bool m_bClickAndStop; // if this is on, if a button is clicked, mouse processing stops. + char m_button[ NUM_BUTTON_TYPES ]; + eFEHotspotType m_hotSpotType; + eFEMouseHorzDir m_horzDir; + + int m_oldPositionX, //We save the last position of the mouse. + m_oldPositionY; + + bool m_bInGame; + bool m_bInGameOverride; + int m_inGamePosX; + int m_inGamePosY; + + int m_buttonDownSelection; +}; + +#endif
\ No newline at end of file diff --git a/game/code/input/Gamepad.cpp b/game/code/input/Gamepad.cpp new file mode 100644 index 0000000..5bf4445 --- /dev/null +++ b/game/code/input/Gamepad.cpp @@ -0,0 +1,567 @@ +//********************************************************** +// C++ Class Name : Gamepad +// --------------------------------------------------------- +// Filetype: (SOURCE) +// Filepath: D:/simpsonsrr2/game/code/input/Gamepad.cpp +// +// +// GDPro Properties +// --------------------------------------------------- +// - GD Symbol Type : CLD_Class +// - GD Method : UML ( 5.0 ) +// - GD System Name : Simpsons Controller System +// - GD Diagram Type : Class Diagram +// - GD Diagram Name : Input Device +// --------------------------------------------------- +// Author : nharan +// Creation Date : Tues - May 20, 2003 +// +// Change Log : +// +//********************************************************** +#include <input/Gamepad.h> + +#define DIRECTINPUT_VERSION 0x0800 +#include <dinput.h> + +//============================================================================== +// Gamepad constructor +//============================================================================== +// +// Description: Creates an empty gamepad. +// +// Parameters: None. +// +// Return: None. +// +//============================================================================== + +Gamepad::Gamepad() +: RealController( GAMEPAD ) +{ + ClearMappedButtons(); +} + +//============================================================================== +// Gamepad destructor +//============================================================================== +// +// Description: Destroy the gamepad. +// +// Parameters: None. +// +// Return: None. +// +//============================================================================== + +Gamepad::~Gamepad() +{ +} + +//============================================================================== +// Gamepad::IsInputAxis +//============================================================================== +// +// Description: Identifies any keys that are input axes. (can go in two directions) +// +// Parameters: dxkey - the directinput index identifying the physical input. +// +// Return: true if input is an axis +// +//============================================================================== + +bool Gamepad::IsInputAxis( int dxKey ) const +{ + switch( dxKey ) + { + case DIJOFS_X: + case DIJOFS_Y: + case DIJOFS_Z: + case DIJOFS_RX: + case DIJOFS_RY: + case DIJOFS_RZ: + case DIJOFS_SLIDER(0): + case DIJOFS_SLIDER(1): + GetButtonEnum( dxKey ); + return true; + default: + return false; + } + +} + +//============================================================================== +// Gamepad::IsPovHat +//============================================================================== +// +// Description: Identifies any keys that are pov hats (go in 4 directions) +// +// Parameters: dxkey - the directinput index identifying the physical input. +// +// Return: true if input is a pov hat +// +//============================================================================== + +bool Gamepad::IsPovHat( int dxKey ) const +{ + switch( dxKey ) + { + case DIJOFS_POV(0): + case DIJOFS_POV(1): + return true; + default: + return false; + } +} + +//============================================================================== +// Gamepad::IsValidInput +//============================================================================== +// +// Description: Returns true if this is a valid input for the controller. +// +// Parameters: dxkey - the directinput index identifying the physical input. +// +// Return: true if key it's a valid input +// +//============================================================================== + +bool Gamepad::IsValidInput( int dxKey ) const +{ + return GetButtonEnum( dxKey ) != NUM_GAMEPAD_BUTTONS; +} + +//============================================================================== +// Gamepad::CalculatePOV +//============================================================================== +// +// Description: Takes a POV input point value and calculates the corresponding +// up/down/left/right directional values. +// +// Parameters: POV value +// +// Return: Up/Down/Left/Right values. +// +//============================================================================== + +void Gamepad::CalculatePOV( float povValue, float* up, float* down, float* right, float* left ) const +{ + // Reset all the directional values to 0. + *up = *down = *left = *right = 0.0f; + + // Convert the POV value to directional values. + // A value of 1 means that the pov is untouched. + if( povValue < 1) + { + // Convert the POV value (0.0f - 1.0f) into radians (0.0f - 2PI) for use with radmath Trig functions. + float angle = ((povValue * 360)/180)*rmt::PI; + + // Calculate the corresponding x and y axis values. + float xValue = rmt::Sin(angle); + float yValue = rmt::Cos(angle); + + // Now assign the value to all the directions. + // Note that we are making the POV a digital button with values of only 0 and 1. + // This is so that walking diagonally is doable, instead of annoyingly slow. + *right = ( xValue > 0.1f ) ? 1.0f : 0.0f; + *left = ( xValue < -0.1f ) ? 1.0f : 0.0f; + *up = ( yValue > 0.1f ) ? 1.0f : 0.0f; + *down = ( yValue < -0.1f ) ? 1.0f : 0.0f; + } +} + +//============================================================================== +// Gamepad::SetMap +//============================================================================== +// +// Description: Sets up a mapping from a dxkey/direction to a virtual button +// +// Parameters: dxkey - the directinput index identifying the physical input. +// direction - the direction of the input +// virtualbutton - the virtual button that has been mapped +// +// Return: true if mapped successfully +// +//============================================================================== + +bool Gamepad::SetMap( int dxKey, eDirectionType dir, int virtualButton ) +{ + rAssert( virtualButton >= 0 && virtualButton < Input::MaxPhysicalButtons ); + + eGamepadButton gbutton = GetButtonEnum( dxKey ); + eMapType maptype = VirtualInputs::GetType( virtualButton ); + + if( gbutton != NUM_GAMEPAD_BUTTONS ) + { + m_ButtonMap[ maptype ][ gbutton ][ dir ] = virtualButton; + } + + return gbutton != NUM_GAMEPAD_BUTTONS; +} + +//============================================================================== +// Gamepad::ClearMap +//============================================================================== +// +// Description: Clears the specified mapping so it no longer exists. +// +// Parameters: dxkey - the directinput index identifying the physical input. +// direction - the direction of the input +// +// Return: n/a +// +//============================================================================== + +void Gamepad::ClearMap( int dxKey, eDirectionType dir, int virtualButton ) +{ + eGamepadButton gbutton = GetButtonEnum( dxKey ); + eMapType maptype = VirtualInputs::GetType( virtualButton ); + + if( gbutton != NUM_GAMEPAD_BUTTONS ) + { + m_ButtonMap[ maptype ][ gbutton ][ dir ] = Input::INVALID_CONTROLLERID; + } +} + +//============================================================================== +// Gamepad::GetMap +//============================================================================== +// +// Description: Retrieves the virtual button of the given type mapped to +// a dxKey, direction +// +// Parameters: dxkey - the directinput index identifying the physical input. +// direction - the direction of the input. +// maptype - the type of virtual button to look up +// +// Return: n/a +// +//============================================================================== + +int Gamepad::GetMap( int dxKey, eDirectionType dir, eMapType map ) const +{ + eGamepadButton gbutton = GetButtonEnum( dxKey ); + + if( gbutton != NUM_GAMEPAD_BUTTONS ) + { + return m_ButtonMap[ map ][ gbutton ][ dir ]; + } + else + { + return Input::INVALID_CONTROLLERID; + } +} + +//============================================================================== +// Gamepad::ClearMappedButtons +//============================================================================== +// +// Description: Clears the cached button mappings +// +// Parameters: n/a +// +// Return: n/a +// +//============================================================================== + +void Gamepad::ClearMappedButtons() +{ + memset( &m_ButtonMap, Input::INVALID_CONTROLLERID, sizeof( m_ButtonMap ) ); +} + +//============================================================================== +// Gamepad::MapInputToDICode +//============================================================================== +// +// Description: Creates an input point -> direct input virtual key code mapping +// for the gamepad. Note: this method is really slow, but it only +// should get called once per game. +// +// Parameters: n/a +// +// Return: n/a +// +//============================================================================== + +void Gamepad::MapInputToDICode() +{ + if( m_InputToDICode != NULL ) + { + delete [] m_InputToDICode; + m_InputToDICode = NULL; + } + + if( m_radController != NULL ) + { + // Get the number of input points + m_numInputPoints = m_radController->GetNumberOfInputPoints(); + + // Set up a cleared index -> di map. + m_InputToDICode = new int[ m_numInputPoints ]; + + // Get/set each input point. + // We unfortunately have to special case each direct input code. + for( int i = 0; i < m_numInputPoints; i++ ) + { + m_InputToDICode[ i ] = Input::INVALID_CONTROLLERID; + + const char *type = m_radController->GetInputPointByIndex( i )->GetType(); + + if( strcmp( type, "XAxis" ) == 0 ) + { + m_InputToDICode[ i ] = DIJOFS_X; + } + else if( strcmp( type, "YAxis" ) == 0 ) + { + m_InputToDICode[ i ] = DIJOFS_Y; + } + else if( strcmp( type, "ZAxis" ) == 0 ) + { + m_InputToDICode[ i ] = DIJOFS_Z; + } + else if( strcmp( type, "RxAxis" ) == 0 ) + { + m_InputToDICode[ i ] = DIJOFS_RX; + } + else if( strcmp( type, "RyAxis" ) == 0 ) + { + m_InputToDICode[ i ] = DIJOFS_RY; + } + else if( strcmp( type, "RzAxis" ) == 0 ) + { + m_InputToDICode[ i ] = DIJOFS_RZ; + } + else if( strcmp( type, "Slider" ) == 0 ) + { + // figure out which slider it is. + for( int j = 0; j < 3; j++ ) + { + if( m_radController->GetInputPointByTypeAndIndex( "Slider", j ) == + m_radController->GetInputPointByIndex( i ) ) + { + m_InputToDICode[ i ] = DIJOFS_SLIDER(j); + break; + } + } + } + else if( strcmp( type, "POV" ) == 0 ) + { + // figure out which pov it is. + for( int j = 0; j < 3; j++ ) + { + if( m_radController->GetInputPointByTypeAndIndex( "POV", j ) == + m_radController->GetInputPointByIndex( i ) ) + { + m_InputToDICode[ i ] = DIJOFS_POV(j); + break; + } + } + } + else if( strcmp( type, "Button" ) == 0 ) + { + // figure out which button it is + for( int j = 0; j < 32; j++ ) + { + if( m_radController->GetInputPointByTypeAndIndex( "Button", j ) == + m_radController->GetInputPointByIndex( i ) ) + { + m_InputToDICode[ i ] = DIJOFS_BUTTON(j); + break; + } + } + } + } + } +} + +//============================================================================== +// Gamepad::GetButtonEnum +//============================================================================== +// +// Description: Returns the gamepad button enum for the given input, or +// NUM_GAMEPAD_BUTTONS if it's not a valid gamepad input. +// +// Parameters: n/a +// +// Return: n/a +// +//============================================================================== + +eGamepadButton Gamepad::GetButtonEnum( int dxKey ) const +{ + switch( dxKey ) + { + case DIJOFS_X: + { + return GAMEPAD_X; + } + case DIJOFS_Y: + { + return GAMEPAD_Y; + } + case DIJOFS_Z: + { + return GAMEPAD_Z; + } + case DIJOFS_RX: + { + return GAMEPAD_RX; + } + case DIJOFS_RY: + { + return GAMEPAD_RY; + } + case DIJOFS_RZ: + { + return GAMEPAD_RZ; + } + case DIJOFS_SLIDER(0): + { + return GAMEPAD_SLIDER0; + } + case DIJOFS_SLIDER(1): + { + return GAMEPAD_SLIDER1; + } + case DIJOFS_POV(0): + { + return GAMEPAD_POV0; + } + case DIJOFS_POV(1): + { + return GAMEPAD_POV1; + } + case DIJOFS_BUTTON0: + { + return GAMEPAD_BUTTON0; + } + case DIJOFS_BUTTON1: + { + return GAMEPAD_BUTTON1; + } + case DIJOFS_BUTTON2: + { + return GAMEPAD_BUTTON2; + } + case DIJOFS_BUTTON3: + { + return GAMEPAD_BUTTON3; + } + case DIJOFS_BUTTON4: + { + return GAMEPAD_BUTTON4; + } + case DIJOFS_BUTTON5: + { + return GAMEPAD_BUTTON5; + } + case DIJOFS_BUTTON6: + { + return GAMEPAD_BUTTON6; + } + case DIJOFS_BUTTON7: + { + return GAMEPAD_BUTTON7; + } + case DIJOFS_BUTTON8: + { + return GAMEPAD_BUTTON8; + } + case DIJOFS_BUTTON9: + { + return GAMEPAD_BUTTON9; + } + case DIJOFS_BUTTON10: + { + return GAMEPAD_BUTTON10; + } + case DIJOFS_BUTTON11: + { + return GAMEPAD_BUTTON11; + } + case DIJOFS_BUTTON12: + { + return GAMEPAD_BUTTON12; + } + case DIJOFS_BUTTON13: + { + return GAMEPAD_BUTTON13; + } + case DIJOFS_BUTTON14: + { + return GAMEPAD_BUTTON14; + } + case DIJOFS_BUTTON15: + { + return GAMEPAD_BUTTON15; + } + case DIJOFS_BUTTON16: + { + return GAMEPAD_BUTTON16; + } + case DIJOFS_BUTTON17: + { + return GAMEPAD_BUTTON17; + } + case DIJOFS_BUTTON18: + { + return GAMEPAD_BUTTON18; + } + case DIJOFS_BUTTON19: + { + return GAMEPAD_BUTTON19; + } + case DIJOFS_BUTTON20: + { + return GAMEPAD_BUTTON20; + } + case DIJOFS_BUTTON21: + { + return GAMEPAD_BUTTON21; + } + case DIJOFS_BUTTON22: + { + return GAMEPAD_BUTTON22; + } + case DIJOFS_BUTTON23: + { + return GAMEPAD_BUTTON23; + } + case DIJOFS_BUTTON24: + { + return GAMEPAD_BUTTON24; + } + case DIJOFS_BUTTON25: + { + return GAMEPAD_BUTTON25; + } + case DIJOFS_BUTTON26: + { + return GAMEPAD_BUTTON26; + } + case DIJOFS_BUTTON27: + { + return GAMEPAD_BUTTON27; + } + case DIJOFS_BUTTON28: + { + return GAMEPAD_BUTTON28; + } + case DIJOFS_BUTTON29: + { + return GAMEPAD_BUTTON29; + } + case DIJOFS_BUTTON30: + { + return GAMEPAD_BUTTON30; + } + case DIJOFS_BUTTON31: + { + return GAMEPAD_BUTTON31; + } + default: + { + return NUM_GAMEPAD_BUTTONS; + } + }; +}
\ No newline at end of file diff --git a/game/code/input/Gamepad.h b/game/code/input/Gamepad.h new file mode 100644 index 0000000..4e972de --- /dev/null +++ b/game/code/input/Gamepad.h @@ -0,0 +1,107 @@ +//********************************************************** +// C++ Class Name : Gamepad +// --------------------------------------------------------- +// Filetype: (HEADER) +// Filepath: D:/simpsonsrr2/game/code/input/Gamepad.h +// +// +// GDPro Properties +// --------------------------------------------------- +// - GD Symbol Type : CLD_Class +// - GD Method : UML ( 5.0 ) +// - GD System Name : Simpsons Controller System +// - GD Diagram Type : Class Diagram +// - GD Diagram Name : Input Device +// --------------------------------------------------- +// Author : nharan +// Creation Date : Tues - May 20, 2003 +// +// Change Log : +// +//********************************************************** +#ifndef GAMEPAD_H +#define GAMEPAD_H + +#include <input/RealController.h> + +// We need the eGamepadButtons enum to provide a sequential equivalent to DIJOFS_X... +// so that we can use them to access our arrays. +enum eGamepadButton +{ + GAMEPAD_X, + GAMEPAD_Y, + GAMEPAD_Z, + GAMEPAD_RX, + GAMEPAD_RY, + GAMEPAD_RZ, + GAMEPAD_SLIDER0, + GAMEPAD_SLIDER1, + GAMEPAD_POV0, + GAMEPAD_POV1, + GAMEPAD_BUTTON0, + GAMEPAD_BUTTON1, + GAMEPAD_BUTTON2, + GAMEPAD_BUTTON3, + GAMEPAD_BUTTON4, + GAMEPAD_BUTTON5, + GAMEPAD_BUTTON6, + GAMEPAD_BUTTON7, + GAMEPAD_BUTTON8, + GAMEPAD_BUTTON9, + GAMEPAD_BUTTON10, + GAMEPAD_BUTTON11, + GAMEPAD_BUTTON12, + GAMEPAD_BUTTON13, + GAMEPAD_BUTTON14, + GAMEPAD_BUTTON15, + GAMEPAD_BUTTON16, + GAMEPAD_BUTTON17, + GAMEPAD_BUTTON18, + GAMEPAD_BUTTON19, + GAMEPAD_BUTTON20, + GAMEPAD_BUTTON21, + GAMEPAD_BUTTON22, + GAMEPAD_BUTTON23, + GAMEPAD_BUTTON24, + GAMEPAD_BUTTON25, + GAMEPAD_BUTTON26, + GAMEPAD_BUTTON27, + GAMEPAD_BUTTON28, + GAMEPAD_BUTTON29, + GAMEPAD_BUTTON30, + GAMEPAD_BUTTON31, + NUM_GAMEPAD_BUTTONS +}; + +class Gamepad : public RealController +{ +public: + Gamepad () ; + virtual ~Gamepad(); + + virtual bool IsInputAxis( int dxKey ) const; + virtual bool IsPovHat( int dxKey ) const; + + // Returns true if this is a valid input for the controller. + virtual bool IsValidInput( int dxKey ) const; + + void CalculatePOV( float povVal, float* up, float* down, float* right, float* left ) const; + + // Sets up a mapping from a dxkey/direction to a virtual button + virtual bool SetMap( int dxKey, eDirectionType dir, int virtualButton ); + // Retrieves the virtual button of the given type mapped to a dxKey, direction + virtual int GetMap( int dxKey, eDirectionType dir, eMapType map ) const; + // Clears the specified mapping so it no longer exists. + virtual void ClearMap( int dxKey, eDirectionType dir, int virtualButton ); + // Clears all the cached mappings. + virtual void ClearMappedButtons(); + +private: + virtual void MapInputToDICode(); + + eGamepadButton GetButtonEnum( int dxKey ) const; + +private: + int m_ButtonMap[ NUM_MAPTYPES ][ NUM_GAMEPAD_BUTTONS ][ NUM_DIRTYPES ]; +}; +#endif diff --git a/game/code/input/Keyboard.cpp b/game/code/input/Keyboard.cpp new file mode 100644 index 0000000..f366e57 --- /dev/null +++ b/game/code/input/Keyboard.cpp @@ -0,0 +1,215 @@ +#include <input/Keyboard.h> + +#define DIRECTINPUT_VERSION 0x0800 +#include <dinput.h> + +//-------------------------------------------------------- +// Constructor/Destructor +//-------------------------------------------------------- + +Keyboard::Keyboard() +: RealController( KEYBOARD ) +{ + ClearMappedButtons(); +} + +Keyboard::~Keyboard() +{ +} + +//============================================================================== +// Keyboard::IsValidInput +//============================================================================== +// +// Description: Returns true if this is a valid input for the controller. +// +// Parameters: dxkey - the directinput index identifying the physical input. +// +// Return: true if key it's a valid input +// +//============================================================================== + +bool Keyboard::IsValidInput( int dxKey ) const +{ + return dxKey >= DIK_ESCAPE && dxKey <= DIK_MEDIASELECT; +} + +//============================================================================== +// Keyboard::IsBannedInput +//============================================================================== +// +// Description: Returns true if the key is banned for mapping. +// +// Parameters: dxkey - the directinput index identifying the physical input. +// +// Return: true if key is banned for mapping +// +//============================================================================== + +bool Keyboard::IsBannedInput( int dxKey ) const +{ + switch( dxKey ) + { + case DIK_LMENU: + case DIK_RMENU: + case DIK_LWIN: + case DIK_RWIN: + return true; + default: + return false; + } +} + +//============================================================================== +// Keyboard::SetMap +//============================================================================== +// +// Description: Sets up a mapping from a dxkey/direction to a virtual button +// +// Parameters: dxkey - the directinput index identifying the physical input. +// direction - for keyboard this must be DIR_UP +// virtualbutton - the virtual button that has been mapped +// +// Return: true if mapped successfully +// +//============================================================================== + +bool Keyboard::SetMap( int dxKey, eDirectionType dir, int virtualButton ) +{ + rAssert( dxKey >= 0 && dxKey < NUM_KEYBOARD_BUTTONS ); + rAssert( virtualButton >= 0 && virtualButton < Input::MaxPhysicalButtons ); + rAssert( dir == DIR_UP ); + + eMapType maptype = VirtualInputs::GetType( virtualButton ); + + if( dxKey >= 0 && dxKey < NUM_KEYBOARD_BUTTONS ) + { + m_ButtonMap[ maptype ][ dxKey ] = virtualButton; + return true; + } + else + { + return false; + } +} + +//============================================================================== +// Keyboard::ClearMap +//============================================================================== +// +// Description: Clears the specified mapping so it no longer exists. +// +// Parameters: dxkey - the directinput index identifying the physical input. +// direction - the direction of the input +// +// Return: n/a +// +//============================================================================== + +void Keyboard::ClearMap( int dxKey, eDirectionType dir, int virtualButton ) +{ + rAssert( dxKey >= 0 && dxKey < NUM_KEYBOARD_BUTTONS ); + rAssert( virtualButton >= 0 && virtualButton < Input::MaxPhysicalButtons ); + rAssert( dir == DIR_UP ); + + eMapType maptype = VirtualInputs::GetType( virtualButton ); + + if( dxKey >= 0 && dxKey < NUM_KEYBOARD_BUTTONS ) + { + m_ButtonMap[ maptype ][ dxKey ] = Input::INVALID_CONTROLLERID; + } +} + +//============================================================================== +// Keyboard::GetMap +//============================================================================== +// +// Description: Retrieves the virtual button of the given type mapped to +// a dxKey, direction +// +// Parameters: dxkey - the directinput index identifying the physical input. +// direction - for keyboard only DIR_UP is used. +// maptype - the type of virtual button to look up +// +// Return: n/a +// +//============================================================================== + +int Keyboard::GetMap( int dxKey, eDirectionType dir, eMapType map ) const +{ + rAssert( dxKey >= 0 && dxKey < NUM_KEYBOARD_BUTTONS ); + + if( dir == DIR_UP ) + { + return m_ButtonMap[ map ][ dxKey ]; + } + else + { + return Input::INVALID_CONTROLLERID; + } +} + +//============================================================================== +// Keyboard::ClearMappedButtons +//============================================================================== +// +// Description: Clears the cached button mappings +// +// Parameters: n/a +// +// Return: n/a +// +//============================================================================== + +void Keyboard::ClearMappedButtons() +{ + memset( &m_ButtonMap, Input::INVALID_CONTROLLERID, sizeof( m_ButtonMap ) ); +} + +//============================================================================== +// Keyboard::MapInputToDICode +//============================================================================== +// +// Description: Creates an input point -> direct input virtual key code mapping +// for the keyboard +// +// Parameters: n/a +// +// Return: n/a +// +//============================================================================== + +void Keyboard::MapInputToDICode() +{ + if( m_InputToDICode != NULL ) + { + delete [] m_InputToDICode; + m_InputToDICode = NULL; + } + + if( m_radController != NULL ) + { + // Get the number of input points + m_numInputPoints = m_radController->GetNumberOfInputPoints(); + + // Set up a cleared index -> di map. + m_InputToDICode = new int[ m_numInputPoints ]; + + for( int i = 0; i < m_numInputPoints; i++ ) + { + m_InputToDICode[ i ] = Input::INVALID_CONTROLLERID; + } + + // Reverse the di -> index map into what we want. + for( int di = DIK_ESCAPE; di <= NUM_KEYBOARD_BUTTONS; di++ ) + { + int inputpoint = VirtualKeyToIndex[ di ]; + + if( inputpoint >= 0 && + inputpoint < m_numInputPoints ) + { + m_InputToDICode[ inputpoint ] = di; + } + } + } +} diff --git a/game/code/input/Keyboard.h b/game/code/input/Keyboard.h new file mode 100644 index 0000000..0600dfb --- /dev/null +++ b/game/code/input/Keyboard.h @@ -0,0 +1,58 @@ +//********************************************************** +// C++ Class Name : Keyboard +// --------------------------------------------------------- +// Filetype: (HEADER) +// Filepath: D:/simpsonsrr2/game/code/input/Keyboard.h +// +// +// GDPro Properties +// --------------------------------------------------- +// - GD Symbol Type : CLD_Class +// - GD Method : UML ( 5.0 ) +// - GD System Name : Simpsons Controller System +// - GD Diagram Type : Class Diagram +// - GD Diagram Name : Input Device +// --------------------------------------------------- +// Author : nharan +// Creation Date : Tues - May 20, 2003 +// +// Change Log : +// +//********************************************************** +#ifndef KEYBOARD_H +#define KEYBOARD_H + +#include <input/RealController.h> + +const NUM_KEYBOARD_BUTTONS = 256; + +class Keyboard : public RealController +{ +public: + Keyboard(); + virtual ~Keyboard(); + + // Returns true if this is a valid input for the controller. + virtual bool IsValidInput( int dxKey ) const; + + // Returns true if the key is banned for mapping. + virtual bool IsBannedInput( int dxKey ) const; + + // Sets up a mapping from a dxkey/direction to a virtual button + virtual bool SetMap( int dxKey, eDirectionType dir, int virtualButton ); + // Retrieves the virtual button of the given type mapped to a dxKey, direction + virtual int GetMap( int dxKey, eDirectionType dir, eMapType map ) const; + // Clears the specified mapping so it no longer exists. + virtual void ClearMap( int dxKey, eDirectionType dir, int virtualButton ); + // Clears all the cached mappings. + virtual void ClearMappedButtons(); + +private: + // Sets up a input point index -> direct input keycode map. + virtual void MapInputToDICode(); + +private: + int m_ButtonMap[ NUM_MAPTYPES ][ NUM_KEYBOARD_BUTTONS ]; +}; + +#endif diff --git a/game/code/input/Mouse.cpp b/game/code/input/Mouse.cpp new file mode 100644 index 0000000..454f111 --- /dev/null +++ b/game/code/input/Mouse.cpp @@ -0,0 +1,399 @@ +#include <input/Mouse.h> + +#define DIRECTINPUT_VERSION 0x0800 +#include <dinput.h> + +/****************************************************************************** + Construction/Destruction + *****************************************************************************/ + +Mouse::Mouse() +: RealController(MOUSE), + m_fSensitivityX(10.0f), + m_fSensitivityY(10.0f) +{ + memset( &m_absPosition, 0, sizeof( m_absPosition ) ); + memset( &m_relPosition, 0, sizeof( m_relPosition ) ); + + ClearMappedButtons(); +} + +Mouse::~Mouse() +{ +} + +//============================================================================== +// Mouse::IsMouseAxis +//============================================================================== +// +// Description: Identifies any keys that are input axes. (can go in two directions) +// +// Parameters: dxkey - the directinput index identifying the physical input. +// +// Return: true if input is an axis +// +//============================================================================== + +bool Mouse::IsMouseAxis( int dxKey ) const +{ + switch( dxKey ) + { + case DIMOFS_X: + case DIMOFS_Y: + case DIMOFS_Z: + return true; + default: + return false; + } +} + +//============================================================================== +// Mouse::IsValidInput +//============================================================================== +// +// Description: Returns true if this is a valid input for the controller. +// +// Parameters: dxkey - the directinput index identifying the physical input. +// +// Return: true if key it's a valid input +// +//============================================================================== + +bool Mouse::IsValidInput( int dxKey ) const +{ + return GetButtonEnum( dxKey ) != NUM_MOUSE_BUTTONS; +} + +//============================================================================== +// Mouse::CalculateMouseAxis +//============================================================================== +// +// Description: Calculates a direct input axis value for a mouse axis based on +// its current mouse value. Mouse values can cover -1000..1000, +// and this gets mapped to an axis value of -1..1. +// +// Parameters: mouseAxis - the axis that's changed. +// value - the value of the mouse axis +// +// Return: input point value of -1..1 +// +//============================================================================== + +float Mouse::CalculateMouseAxis( int mouseAxis, float value ) +{ + const float MAX_THRESH = 1.0f; + const float MIN_THRESH = -1.0f; + + if( value == 0.0f ) + { + return 0.0f; + } + + switch( mouseAxis ) + { + case DIMOFS_X: + { + //take the delta + m_relPosition.x = (value - m_absPosition.x) / m_fSensitivityX; + + //re-center the cursor pos. + m_absPosition.x = value; + + if( m_relPosition.x > MAX_THRESH ) m_relPosition.x = MAX_THRESH; + else if( m_relPosition.x < MIN_THRESH ) m_relPosition.x = MIN_THRESH; + + return m_relPosition.x; + } + break; + case DIMOFS_Y: + case DIMOFS_Z: + { + //take the delta + m_relPosition.y = (value - m_absPosition.y) / m_fSensitivityY; + + //re-center the cursor pos. + m_absPosition.y = value; + + if( m_relPosition.y > MAX_THRESH ) m_relPosition.y = MAX_THRESH; + else if( m_relPosition.y < MIN_THRESH ) m_relPosition.y = MIN_THRESH; + + return -m_relPosition.y; + } + break; + default: + break; + } + return 0.0f; +} + +//============================================================================== +// Mouse::SetMap +//============================================================================== +// +// Description: Sets up a mapping from a dxkey/direction to a virtual button +// +// Parameters: dxkey - the directinput index identifying the physical input. +// direction - the direction of the input +// virtualbutton - the virtual button that has been mapped +// +// Return: true if button was mapped successfully +// +//============================================================================== + +bool Mouse::SetMap( int dxKey, eDirectionType dir, int virtualButton ) +{ + rAssert( virtualButton >= 0 && virtualButton < Input::MaxPhysicalButtons ); + + eMouseButton mbutton = GetButtonEnum( dxKey ); + eMapType maptype = VirtualInputs::GetType( virtualButton ); + + if( mbutton != NUM_MOUSE_BUTTONS ) + { + m_ButtonMap[ maptype ][ mbutton ][ dir ] = virtualButton; + } + + return mbutton != NUM_MOUSE_BUTTONS; +} + +//============================================================================== +// Mouse::ClearMap +//============================================================================== +// +// Description: Clears the specified mapping so it no longer exists. +// +// Parameters: dxkey - the directinput index identifying the physical input. +// direction - the direction of the input +// +// Return: n/a +// +//============================================================================== + +void Mouse::ClearMap( int dxKey, eDirectionType dir, int virtualButton ) +{ + eMouseButton mbutton = GetButtonEnum( dxKey ); + eMapType maptype = VirtualInputs::GetType( virtualButton ); + + if( mbutton != NUM_MOUSE_BUTTONS ) + { + m_ButtonMap[ maptype ][ mbutton ][ dir ] = Input::INVALID_CONTROLLERID; + } +} + +//============================================================================== +// Mouse::GetMap +//============================================================================== +// +// Description: Retrieves the virtual button of the given type mapped to +// a dxKey, direction +// +// Parameters: dxkey - the directinput index identifying the physical input. +// direction - the direction of the input. +// maptype - the type of virtual button to look up +// +// Return: n/a +// +//============================================================================== + +int Mouse::GetMap( int dxKey, eDirectionType dir, eMapType map ) const +{ + eMouseButton mbutton = GetButtonEnum( dxKey ); + + if( mbutton != NUM_MOUSE_BUTTONS ) + { + return m_ButtonMap[ map ][ mbutton ][ dir ]; + } + else + { + return Input::INVALID_CONTROLLERID; + } +} + +//============================================================================== +// Mouse::ClearMappedButtons +//============================================================================== +// +// Description: Clears the cached button mappings +// +// Parameters: n/a +// +// Return: n/a +// +//============================================================================== + +void Mouse::ClearMappedButtons() +{ + memset( &m_ButtonMap, Input::INVALID_CONTROLLERID, sizeof( m_ButtonMap ) ); +} + +//============================================================================== +// Mouse::MapInputToDICode +//============================================================================== +// +// Description: Creates an input point -> direct input virtual key code mapping +// for the mouse +// +// Parameters: n/a +// +// Return: n/a +// +//============================================================================== + +void Mouse::MapInputToDICode() +{ + if( m_InputToDICode != NULL ) + { + delete [] m_InputToDICode; + m_InputToDICode = NULL; + } + + if( m_radController != NULL ) + { + // Get the number of input points + m_numInputPoints = m_radController->GetNumberOfInputPoints(); + + // Set up a cleared index -> di map. + m_InputToDICode = new int[ m_numInputPoints ]; + + // Get/set each input point. + // We unfortunately have to special case each direct input code. + for( int i = 0; i < m_numInputPoints; i++ ) + { + m_InputToDICode[ i ] = Input::INVALID_CONTROLLERID; + + const char *type = m_radController->GetInputPointByIndex( i )->GetType(); + const char *name = m_radController->GetInputPointByIndex( i )->GetName(); + + if( strcmp( type, "RelXAxis" ) == 0 ) + { + m_InputToDICode[ i ] = DIMOFS_X; + } + else if( strcmp( type, "RelYAxis" ) == 0 ) + { + m_InputToDICode[ i ] = DIMOFS_Y; + } + else if( strcmp( type, "RelZAxis" ) == 0 ) + { + m_InputToDICode[ i ] = DIMOFS_Z; + } + else if( strcmp( type, "Button" ) == 0 ) + { + int button; + + if( sscanf( name, "Button %d", &button ) == 1 ) + { + switch( button ) + { + case 0: + { + m_InputToDICode[ i ] = DIMOFS_BUTTON0; + break; + } + case 1: + { + m_InputToDICode[ i ] = DIMOFS_BUTTON1; + break; + } + case 2: + { + m_InputToDICode[ i ] = DIMOFS_BUTTON2; + break; + } + case 3: + { + m_InputToDICode[ i ] = DIMOFS_BUTTON3; + break; + } + case 4: + { + m_InputToDICode[ i ] = DIMOFS_BUTTON4; + break; + } + case 5: + { + m_InputToDICode[ i ] = DIMOFS_BUTTON5; + break; + } + case 6: + { + m_InputToDICode[ i ] = DIMOFS_BUTTON6; + break; + } + case 7: + { + m_InputToDICode[ i ] = DIMOFS_BUTTON7; + break; + } + } + } + } + } + } +} + +//============================================================================== +// Mouse::GetButtonEnum +//============================================================================== +// +// Description: Returns the mouse button enum for the given input, or +// NUM_MOUSE_BUTTONS if it's not a valid mouse input. +// +// Parameters: n/a +// +// Return: n/a +// +//============================================================================== + +eMouseButton Mouse::GetButtonEnum( int dxKey ) const +{ + switch( dxKey ) + { + case DIMOFS_X: + { + return MOUSE_X; + } + case DIMOFS_Y: + { + return MOUSE_Y; + } + case DIMOFS_Z: + { + return MOUSE_Z; + } + case DIMOFS_BUTTON0: + { + return MOUSE_BUTTON0; + } + case DIMOFS_BUTTON1: + { + return MOUSE_BUTTON1; + } + case DIMOFS_BUTTON2: + { + return MOUSE_BUTTON2; + } + case DIMOFS_BUTTON3: + { + return MOUSE_BUTTON3; + } + case DIMOFS_BUTTON4: + { + return MOUSE_BUTTON4; + } + case DIMOFS_BUTTON5: + { + return MOUSE_BUTTON5; + } + case DIMOFS_BUTTON6: + { + return MOUSE_BUTTON6; + } + case DIMOFS_BUTTON7: + { + return MOUSE_BUTTON7; + } + default: + { + return NUM_MOUSE_BUTTONS; + } + } +} diff --git a/game/code/input/Mouse.h b/game/code/input/Mouse.h new file mode 100644 index 0000000..7f33402 --- /dev/null +++ b/game/code/input/Mouse.h @@ -0,0 +1,80 @@ +/****************************************************************************** + File: Mouse.h + Desc: Interface for the Mouse class. + - Responsible for managing relative axis info + for the mouse and other mouse related stuff. + + Date: May 16, 2003 + History: + *****************************************************************************/ +#ifndef MOUSE_H +#define MOUSE_H + +#include <input/RealController.h> + +struct MouseCoord +{ + float x, y; +}; + +// We need the eMouseButtons enum to provide a sequential equivalent to DIMOFS_X... +// so that we can use them to access our arrays. +enum eMouseButton +{ + MOUSE_X, + MOUSE_Y, + MOUSE_Z, + MOUSE_BUTTON0, + MOUSE_BUTTON1, + MOUSE_BUTTON2, + MOUSE_BUTTON3, + MOUSE_BUTTON4, + MOUSE_BUTTON5, + MOUSE_BUTTON6, + MOUSE_BUTTON7, + NUM_MOUSE_BUTTONS +}; + +class Mouse : public RealController +{ +public: + Mouse(); + virtual ~Mouse(); + + float XPos() const { return m_relPosition.x; } + float YPos() const { return m_relPosition.y; } + void setSensitivityX( float fSensitivityX ) { m_fSensitivityX = fSensitivityX; } + void setSensitivityY( float fSensitivityY ) { m_fSensitivityY = fSensitivityY; } + float getSensitivityX() const { return m_fSensitivityX; } + float getSensitivityY() const { return m_fSensitivityY; } + + virtual bool IsMouseAxis( int dxKey ) const; + + // Returns true if this is a valid input for the controller. + virtual bool IsValidInput( int dxKey ) const; + + float CalculateMouseAxis( int mouseAxis, float value ); + + // Sets up a mapping from a dxkey/direction to a virtual button + virtual bool SetMap( int dxKey, eDirectionType dir, int virtualButton ); + // Retrieves the virtual button of the given type mapped to a dxKey, direction + virtual int GetMap( int dxKey, eDirectionType dir, eMapType map ) const; + // Clears the specified mapping so it no longer exists. + virtual void ClearMap( int dxKey, eDirectionType dir, int virtualButton ); + // Clears all the cached mappings. + virtual void ClearMappedButtons(); + + +private: + virtual void MapInputToDICode(); + + eMouseButton GetButtonEnum( int dxKey ) const; + +private: + MouseCoord m_relPosition; + MouseCoord m_absPosition; + float m_fSensitivityX; + float m_fSensitivityY; + int m_ButtonMap[ NUM_MAPTYPES ][ NUM_MOUSE_BUTTONS ][ NUM_DIRTYPES ]; +}; +#endif diff --git a/game/code/input/MouseCursor.cpp b/game/code/input/MouseCursor.cpp new file mode 100644 index 0000000..bcedf16 --- /dev/null +++ b/game/code/input/MouseCursor.cpp @@ -0,0 +1,149 @@ +#include <input/MouseCursor.h> + +// THIS CURSOR STUFF IS JUST FOR TESTING!. +static void StreamLine(pddiPrimStream* pstream, rmt::Vector a, rmt::Vector b, tColour colora, tColour colorb) +{ + pddiVector pa; + pddiVector pb; + + pa.x = a.x; + pa.y = a.y; + pa.z = a.z; + + pb.x = b.x; + pb.y = b.y; + pb.z = b.z; + + pstream->Vertex(&pa, colora); + pstream->Vertex(&pb, colorb); +} +static void StreamLine(pddiPrimStream* pstream, rmt::Vector a, rmt::Vector b, tColour color) +{ + StreamLine(pstream, a, b, color, color); +} + +static pddiShader* simpleShader = NULL; + +static void DrawSquare(rmt::Vector v1, rmt::Vector v2, rmt::Vector v3, rmt::Vector v4, + tColour color = tColour(255, 255, 255), + pddiPrimType primType = PDDI_PRIM_LINES) +{ + if(simpleShader == NULL) + { + simpleShader = p3d::device->NewShader("simple"); + simpleShader->AddRef(); + simpleShader->SetInt(PDDI_SP_BLENDMODE, PDDI_BLEND_ALPHA); + } + + pddiPrimStream* pStream; + pStream = p3d::pddi->BeginPrims(simpleShader, primType, PDDI_V_C, 8); + if(pStream) + { + StreamLine(pStream, v1, v2, color); + StreamLine(pStream, v2, v4, color); + StreamLine(pStream, v4, v3, color); + StreamLine(pStream, v3, v1, color); + } + p3d::pddi->EndPrims(pStream); +} + +/* +* DrawSquare: +* the square is defined as: +* +* v1 ---------+ +* | | +* | | +* | | +* | | +* +--------- v2 +* +*/ +static void DrawSquare(rmt::Vector v1, rmt::Vector v2, + tColour color = tColour(255, 255, 255), + pddiPrimType primType = PDDI_PRIM_LINES) +{ + DrawSquare( + rmt::Vector(v1.x, v1.y, 0), + rmt::Vector(v2.x, v1.y, 0), + rmt::Vector(v1.x, v2.y, 0), + rmt::Vector(v2.x, v2.y, 0), + color, primType); +} + +/****************************************************************************** + Some global constants/defines for this file. + *****************************************************************************/ + + +/****************************************************************************** + Initialization of static member variables. + *****************************************************************************/ + +/****************************************************************************** + Construction/Destruction + *****************************************************************************/ + +MouseCursor::MouseCursor() +: m_bVisible(false), + m_position(), + m_pCursorIcon(NULL), + m_width(10), + m_height(10) +{ +} + +MouseCursor::~MouseCursor() +{ + tRefCounted::Release( m_pCursorIcon ); +} + +void MouseCursor::Set( tDrawable* pCursorIcon ) +{ + if( !m_pCursorIcon ) + tRefCounted::Assign(m_pCursorIcon, pCursorIcon); +} + +void MouseCursor::Render() +{ + if( !m_bVisible ) return; + + rmt::Vector v1(-0.1f, -0.1f, 0.0f); + rmt::Vector v2(-0.1f, 0.1f, 0.0f); + rmt::Vector v3(0.1f, 0.1f, 0.0f); + rmt::Vector v4(0.1f, -0.1f, 0.0f); + + pddiProjectionMode pMode = p3d::pddi->GetProjectionMode(); + p3d::pddi->SetProjectionMode(PDDI_PROJECTION_ORTHOGRAPHIC); + + p3d::stack->Push(); + p3d::stack->LoadIdentity(); + + // Offsets are hardcoded right now for the type of cursor that it is. + static float XOFFSET = 0.020f; + static float YOFFSET = 0.035f; + p3d::stack->Translate( m_position.x-XOFFSET, m_position.y-YOFFSET, m_position.z ); + + if (m_pCursorIcon) + { + static float scaleFactor = 0.5f; + p3d::stack->Scale(scaleFactor, scaleFactor, 1.0f); + //p3d::stack->Scale(0.0007f, 0.0007f, 0.0007f); + m_pCursorIcon->Display(); + } + else + { + float scale = 0.2f; + p3d::stack->Scale(scale, scale, scale); + pddiColour c = pddiColour(255, 0, 0); // 0-255 + //This should be replaced with a DrawCursor function. + DrawSquare(v2, v3, v1, v4, c); + } + + p3d::pddi->Clear(PDDI_BUFFER_DEPTH | PDDI_BUFFER_STENCIL); + + p3d::stack->Pop(); + + //Restore things we've messed with + p3d::pddi->SetProjectionMode(pMode); +}
\ No newline at end of file diff --git a/game/code/input/MouseCursor.h b/game/code/input/MouseCursor.h new file mode 100644 index 0000000..43e2119 --- /dev/null +++ b/game/code/input/MouseCursor.h @@ -0,0 +1,57 @@ +/****************************************************************************** + File: MouseCursor.h + Desc: Interface for the Mouse cursor. + - Responsible for drawing the 3D/2D cursor. + + Date: May 16, 2003 + History: + *****************************************************************************/ +#ifndef MOUSECURSOR_H +#define MOUSECURSOR_H + +class MouseCursor +{ +public: + MouseCursor(); + ~MouseCursor(); + + void SetPos( float x, float y, float z = 10.0f ) + { + m_position.x = x; + m_position.y = y; + m_position.z = z; + } + + void SetVisible( bool bVisible ) + { + m_bVisible = bVisible; + } + + void SetSize( int width, int height ) + { + m_width = width; + m_height = height; + } + + float XPos() const { return m_position.x; } + float YPos() const { return m_position.y; } + float ZPos() const { return m_position.z; } + + bool IsVisible() const { return m_bVisible; } + + int Width() const { return m_width; } + int Height() const { return m_height; } + + void Set( tDrawable* pCursorIcon ); + void Render(); + +private: + tDrawable* m_pCursorIcon; + rmt::Vector m_position; + bool m_bVisible; + int m_width; + int m_height; +}; + + +#endif diff --git a/game/code/input/RealController.cpp b/game/code/input/RealController.cpp new file mode 100644 index 0000000..e7bf1e4 --- /dev/null +++ b/game/code/input/RealController.cpp @@ -0,0 +1,210 @@ +/****************************************************************************** + File: RealController.cpp + Desc: Defines the RealController class. + Author: Neil Haran + Date: May 16, 2003 + History: + *****************************************************************************/ +#include <input/RealController.h> +#include <input/usercontrollerWin32.h> +#include <input/inputmanager.h> + +/****************************************************************************** + Construction/Destruction + *****************************************************************************/ +RealController::RealController( eControllerType type ) +: m_radController(NULL), + m_eControllerType(type), + m_bConnected(false), + m_InputToDICode(NULL), + m_numInputPoints(0) +{ +} + +RealController::~RealController() +{ + if( m_InputToDICode != NULL ) + { + delete [] m_InputToDICode; + } +} + +//-------------------------------------------------------- +// Init +//-------------------------------------------------------- +void RealController::Init( IRadController* pRadController ) +{ +// rAssert(!m_radController); + if( !m_radController ) + { + m_radController = pRadController; + + MapInputToDICode(); + } +} + +void RealController::Release() +{ + if( m_radController ) + m_radController = NULL; +} + +//============================================================================== +// RealController::IsInputAxis +//============================================================================== +// +// Description: Identifies any keys that are input axes. (can go in two directions) +// +// Parameters: dxkey - the directinput index identifying the physical input. +// +// Return: true if input is an axis +// +//============================================================================== + +bool RealController::IsInputAxis( int dxKey ) const +{ + return false; +} + +//============================================================================== +// RealController::IsMouseAxis +//============================================================================== +// +// Description: Identifies any keys that are mouse axes. (special to mouse) +// +// Parameters: dxkey - the directinput index identifying the physical input. +// +// Return: true if input is a mouse axis +// +//============================================================================== + +bool RealController::IsMouseAxis( int dxKey ) const +{ + return false; +} + +//============================================================================== +// RealController::IsPovHat +//============================================================================== +// +// Description: Identifies any keys that are pov hats (go in 4 directions) +// +// Parameters: dxkey - the directinput index identifying the physical input. +// +// Return: true if input is a pov hat +// +//============================================================================== + +bool RealController::IsPovHat( int dxKey ) const +{ + return false; +} + +//============================================================================== +// RealController::IsBannedInput +//============================================================================== +// +// Description: Returns true if the key is banned for mapping. +// +// Parameters: dxkey - the directinput index identifying the physical input. +// +// Return: true if key is banned for mapping +// +//============================================================================== + +bool RealController::IsBannedInput( int dxKey ) const +{ + return false; +} + +//============================================================================== +// RealController::GetInputName +//============================================================================== +// +// Description: Returns the name of the input +// +// Parameters: dxkey - the directinput index identifying the physical input. +// +// Return: name +// +//============================================================================== + +const char* RealController::GetInputName( int dxKey ) const +{ + if( IsValidInput( dxKey ) ) + { + for( int i = 0; i < m_numInputPoints; i++ ) + { + if( GetDICode( i ) == dxKey ) + { + IRadControllerInputPoint* pInputPoint = m_radController->GetInputPointByIndex( i ); + rAssert( pInputPoint != NULL ); + + return pInputPoint->GetName(); + } + } + } + + rAssert( false ); + return NULL; +} + +void RealController::AddInputPoints( IRadControllerInputPoint* pInputPoint ) +{ + rAssert(pInputPoint); + + // Check if the input point is already in the list. + for( INPUTPOINTITER iter = m_inputPointList.begin(); iter != m_inputPointList.end(); iter++ ) + { + if( *iter == pInputPoint ) + { + return; + } + } + + // Add the point. + m_inputPointList.push_back( pInputPoint ); +} + +void RealController::ReleaseInputPoints( UserController* parent ) +{ + INPUTPOINTITER iter; + + for( iter = m_inputPointList.begin(); iter != m_inputPointList.end(); iter++ ) + { + IRadControllerInputPoint* pInputPoint = *iter; + if( pInputPoint ) + { + pInputPoint->UnRegisterControllerInputPointCallback( static_cast< IRadControllerInputPointCallback* >( parent ) ); + } + } + // after unregistering, we don't need this point anymore. + m_inputPointList.clear(); +} + +//============================================================================== +// RealController::GetDICode +//============================================================================== +// +// Description: Returns the direct input keycode associated with an input point, +// or Input::INVALID_CONTROLLERID if there is no controller or input code. +// +// Parameters: n/a +// +// Return: n/a +// +//============================================================================== + +int RealController::GetDICode( int inputpoint ) const +{ + rAssert( inputpoint >= 0 && inputpoint < m_numInputPoints ); + + if( m_InputToDICode != NULL && inputpoint >= 0 && inputpoint < m_numInputPoints ) + { + return m_InputToDICode[ inputpoint ]; + } + else + { + return Input::INVALID_CONTROLLERID; + } +} diff --git a/game/code/input/RealController.h b/game/code/input/RealController.h new file mode 100644 index 0000000..2377069 --- /dev/null +++ b/game/code/input/RealController.h @@ -0,0 +1,131 @@ +/****************************************************************************** + File: RealController.h + Desc: Interface for the RealController class. + - RealController essentially is a physical controller class. + - a wrapper around IRadController. + + Date: May 16, 2003 + History: + *****************************************************************************/ + +#ifndef REALCONTROLLER_H +#define REALCONTROLLER_H + +//======================================== +// System Includes +//======================================== +#include <radcontroller.hpp> +#include <list> +using namespace std; + +//======================================== +// Nested Includes +//======================================== + +#include <input/controller.h> +#include <input/mapper.h> +#include <input/virtualinputs.hpp> + +class UserController; +/***************************************** + Some typedefs for convienince + ****************************************/ +typedef ref< IRadController > RADCONTROLLER; +typedef list< IRadControllerInputPoint* > RADINPUTPOINTLIST; +typedef list< IRadControllerInputPoint* >::iterator INPUTPOINTITER; + +//============================================================================= +// Enumerations +//============================================================================= + +// Types of real controllers. +enum eControllerType +{ + GAMEPAD = 0, // gamepad/joystick + KEYBOARD, + MOUSE, + STEERINGWHEEL, + NUM_CONTROLLERTYPES +}; + +// Directions which inputs can process. +enum eDirectionType +{ + DIR_UP = 0, + DIR_DOWN, + DIR_RIGHT, + DIR_LEFT, + NUM_DIRTYPES +}; + +//============================================================================= +// Class: RealController +//============================================================================= +// +// Description: The base class for every device plugged in to receive input +// from the user. There is one instance for each keyboard, mouse, +// gamepad... +// +//============================================================================= + +class RealController +{ +public: + RealController( eControllerType type ); + virtual ~RealController(); + + RADCONTROLLER getController() const { return m_radController; } + bool IsConnected() const { return m_bConnected; } + void Connect() { m_bConnected = true; } + void Disconnect() { m_bConnected = false; } + eControllerType ControllerType() const { return m_eControllerType; } + + void Init( IRadController* pController ); + void Release(); + + // Return true if the dxKey is one of the following types of inputs. + virtual bool IsInputAxis( int dxKey ) const; + virtual bool IsMouseAxis( int dxKey ) const; + virtual bool IsPovHat( int dxKey ) const; + + // Returns true if this is a valid input for the controller. + virtual bool IsValidInput( int dxKey ) const = 0; + + // Returns true if the key is banned for mapping. + virtual bool IsBannedInput( int dxKey ) const; + + // Sets up a mapping from a dxkey/direction to a virtual button + virtual bool SetMap( int dxKey, eDirectionType dir, int virtualButton ) = 0; + // Retrieves the virtual button of the given type mapped to a dxKey, direction + virtual int GetMap( int dxKey, eDirectionType dir, eMapType map ) const = 0; + // Clears the specified mapping so it no longer exists. + virtual void ClearMap( int dxKey, eDirectionType dir, int virtualButton ) = 0; + // Clears all the cached mappings. + virtual void ClearMappedButtons() = 0; + + // Returns the name of the input. + const char* GetInputName( int dxKey ) const; + + // Store & release registered input points. + void AddInputPoints( IRadControllerInputPoint* pInputPoint ); + void ReleaseInputPoints( UserController* parent ); + + // Returns the direct input code representing a given input point for + // the controller, or Input::INVALID_CONTROLLERID if the i.p. doesn't exist. + int GetDICode( int inputpoint ) const; + +protected: + // Sets up an input point index -> direct input keycode map for the + // controller in m_InputToDICode. Called automatically by Init(). + virtual void MapInputToDICode() = 0; + +protected: + RADCONTROLLER m_radController; + bool m_bConnected; + eControllerType m_eControllerType; + RADINPUTPOINTLIST m_inputPointList; + int* m_InputToDICode; + int m_numInputPoints; +}; + +#endif
\ No newline at end of file diff --git a/game/code/input/SteeringWheel.cpp b/game/code/input/SteeringWheel.cpp new file mode 100644 index 0000000..7504633 --- /dev/null +++ b/game/code/input/SteeringWheel.cpp @@ -0,0 +1,170 @@ +#include <input/SteeringWheel.h> + +#define DIRECTINPUT_VERSION 0x0800 +#include <dinput.h> + +//-------------------------------------------------------- +// Constructor/Destructor +//-------------------------------------------------------- + +SteeringWheel::SteeringWheel() +: RealController( STEERINGWHEEL ), + m_bPedalInverted(false), + m_InputToDICode( NULL ) +{ +} + +SteeringWheel::~SteeringWheel() +{ + if( m_InputToDICode != NULL ) + { + delete [] m_InputToDICode; + } +} + +//============================================================================== +// SteeringWheel::Init +//============================================================================== +// +// Description: Initializes the wheel and figures out what special type it is. +// +// Parameters: controller - the rad controller for the steering wheel +// +// Return: None. +// +//============================================================================== + +void SteeringWheel::Init( IRadController* pController ) +{ + // Clear the properties + m_bPedalInverted = false; + + if( pController != NULL ) + { + // Check for the wingman - a bad bad wheel. + m_bPedalInverted = (_stricmp( pController->GetType(), "Logitech WingMan Formula Force GP USB") == 0); + } + + // Connect + RealController::Init( pController ); +} + +//============================================================================== +// SteeringWheel::MapInputToDICode +//============================================================================== +// +// Description: Creates an input point -> direct input virtual key code mapping +// for the keyboard +// +// Parameters: n/a +// +// Return: n/a +// +//============================================================================== + +void SteeringWheel::MapInputToDICode() +{ + if( m_InputToDICode != NULL ) + { + delete [] m_InputToDICode; + m_InputToDICode = NULL; + } + + if( m_radController != NULL ) + { + // Get the number of input points + unsigned num = m_radController->GetNumberOfInputPoints(); + + // Set up a cleared index -> di map. + m_InputToDICode = new int[ num ]; + + for( unsigned i = 0; i < num; i++ ) + { + m_InputToDICode[ i ] = Input::INVALID_CONTROLLERID; + const char *type = m_radController->GetInputPointByIndex( i )->GetType(); + + if( strcmp( type, "XAxis" ) == 0 ) + { + m_InputToDICode[ i ] = DIJOFS_X; + } + else if( strcmp( type, "YAxis" ) == 0 ) + { + m_InputToDICode[ i ] = DIJOFS_Y; + } + else if( strcmp( type, "Slider" ) == 0 ) + { + // figure out which slider it is. + for( int j = 0; j < 3; j++ ) + { + if( m_radController->GetInputPointByTypeAndIndex( "Slider", j ) == + m_radController->GetInputPointByIndex( i ) ) + { + m_InputToDICode[ i ] = DIJOFS_SLIDER(j); + break; + } + } + } + else if( strcmp( type, "Button" ) == 0 ) + { + // figure out which button it is + for( int j = 0; j < 32; j++ ) + { + if( m_radController->GetInputPointByTypeAndIndex( "Button", j ) == + m_radController->GetInputPointByIndex( i ) ) + { + m_InputToDICode[ i ] = DIJOFS_BUTTON(j); + break; + } + } + } + // Now make the input code controller independent. + m_InputToDICode[ i ] = GetIndependentDICode( m_InputToDICode[ i ] ); + } + } +} + +//============================================================================== +// SteeringWheel::GetDICode +//============================================================================== +// +// Description: Returns the direct input keycode associated with an input point, +// or -1 if there is no controller or input code. +// +// Parameters: n/a +// +// Return: n/a +// +//============================================================================== + +int SteeringWheel::GetDICode( int inputpoint ) const +{ + return m_InputToDICode == NULL ? Input::INVALID_CONTROLLERID : m_InputToDICode[ inputpoint ]; +} + +//============================================================================== +// SteeringWheel::GetIndependentDICode +//============================================================================== +// +// Description: Same as gamepad +// +// Parameters: The direct input code for the specific controller. +// +// Return: The inpendent & real direct input code they should have assigned +// it. Often this is the same code. +// +//============================================================================== + +int SteeringWheel::GetIndependentDICode( int diCode ) const +{ + switch( diCode ) + { + case DIJOFS_SLIDER(0): + { + return m_bPedalInverted ? DIJOFS_Y : DIJOFS_SLIDER(0); + } + default: + { + return diCode; + } + } +}
\ No newline at end of file diff --git a/game/code/input/SteeringWheel.h b/game/code/input/SteeringWheel.h new file mode 100644 index 0000000..7742958 --- /dev/null +++ b/game/code/input/SteeringWheel.h @@ -0,0 +1,31 @@ +/****************************************************************************** + File: SteeringWheel.h + Desc: Interface for the SteeringWheel class. + + Date: May 16, 2003 + History: +*****************************************************************************/ +#ifndef STEERINGWHEEL_H +#define STEERINGWHEEL_H + +#include <input/RealController.h> + +class SteeringWheel : public RealController +{ +public: + SteeringWheel(); + virtual ~SteeringWheel(); + + virtual void Init( IRadController* pController ); + virtual int GetDICode( int inputpoint ) const; + bool IsPedalInverted() const { return m_bPedalInverted; } + +private: + virtual void MapInputToDICode(); + int GetIndependentDICode( int diCode ) const; + +private: + int* m_InputToDICode; + bool m_bPedalInverted; +}; +#endif diff --git a/game/code/input/allinput.cpp b/game/code/input/allinput.cpp new file mode 100644 index 0000000..5967c24 --- /dev/null +++ b/game/code/input/allinput.cpp @@ -0,0 +1,20 @@ +#include <input/button.cpp> +#include <input/inputmanager.cpp> +#include <input/mappable.cpp> +#include <input/mapper.cpp> +#include <input/usercontroller.cpp> +#include <input/rumbleeffect.cpp> + +#if defined(RAD_GAMECUBE) || defined(RAD_PS2) +#include <input/steeringspring.cpp> +#include <input/basedamper.cpp> +#include <input/forceeffect.cpp> +#include <input/constanteffect.cpp> +#include <input/wheelrumble.cpp> +#endif + +#ifdef RAD_PS2 +#include <input/rumbleps2.cpp> +#elif defined( RAD_GAMECUBE ) +#include <input/rumblegc.cpp> +#endif diff --git a/game/code/input/basedamper.cpp b/game/code/input/basedamper.cpp new file mode 100644 index 0000000..edafbb0 --- /dev/null +++ b/game/code/input/basedamper.cpp @@ -0,0 +1,185 @@ +//============================================================================= +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: BaseDamper.cpp +// +// Description: Implement BaseDamper +// +// History: 10/21/2002 + Created -- Cary Brisebois +// +//============================================================================= + +//======================================== +// System Includes +//======================================== +// Foundation Tech +#include <raddebug.hpp> + +//======================================== +// Project Includes +//======================================== +#include <input/BaseDamper.h> +#include <input/wheeldefines.h> + +//****************************************************************************** +// +// Global Data, Local Data, Local Classes +// +//****************************************************************************** + +//****************************************************************************** +// +// Public Member Functions +// +//****************************************************************************** + +//============================================================================== +// BaseDamper::BaseDamper +//============================================================================== +// Description: Constructor. +// +// Parameters: None. +// +// Return: N/A. +// +//============================================================================== +BaseDamper::BaseDamper() +{ + //Setup the respective force effect structures. +#ifdef RAD_WIN32 + m_conditon.lOffset = 0; + m_conditon.lDeadBand = 0; + m_conditon.lPositiveCoefficient = 127; + m_conditon.lNegativeCoefficient = 127; + m_conditon.dwPositiveSaturation = 127; + m_conditon.dwNegativeSaturation = 127; + + mForceEffect.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + mForceEffect.dwDuration = INFINITE; + mForceEffect.dwGain = DI_FFNOMINALMAX; + mForceEffect.dwTriggerButton = DIEB_NOTRIGGER; + mForceEffect.cAxes = 1; + mForceEffect.rgdwAxes = m_rgdwAxes; + mForceEffect.rglDirection = m_rglDirection; + mForceEffect.lpEnvelope = NULL; + mForceEffect.cbTypeSpecificParams = sizeof(DICONDITION); + mForceEffect.lpvTypeSpecificParams = &m_conditon; + mForceEffect.dwStartDelay = 0; +#else + mForceEffect.type = LG_TYPE_DAMPER; + mForceEffect.duration = LG_DURATION_INFINITE; + mForceEffect.startDelay = 0; + mForceEffect.p.condition[0].offset = 0; + mForceEffect.p.condition[0].deadband = 0; + mForceEffect.p.condition[0].saturationNeg = 127; + mForceEffect.p.condition[0].saturationPos = 127; + mForceEffect.p.condition[0].coefficientNeg = 127; + mForceEffect.p.condition[0].coefficientPos = 127; +#endif +} + +//============================================================================== +// BaseDamper::~BaseDamper +//============================================================================== +// Description: Destructor. +// +// Parameters: None. +// +// Return: N/A. +// +//============================================================================== +BaseDamper::~BaseDamper() +{ +} + +//============================================================================= +// BaseDamper::OnInit +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: void +// +//============================================================================= +void BaseDamper::OnInit() +{ +} + +//============================================================================= +// BaseDamper::SetCenterPoint +//============================================================================= +// Description: Comment +// +// Parameters: ( s8 point, u8 deadband ) +// +// Return: void +// +//============================================================================= +void BaseDamper::SetCenterPoint( s8 point, u8 deadband ) +{ +#ifdef RAD_WIN32 + m_conditon.lOffset = point; + m_conditon.lDeadBand = deadband; +#else + mForceEffect.p.condition[0].offset = point; + mForceEffect.p.condition[0].deadband = deadband; +#endif + + mEffectDirty = true; +} + +//============================================================================= +// BaseDamper::SetDamperStrength +//============================================================================= +// Description: Comment +// +// Parameters: ( u8 strength ) +// +// Return: void +// +//============================================================================= +#ifdef RAD_WIN32 +void BaseDamper::SetDamperStrength( u16 strength ) +#else +void BaseDamper::SetDamperStrength( u8 strength ) +#endif +{ +#ifdef RAD_WIN32 + m_conditon.dwPositiveSaturation = strength; + m_conditon.dwNegativeSaturation = strength; +#else + mForceEffect.p.condition[0].saturationNeg = strength; + mForceEffect.p.condition[0].saturationPos = strength; +#endif + mEffectDirty = true; +} + +//============================================================================= +// BaseDamper::SetDamperCoefficient +//============================================================================= +// Description: Comment +// +// Parameters: ( s16 coeff ) +// +// Return: void +// +//============================================================================= +void BaseDamper::SetDamperCoefficient( s16 coeff ) +{ +#ifdef RAD_WIN32 + m_conditon.lPositiveCoefficient = coeff; + m_conditon.lNegativeCoefficient = coeff; +#else + mForceEffect.p.condition[0].coefficientNeg = coeff; + mForceEffect.p.condition[0].coefficientPos = coeff; +#endif + + mEffectDirty = true; +} + +//****************************************************************************** +// +// Private Member Functions +// +//****************************************************************************** diff --git a/game/code/input/basedamper.h b/game/code/input/basedamper.h new file mode 100644 index 0000000..66b0dec --- /dev/null +++ b/game/code/input/basedamper.h @@ -0,0 +1,59 @@ +//============================================================================= +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: basedamper.h +// +// Description: Blahblahblah +// +// History: 10/19/2002 + Created -- Cary Brisebois +// +//============================================================================= + +#ifndef BASEDAMPER_H +#define BASEDAMPER_H + +//======================================== +// Nested Includes +//======================================== +#include <radcontroller.hpp> + +#include <input/forceeffect.h> + +//======================================== +// Forward References +//======================================== + +//============================================================================= +// +// Synopsis: Blahblahblah +// +//============================================================================= + +class BaseDamper : public ForceEffect +{ +public: + BaseDamper(); + virtual ~BaseDamper(); + + void OnInit(); + + void SetCenterPoint( s8 degrees, u8 deadband ); //Where 0 is straight up. +#ifdef RAD_WIN32 + void SetDamperStrength( u16 strength ); +#else + void SetDamperStrength( u8 strength ); +#endif + void SetDamperCoefficient( s16 coeff ); +private: + +#ifdef RAD_WIN32 + DICONDITION m_conditon; +#endif + + //Prevent wasteful constructor creation. + BaseDamper( const BaseDamper& basedamper ); + BaseDamper& operator=( const BaseDamper& basedamper ); +}; + + +#endif //BASEDAMPER_H diff --git a/game/code/input/button.cpp b/game/code/input/button.cpp new file mode 100644 index 0000000..7e530a6 --- /dev/null +++ b/game/code/input/button.cpp @@ -0,0 +1,14 @@ +#include <input/button.h> + +unsigned int Button::mTickCount = 0; + +Button::Button( void ) : + mfValue( 0.0f ), + mTickCountAtChange( 0 ) +{ +} + +Button::~Button( void ) +{ +} + diff --git a/game/code/input/button.h b/game/code/input/button.h new file mode 100644 index 0000000..7c76288 --- /dev/null +++ b/game/code/input/button.h @@ -0,0 +1,71 @@ +#ifndef BUTTON_H_ +#define BUTTON_H_ + +// An input point, either physical (if storeig in a UserController), or logical (if stored in a Mappable +// (even joysticks are treated as "buttons" by the game) +class Button +{ +public: + Button( void ); + ~Button( void ); + + // test the properties of the button + inline float GetValue( void ) const; + inline void SetValue( float fValue ); + inline bool IsDown( void ) const; + inline bool IsUp( void ) const; + + // returns number of input ticks since the value of this button changed + inline unsigned int TimeSinceChange( void ) const; + + // force the change flag to be set without resetting the value + inline void ForceChange(void); + + inline static void Tick(int timeinms) { mTickCount += timeinms; } + +protected: + float mfValue; + unsigned int mTickCountAtChange; + + // counter for current number of input ticks (for tracking + static unsigned int mTickCount; +}; + +// Inline member functions +float Button::GetValue( void ) const +{ + return mfValue; +} + +void Button::ForceChange(void) +{ + mTickCountAtChange = mTickCount; +} + +void Button::SetValue( float fValue ) +{ + mTickCountAtChange = mTickCount; + mfValue = fValue; +} + +bool Button::IsDown( void ) const +{ + return mfValue != 0.0f; +} + +bool Button::IsUp( void ) const +{ + return mfValue == 0.0f; +} + +unsigned int Button::TimeSinceChange( void ) const +{ + return mTickCount - mTickCountAtChange; +} + +// nbrooke 15/10/02 :I devirtualized the Button class (there was a lot of hierarchy +// and virtual functions considering there was only one class avtually used my any other code) +// but didn't feel like changing a bunch of stuff that was using IButton, thus the typedef +typedef Button IButton; + +#endif
\ No newline at end of file diff --git a/game/code/input/constanteffect.cpp b/game/code/input/constanteffect.cpp new file mode 100644 index 0000000..c0797a6 --- /dev/null +++ b/game/code/input/constanteffect.cpp @@ -0,0 +1,163 @@ +//============================================================================= +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: constanteffect.cpp +// +// Description: Implement ConstantEffect +// +// History: 6/25/2003 + Created -- Cary Brisebois +// +//============================================================================= + +//======================================== +// System Includes +//======================================== +// Foundation Tech +#include <raddebug.hpp> + +//======================================== +// Project Includes +//======================================== +#include <input/constanteffect.h> +#include <input/wheeldefines.h> +#include <input/inputmanager.h> + + +//***************************************************************************** +// +// Global Data, Local Data, Local Classes +// +//***************************************************************************** + +//***************************************************************************** +// +// Public Member Functions +// +//***************************************************************************** + +//============================================================================= +// ConstantEffect::ConstantEffect +//============================================================================= +// Description: Constructor. +// +// Parameters: None. +// +// Return: N/A. +// +//============================================================================= +ConstantEffect::ConstantEffect() +{ + //Setup the respective force effect structures. +#ifdef RAD_WIN32 + m_diConstant.lMagnitude = 0; + m_diEnvelope.dwSize = sizeof(DIENVELOPE); + m_diEnvelope.dwAttackLevel = 0; + m_diEnvelope.dwAttackTime = 0; + m_diEnvelope.dwFadeLevel = 0; + m_diEnvelope.dwFadeTime = 0; + + mForceEffect.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + mForceEffect.dwDuration = 500; + mForceEffect.dwGain = DI_FFNOMINALMAX; + mForceEffect.dwTriggerButton = DIEB_NOTRIGGER; + mForceEffect.cAxes = 1; + mForceEffect.rgdwAxes = m_rgdwAxes; + mForceEffect.rglDirection = m_rglDirection; + mForceEffect.lpEnvelope = NULL; + mForceEffect.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); + mForceEffect.lpvTypeSpecificParams = &m_diConstant; + mForceEffect.dwStartDelay = 0; + +#else + mForceEffect.type = LG_TYPE_CONSTANT; + mForceEffect.duration = 500; + mForceEffect.startDelay = 0; + mForceEffect.p.constant.magnitude = 0; + mForceEffect.p.constant.direction = 0; + mForceEffect.p.constant.envelope.attackTime = 0; + mForceEffect.p.constant.envelope.fadeTime = 0; + mForceEffect.p.constant.envelope.attackLevel = 0; + mForceEffect.p.constant.envelope.fadeLevel = 0; +#endif +} + +//============================================================================= +// ConstantEffect::~ConstantEffect +//============================================================================= +// Description: Destructor. +// +// Parameters: None. +// +// Return: N/A. +// +//============================================================================= +ConstantEffect::~ConstantEffect() +{ +} + +//============================================================================= +// ConstantEffect::OnInit +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: void +// +//============================================================================= +void ConstantEffect::OnInit() +{ +#ifdef RAD_WIN32 + m_diConstant.lMagnitude = 0; +#else + mForceEffect.p.constant.magnitude = 0; +#endif +} + +//============================================================================= +// ConstantEffect::SetMagnitude +//============================================================================= +// Description: Comment +// +// Parameters: ( s16 magnitude ) +// +// Return: void +// +//============================================================================= +void ConstantEffect::SetMagnitude( s16 magnitude ) +{ +#ifdef RAD_WIN32 + m_diConstant.lMagnitude = magnitude; +#else + mForceEffect.p.constant.magnitude = magnitude; +#endif + mEffectDirty = true; +} + +//============================================================================= +// ConstantEffect::SetDirection +//============================================================================= +// Description: Comment +// +// Parameters: ( u16 direction ) +// +// Return: void +// +//============================================================================= +void ConstantEffect::SetDirection( u16 direction ) +{ +#ifdef RAD_WIN32 + LONG rglDirection[2] = { direction, 0 }; + mForceEffect.rglDirection = rglDirection; +#else + mForceEffect.p.constant.direction = direction; +#endif + + mEffectDirty = true; +} + +//***************************************************************************** +// +// Private Member Functions +// +//***************************************************************************** diff --git a/game/code/input/constanteffect.h b/game/code/input/constanteffect.h new file mode 100644 index 0000000..ed9ff9e --- /dev/null +++ b/game/code/input/constanteffect.h @@ -0,0 +1,59 @@ +//============================================================================= +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: constanteffect.h +// +// Description: Blahblahblah +// +// History: 6/25/2003 + Created -- Cary Brisebois +// +//============================================================================= + +#ifndef CONSTANTEFFECT_H +#define CONSTANTEFFECT_H + +//======================================== +// Nested Includes +//======================================== +#include <input/forceeffect.h> + +//======================================== +// Forward References +//======================================== + +//============================================================================= +// +// Synopsis: Blahblahblah +// +//============================================================================= + +class ConstantEffect : public ForceEffect +{ +public: + ConstantEffect(); + virtual ~ConstantEffect(); + + void OnInit(); + + void SetMagnitude( s16 magnitude ); + void SetDirection( u16 direction ); + +private: + +#ifdef RAD_WIN32 + DICONSTANTFORCE m_diConstant; + DIENVELOPE m_diEnvelope; +#endif + + //Prevent wasteful constructor creation. + ConstantEffect( const ConstantEffect& constanteffect ); + ConstantEffect& operator=( const ConstantEffect& constanteffect ); +}; + +//***************************************************************************** +// +//Inline Public Member Functions +// +//***************************************************************************** + +#endif //CONSTANTEFFECT_H diff --git a/game/code/input/controller.h b/game/code/input/controller.h new file mode 100644 index 0000000..d98482a --- /dev/null +++ b/game/code/input/controller.h @@ -0,0 +1,100 @@ +#ifndef CONTROLLER_HPP +#define CONTROLLER_HPP + +namespace Input +{ + // Platform specific controller topology. + #ifdef RAD_XBOX + const static unsigned int MaxPorts = 4; + const static unsigned int MaxSlots = 1; + #endif + #ifdef RAD_PS2 + const static unsigned int MaxPorts = 2; + const static unsigned int MaxSlots = 4; + #endif + #ifdef RAD_GAMECUBE + const static unsigned int MaxPorts = 4; + const static unsigned int MaxSlots = 1; + #endif + #if defined( RAD_WIN32 ) + const static unsigned int MaxPorts = 4; + const static unsigned int MaxSlots = 1; + #endif + + #ifdef RAD_PS2 + enum USBID + { + USB0 = (MaxPorts * MaxSlots), + USB1 = (MaxPorts * MaxSlots) + 1 + }; + static const unsigned int MaxUSB = 2; + + // Platform specific max controllers. + const static unsigned int MaxControllers = (MaxPorts * MaxSlots) + MaxUSB; + + #else //NOT PS2 + // Platform specific max controllers. + const static unsigned int MaxControllers = (MaxPorts * MaxSlots); + #endif + + + #ifdef RAD_WIN32 + const static unsigned int NumExtraButtonsForSuperSprint = 7; + #endif + + // Maximum number of physical buttons (in a UserController) + #ifdef RAD_WIN32 + const static unsigned int MaxPhysicalButtons = 42 + NumExtraButtonsForSuperSprint; + #else + const static unsigned int MaxPhysicalButtons = 40; + #endif + + // Maximum number of logical buttons (in a UserController) + #ifdef RAD_WIN32 + const static unsigned int MaxLogicalButtons = 42 + NumExtraButtonsForSuperSprint; + #else + const static unsigned int MaxLogicalButtons = 40; + #endif + + // Maximum number of logical controllers for a physical device + const static unsigned int MaxMappables = 16; + + // Maximum number of control mappings for a logical controller + const static unsigned int MaxMappings = 2; + + // Maximum number of physical keys that can be assigned to a virtual key + // for a controller. + #ifdef RAD_WIN32 + const static unsigned int MaxVirtualMappings = 2; + #endif + + // Maximum number of rumble motors + #ifdef RAD_GAMECUBE + const static unsigned int MaxOutputMotor = 1; + #else + const static unsigned int MaxOutputMotor = 2; + #endif + + // Control system state (for keeping input roped in in certain gameplay states) + enum ActiveState + { + ACTIVE_NONE = 0, + ACTIVE_GAMEPLAY = 1 << 0, + ACTIVE_FRONTEND = 1 << 1, + ACTIVE_SS_GAME = 1 << 2, + ACTIVE_FIRST_PERSON = 1 << 3, + ACTIVE_ANIM_CAM = 1 << 4, + DEACTIVE_ANIM_CAM = 0xfffffffe, + ACTIVE_ALL = 0xffffffff + }; + + // handy constant for a bunk controller / input + enum + { + INVALID_CONTROLLERID = -1 + }; +}; + + + +#endif diff --git a/game/code/input/forceeffect.cpp b/game/code/input/forceeffect.cpp new file mode 100644 index 0000000..70fb63c --- /dev/null +++ b/game/code/input/forceeffect.cpp @@ -0,0 +1,195 @@ +//============================================================================= +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: forceeffect.cpp +// +// Description: Implement ForceEffect +// +// History: 6/25/2003 + Created -- Cary Brisebois +// +//============================================================================= + +//======================================== +// System Includes +//======================================== +// Foundation Tech +#include <raddebug.hpp> + +//======================================== +// Project Includes +//======================================== +#include <input/forceeffect.h> + + +//***************************************************************************** +// +// Global Data, Local Data, Local Classes +// +//***************************************************************************** + +//***************************************************************************** +// +// Public Member Functions +// +//***************************************************************************** + +//============================================================================= +// ForceEffect::ForceEffect +//============================================================================= +// Description: Constructor. +// +// Parameters: None. +// +// Return: N/A. +// +//============================================================================= +ForceEffect::ForceEffect() : +mOutputPoint( NULL ), +#ifdef RAD_WIN32 +m_effectTime(0), +m_currentTime(0), +#endif +mEffectDirty( true ) +{ +#ifdef RAD_WIN32 + ZeroMemory( &mForceEffect, sizeof(mForceEffect) ); + ZeroMemory( &m_rglDirection, sizeof(m_rglDirection) ); + + mForceEffect.dwSize = sizeof(DIEFFECT); + + m_rgdwAxes[0] = DIJOFS_X; + m_rgdwAxes[1] = DIJOFS_Y; +#endif +} + +//============================================================================= +// ForceEffect::~ForceEffect +//============================================================================= +// Description: Destructor. +// +// Parameters: None. +// +// Return: N/A. +// +//============================================================================= +ForceEffect::~ForceEffect() +{ + if ( mOutputPoint ) + { + mOutputPoint->Stop(); + mOutputPoint->Release(); + mOutputPoint = NULL; + } +} + +//============================================================================= +// ForceEffect::Init +//============================================================================= +// Description: Comment +// +// Parameters: ( IRadControllerOutputPoint* outputPoint ) +// +// Return: void +// +//============================================================================= +void ForceEffect::Init( IRadControllerOutputPoint* outputPoint ) +{ +#ifdef RAD_WIN32 + rAssertMsg( outputPoint != NULL, "Attempt to set the outputPoint with a NULL pointer." ); + // mOutputPoint is dirty. + if ( mOutputPoint ) + { + ShutDownEffects(); + } +#endif + mOutputPoint = outputPoint; + mOutputPoint->AddRef(); + + OnInit(); + + mOutputPoint->UpdateEffect( &mForceEffect ); +} + +//============================================================================= +// ForceEffect::Start +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: void +// +//============================================================================= +void ForceEffect::Start() +{ + //Clear out current effects. + OnInit(); + mEffectDirty = true; + + if ( mOutputPoint ) + { + mOutputPoint->Start(); + } +} + +//============================================================================= +// ForceEffect::Stop +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: void +// +//============================================================================= +void ForceEffect::Stop() +{ + if ( mOutputPoint ) + { + mOutputPoint->Stop(); + } +} + +//============================================================================= +// ForceEffect::Update +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: void +// +//============================================================================= +#ifdef RAD_WIN32 +void ForceEffect::Update(unsigned timeins) +#else +void ForceEffect::Update() +#endif +{ + if ( mEffectDirty && mOutputPoint ) + { + mOutputPoint->UpdateEffect( &mForceEffect ); + mEffectDirty = false; + } +} +#ifdef RAD_WIN32 +void ForceEffect::ShutDownEffects() +{ + if ( mOutputPoint ) + { + mOutputPoint->ReleaseEffect(); + mOutputPoint->Release(); + mOutputPoint = NULL; + } +} + +void ForceEffect::SetResetTime( DWORD dwMilliSeconds ) +{ + m_effectTime = dwMilliSeconds; +} +#endif +//***************************************************************************** +// +// Private Member Functions +// +//***************************************************************************** diff --git a/game/code/input/forceeffect.h b/game/code/input/forceeffect.h new file mode 100644 index 0000000..050c284 --- /dev/null +++ b/game/code/input/forceeffect.h @@ -0,0 +1,104 @@ +//============================================================================= +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: forceeffect.h +// +// Description: Blahblahblah +// +// History: 6/25/2003 + Created -- Cary Brisebois +// +//============================================================================= + +#ifndef FORCEEFFECT_H +#define FORCEEFFECT_H + +//======================================== +// Nested Includes +//======================================== +#include <radcontroller.hpp> + +#ifdef RAD_GAMECUBE +#include <dolphin/lg.h> +#endif + +#ifdef RAD_PS2 +#include <liblgdev.h> +#endif + +#ifdef RAD_WIN32 +#define DIRECTINPUT_VERSION 0x0800 +#include <dinput.h> +#endif + +#if defined(RAD_PS2) || defined(RAD_WIN32) +typedef char s8; +typedef unsigned char u8; +typedef short s16; +typedef unsigned short u16; +typedef unsigned int u32; +#endif + +//======================================== +// Forward References +//======================================== + +//============================================================================= +// +// Synopsis: Blahblahblah +// +//============================================================================= + +class ForceEffect +{ +public: + ForceEffect(); + virtual ~ForceEffect(); + +#ifdef RAD_WIN32 + void SetForceID( u8 forceID ) { m_index = forceID; } + u8 GetForceID() const { return m_index; } + +#endif + + void Init( IRadControllerOutputPoint* outputPoint ); + bool IsInit() const { return ( mOutputPoint != NULL ); }; + + void Start(); + void Stop(); + +#ifdef RAD_WIN32 + virtual void Update(unsigned timeins = 0); + void ShutDownEffects(); + void SetResetTime( DWORD dwMilliSeconds ); +#else + void Update(); +#endif + +protected: + IRadControllerOutputPoint* mOutputPoint; +#ifdef RAD_WIN32 + DIEFFECT mForceEffect; + DWORD m_rgdwAxes[2]; + LONG m_rglDirection[2]; + u8 m_index; // the index ID of this force. + DWORD m_currentTime; + DWORD m_effectTime; +#else + LGForceEffect mForceEffect; +#endif + bool mEffectDirty; + + virtual void OnInit() = 0; + + //Prevent wasteful constructor creation. + ForceEffect( const ForceEffect& forceeffect ); + ForceEffect& operator=( const ForceEffect& forceeffect ); +}; + +//***************************************************************************** +// +//Inline Public Member Functions +// +//***************************************************************************** + +#endif //FORCEEFFECT_H diff --git a/game/code/input/inputPointList.h b/game/code/input/inputPointList.h new file mode 100644 index 0000000..2d581d5 --- /dev/null +++ b/game/code/input/inputPointList.h @@ -0,0 +1,176 @@ +#if !defined(AFX_LIST_H__F5C121CA_0F5B_4CE3_91D5_B7B24AEB8D37__INCLUDED_) +#define AFX_LIST_H__F5C121CA_0F5B_4CE3_91D5_B7B24AEB8D37__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +/****************************************************************************** + List + + Date: 19-11-01 + + Name: Jeff Giles + Ezeikeil@Hotmail.com + + Notes: A Simple, doubly linked list which returns NULL when run off + either end. + + +******************************************************************************/ +template <class type> +class List +{ + //*Node struct******************************************************************* + // Notes: The workhorse of the Linked List + //***************************************************************************** + struct Node + { + type * thedata; //pointer to the data + Node * nextnode; //pointer to the next node in the list + Node * lastnode; //pointer to the previous node in the list + + //Ctors + Node(): thedata(0),nextnode(0),lastnode(0) {}; + Node(type* data, Node* next): thedata(data),nextnode(next),lastnode(0) {}; + }; + +public: + //*Ctor/Dtor***************************************************************** + List(): myHead(0),myTail(0), numNodes(0) {}; + virtual ~List(){}; + + //*GetSize********************************************************************* + // Notes: returns the current number of nodes + //***************************************************************************** + int GetSize() + { + return numNodes; + } + + //*PushFront******************************************************************* + // Notes: Pushes an element onto the top of the list + //***************************************************************************** + void PushFront(type * data) + { + myHead = new Node(data, myHead); + + if (myTail == NULL) + myTail = myHead; + + if(myHead->nextnode !=NULL) //redirect the node following myHead + myHead->nextnode->lastnode = myHead; //to point to the new head + + numNodes++; + } + + //*PushBack****************************************************************** + // Notes: Pushes an element onto the bottom of the list + //*************************************************************************** + void PushBack(type * data) + { + if (myHead == NULL) //then the list must be empty + PushFront(data); + else + { + Node * temp = new Node; + temp->thedata = data; + temp->lastnode = myTail; + + myTail= temp; //redirect myTail + myTail->lastnode->nextnode = temp; //redirect the nextnode before + //myTail to point to the new Node + numNodes++; + } + } + + //*PopBack********************************************************************* + // Notes: Removes an element from the top of the list + //***************************************************************************** + type * PopBack() + { + if(myTail != NULL) + { + type * temp = myTail->thedata; + Node * oldtail = myTail; //keep a hold of the data to prevent memory leak + myTail = myTail->lastnode; + numNodes--; + delete oldtail; + return temp; + } + else + return NULL; + }; + + //*PopFront******************************************************************* + // Notes: Removes an element from the bottom of the list + //**************************************************************************** + type * PopFront() + { + + if(myHead != NULL) + { + type * temp = myHead->thedata; + Node * oldHead = myHead; //keep a hold of the data to prevent memory leak + myHead = myHead->nextnode; + numNodes--; + delete oldHead; + return temp; + } + else + return NULL; + + }; + + //*PeekFront****************************************************************** + // Notes: Accesses the top of the list without removing the node + //**************************************************************************** + type * PeekFront() + { + if(myHead) + return myHead->thedata; + else + return NULL; + }; + + //*PeekBack******************************************************************* + // Notes: Accesses the bottom of the list without removing the node + //**************************************************************************** + type * PeekBack() + { + if(myTail) + return myTail->thedata; + else + return NULL; + }; + + //*operator []**************************************************************** + // Notes: Accesses the any node of the list without removing it + // Position is from top to + //**************************************************************************** + type * operator[] (int index) + { + if(numNodes < 0 || index >= numNodes) //prevent overrun + return NULL; + else + { + Node * temp = myHead; + int counter = 0; + + while (counter < index) + { + temp = temp->nextnode; //point temp at the next node in the list + counter++; + } + return temp->thedata; + } + }; + +private: + Node * myTail; + Node * myHead; + int numNodes; +}; + +#endif // !defined(AFX_LIST_H__F5C121CA_0F5B_4CE3_91D5_B7B24AEB8D37__INCLUDED_) diff --git a/game/code/input/inputmanager.cpp b/game/code/input/inputmanager.cpp new file mode 100644 index 0000000..8bd8550 --- /dev/null +++ b/game/code/input/inputmanager.cpp @@ -0,0 +1,731 @@ +//============================================================================= +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: inputmanager.cpp +// +// Description: Implementation for the InputManager class. +// +// History: + Created -- TBJ +// +//============================================================================= + +//======================================== +// System Includes +//======================================== +#include <string.h> // ::strcmp() +//FTech +#include <raddebugwatch.hpp> +#include <raddebug.hpp> +#include <radcontroller.hpp> + +//======================================== +// Project Includes +//======================================== +#include <input/inputmanager.h> +#ifdef RAD_WIN32 +#include <input/usercontrollerWin32.h> +#else +#include <input/usercontroller.h> +#endif +#include <input/button.h> + +#include <main/game.h> +#include <main/platform.h> + +#include <data/gamedatamanager.h> + +#ifndef WORLD_BUILDER +#include <memory/srrmemory.h> +#else +#define MEMTRACK_PUSH_GROUP(x) +#define MEMTRACK_POP_GROUP(x) +#define GMA_PERSISTENT 0 +#define GMA_DEFAULT 0 +#endif + +#ifdef RAD_PS2 +#include <main/ps2platform.h> +#include <libmtap.h> +#endif + +#if defined RAD_XBOX + + InputManager::eButtonMap RESET_BUTTONS[] = + { + InputManager::Start, + InputManager::Select + }; + + const int NUM_RESET_BUTTONS = 2; + +#else //GC handled in gcmanager and we don't do this on the PC + +InputManager::eButtonMap RESET_BUTTONS[] = +{ + InputManager::Start +}; + +const int NUM_RESET_BUTTONS = 0; + +#endif + +const unsigned int RESET_TIMEOUT = 2000; + +//****************************************************************************** +// Global Data, Local Data, Local Classes +//****************************************************************************** + +// +// Static pointer to instance of singleton. +// +InputManager* InputManager::spInstance = NULL; + + +//****************************************************************************** +// Public Member Functions +//****************************************************************************** + +// Creates the InputManager. +// This is a singleton so only one instance is allowed. +InputManager* InputManager::CreateInstance() +{ +MEMTRACK_PUSH_GROUP( "InputManager" ); + + rAssert( spInstance == NULL ); + + spInstance = new InputManager; +MEMTRACK_POP_GROUP("InputManager"); + + return spInstance; +} + +// Access point for the InputManager singleton. +InputManager* InputManager::GetInstance() +{ + rAssert( spInstance != NULL ); + + return spInstance; +} + +// Destroy the InputManager.singleton +void InputManager::DestroyInstance() +{ + rAssert( spInstance != NULL ); + + delete spInstance; + spInstance = NULL; +} + + +void InputManager::Init() +{ + +MEMTRACK_PUSH_GROUP( "InputManager" ); + ::radControllerInitialize( this, GMA_DEFAULT ); + + mxIControllerSystem2 = radControllerSystemGet(); + +#ifdef RAD_PS2 + // On PS2, check for initial button pushes. + m_isProScanButtonsPressed = PS2Platform::GetInstance()->CheckForStartupButtons( ); + rDebugPrintf( "Do Progressive scan: %s\n", m_isProScanButtonsPressed ? "yup" : "nope" ); +#endif + + unsigned int i = 0; + + for ( i = 0; i < Input::MaxControllers; i++ ) + { + // preallocate run time controller structure. + mControllerArray[ i ].Create(i); + } +#ifndef RAD_WIN32 + mxIControllerSystem2->RegisterConnectionChangeCallback( this ); +#endif + rDebugString( "Just created User controller system\n" ); + + EnumerateControllers( ); +MEMTRACK_POP_GROUP("InputManager"); + +} + + +void InputManager::Update( unsigned int timeinms ) +{ + // update the button timestamp (so we can tell when buttons were pressed) + Button::Tick(timeinms); + + ::radControllerSystemService(); + + // if controllers have been disconnected, change the state + if(mConnectStateChanged) + { + mConnectStateChanged = false; + EnumerateControllers( ); + } + + unsigned int i = 0; + + // update physical controllers + bool resetting = false; + for ( i = 0; i < Input::MaxControllers; i++ ) + { + if(mControllerArray[i].IsConnected()) + { + mControllerArray[i].Update(timeinms); + + if ( mResetEnabled && + NUM_RESET_BUTTONS > 0 && + !resetting && + mControllerArray[i].GetInputValueRT( RESET_BUTTONS[ 0 ] ) > 0.5f && + mControllerArray[i].GetInputValueRT( RESET_BUTTONS[ 1 ] ) > 0.5f ) + { + resetting = true; + } + } + } + +#ifndef RAD_XBOX + if ( mResetEnabled ) + { + if ( !resetting ) + { + mResetTimeout = 0; + mIsResetting = false; + } + else if ( resetting && !mIsResetting ) + { + mResetTimeout = RESET_TIMEOUT; + mIsResetting = true; + } + } +#endif + + + // broadcast new game state if it has changed + if(mChangeGameState) + { + for ( i = 0; i < Input::MaxControllers; i++ ) + { + // TC: Why does controller have to be connected for its game state to be updated? + // Having the 'if' conditional here causes a problem when the controller is + // disconnnected during a state when it's non-active. + // +// if(mControllerArray[i].IsConnected()) + { + mControllerArray[i].SetGameState(mGameState); + } + } + mChangeGameState = false; + } + + if ( mResetEnabled && mIsResetting && mResetTimeout >= 0 ) + { + if ( mResetTimeout <= timeinms ) + { + GetGame()->GetPlatform()->LaunchDashboard(); + mResetTimeout = 0; + mIsResetting = false; + } + else + { + mResetTimeout -= timeinms; + } + } +} + + +void InputManager::OnControllerConnectionStatusChange( IRadController * pIController2 ) +{ + mConnectStateChanged = true; +} + +bool InputManager::IsControllerInPort( int portnum ) const +{ + rAssert(portnum < static_cast< int >( Input::MaxControllers ) ); + return mControllerArray[portnum].IsConnected(); +} + +void InputManager::ToggleRumble( bool on ) +{ + unsigned int i; + for ( i = 0; i < Input::MaxControllers; ++i ) + { + if ( mControllerArray[ i ].IsConnected() ) + { + mControllerArray[ i ].SetRumble( on ); + } + } +} + + +//============================================================================= +// InputManager::SetRumbleEnabled +//============================================================================= +// Description: Comment +// +// Parameters: ( bool isEnabled ) +// +// Return: nothing +// +//============================================================================= +void InputManager::SetRumbleEnabled( bool isEnabled ) +{ + mIsRumbleEnabled = isEnabled; +} + +void InputManager::SetRumbleForDevice( int controllerId, bool bRumbleOn ) +{ + if ( (unsigned int)controllerId < Input::MaxControllers) + { + mControllerArray[controllerId].SetRumble( bRumbleOn ); + } +} + + +bool InputManager::IsRumbleOnForDevice( int controllerId ) const +{ + if ( (unsigned int)controllerId < Input::MaxControllers) + { + return mControllerArray[controllerId].IsRumbleOn( ); + } + return false; +} + +void InputManager::TriggerRumblePulse( int controllerId ) +{ + if ( (unsigned int)controllerId < Input::MaxControllers) + { + mControllerArray[ controllerId ].PulseRumble(); + } +} + +// Returns the value of the input point 'inputIndex' owned by the controller at +// controllerIndex. +float InputManager::GetValue( unsigned int controllerIndex, unsigned int inputIndex ) const +{ + rAssert( controllerIndex < Input::MaxControllers); + if ( controllerIndex < Input::MaxControllers) + { + return mControllerArray[ controllerIndex ].GetInputValue( inputIndex ); + } + else + { + return 0.0f; + } +} + +// Returns a const pointer to the controller at controller index. +UserController* InputManager::GetController( unsigned int controllerIndex ) +{ + rAssert( controllerIndex < Input::MaxControllers ); + if ( controllerIndex < Input::MaxControllers ) + { + return &mControllerArray[ controllerIndex ]; + } + else + { + return 0; + } +} + + +// Associate this device with a game object. +int InputManager::RegisterMappable( unsigned int index, Mappable *pMappable ) +{ + int handle = Input::INVALID_CONTROLLERID; + if ( index < Input::MaxControllers) + { + handle = mControllerArray[ index ].RegisterMappable( pMappable ); + } + return handle; +} + + +// Remove associations between this device and a game object. +void InputManager::UnregisterMappable( unsigned int index, int handle ) +{ + if ( handle > Input::INVALID_CONTROLLERID ) + { + if ( index < Input::MaxControllers) + { + mControllerArray[ index ].UnregisterMappable( handle ); + } + } +} + +void InputManager::UnregisterMappable( unsigned int index, Mappable* mappable) +{ + mControllerArray[ index ].UnregisterMappable( mappable ); +} + +void InputManager::UnregisterMappable( Mappable *pMappable ) +{ + unsigned int i; + for ( i = 0; i < Input::MaxControllers; ++i ) + { + mControllerArray[ i ].UnregisterMappable( pMappable ); + } +} + + +void InputManager::LoadData( const GameDataByte* dataBuffer, unsigned int numBytes ) +{ + mIsRumbleEnabled = ( dataBuffer[ 0 ] != 0 ); +} + +void InputManager::SaveData( GameDataByte* dataBuffer, unsigned int numBytes ) +{ + dataBuffer[ 0 ] = mIsRumbleEnabled ? ~0 : 0; +} + +void InputManager::ResetData() +{ + //Rumble does not RESET. This is a TRC thing. + //mIsRumbleEnabled = true; +} + +//****************************************************************************** +// Private Member Functions +//****************************************************************************** + +InputManager::InputManager() +: +mGameState(Input::ACTIVE_ALL), +mChangeGameState(false), +mConnectStateChanged(false), +mIsRumbleEnabled(true), +mIsResetting(false), +mResetEnabled( false ), +m_isProScanButtonsPressed( false ) +{ + for( int i = 0; i < MAX_PLAYERS; i++ ) + { + m_registeredControllerID[ i ] = -1; + } + + GetGameDataManager()->RegisterGameData( this, 1, "Input Manager" ); +#ifdef RAD_WIN32 + m_pFEMouse = new FEMouse; +#endif +#ifdef RAD_PS2 + mLastMultitapStatus[0] = mLastMultitapStatus[1] = 0; + mCurMultitapStatus[0] = mCurMultitapStatus[1] = 0; + +#endif +} + + +InputManager::~InputManager() +{ + ReleaseAllControllers(); + +#ifndef RAD_WIN32 + mxIControllerSystem2->UnRegisterConnectionChangeCallback( this ); +#endif + ::radControllerTerminate(); +#ifdef RAD_WIN32 + delete m_pFEMouse; + m_pFEMouse = NULL; +#endif +} + +void InputManager::EnumerateControllers( void ) +{ + // on the console the controller device and all the mappables are + // preallocated. So we don't have to create new associations. + // +#ifndef RAD_WIN32 + ref< IRadController > xIC2; +#else + ref< IRadController > radController[ NUM_CONTROLLERTYPES ]; +#endif + + ReleaseAllControllers( ); + + bool somethingPluggedIn0 = false; + bool somethingPluggedIn1 = false; + + unsigned int slot = 0; + unsigned int port = 0; + for ( port = 0; port < Input::MaxPorts; ++port ) + { + for ( slot = 0; slot < Input::MaxSlots; ++slot ) + { + unsigned int i = port * Input::MaxSlots + slot; + + char szLocation[ 256 ]; + +#if defined(RAD_XBOX) || defined( RAD_PS2 ) + sprintf( szLocation, "Port%d\\Slot%d", port, slot ); +#elif defined(RAD_WIN32) + char szJoystickLoc[ 256 ]; + char szMouseLoc[ 256 ]; + char szWheelLoc[ 256 ]; + + sprintf( szLocation, "Keyboard%d", 0); + sprintf( szJoystickLoc, "Joystick%d", i); + sprintf( szMouseLoc, "Mouse%d", i); + sprintf( szWheelLoc, "SteeringWheel%d", i); +#else //This is GC + sprintf( szLocation, "Channel%d", i ); +#endif + +#ifndef RAD_WIN32 + xIC2 = mxIControllerSystem2->GetControllerAtLocation( szLocation ); +#else + radController[KEYBOARD] = mxIControllerSystem2->GetControllerAtLocation( szLocation ); + radController[GAMEPAD] = mxIControllerSystem2->GetControllerAtLocation( szJoystickLoc ); + radController[MOUSE] = mxIControllerSystem2->GetControllerAtLocation( szMouseLoc ); + radController[STEERINGWHEEL] = mxIControllerSystem2->GetControllerAtLocation( szWheelLoc ); + + //Check to see if the steering wheel is on controller 0. + +#endif + + // + // Grab the controller device associated with the foundation controller. + // + UserController* controller = &mControllerArray[ i ]; + + +#ifdef RAD_WIN32 + // One keyboard has to be present. (might want to change later) + if ( (radController[KEYBOARD] == NULL || !radController[KEYBOARD]->IsConnected( )) && (i == 0) ) + { + controller->NotifyDisconnect( ); + } + else + { + controller->Initialize( radController ); + controller->NotifyConnect( ); + controller->LoadControllerMappings( ); + + for( int i = 0; i < NUM_CONTROLLERTYPES; i++ ) + { + radController[i] = NULL; + } + } +#else + if ( xIC2 == NULL || !xIC2->IsConnected( ) ) + { + controller->NotifyDisconnect( ); + } + else + { +#ifdef RAD_PS2 + if(strcmp( "PsxDualShock2", xIC2->GetType() ) == 0 ) + { + controller->Initialize( xIC2 ); + controller->NotifyConnect( ); + controller->LoadControllerMappings( ); + controller->SetRumble( IsRumbleEnabled() ); + } + xIC2 = NULL; + + if ( port == 0 ) + { + somethingPluggedIn0 = true; + } + else + { + somethingPluggedIn1 = true; + } +#else + controller->Initialize( xIC2 ); + controller->NotifyConnect( ); + controller->LoadControllerMappings( ); + controller->SetRumble( IsRumbleEnabled() ); + + xIC2 = NULL; +#endif + } +#endif + } + } + +#ifdef RAD_PS2 + + //TEST THE MULTITAP STATUS + if ( somethingPluggedIn0 || somethingPluggedIn1 ) + { + if ( somethingPluggedIn0 ) + { + mLastMultitapStatus[0] = sceMtapGetConnection(0); + } + + if ( somethingPluggedIn1 ) + { + mLastMultitapStatus[1] = sceMtapGetConnection(1); + } + } +#endif + + +#ifdef RAD_PS2 + unsigned int i; + for ( i = 0; i < Input::MaxUSB; ++i ) + { + char szLocation[ 256 ]; + sprintf( szLocation, "USB%d", i ); + + xIC2 = mxIControllerSystem2->GetControllerAtLocation( szLocation ); + // + // Grab the controller device associated with the foundation controller. + // + UserController* controller = &mControllerArray[ Input::USB0 + i ]; + + if ( xIC2 == NULL || !xIC2->IsConnected( ) ) + { + controller->NotifyDisconnect( ); + } + else + { + if ( xIC2->IsConnected( ) && strcmp( xIC2->GetClassification(), "Wheel" ) == 0 ) + { + // Initialize the controller. This will notify all observers of the + // controller being added. + + controller->Initialize( xIC2 ); + controller->NotifyConnect( ); + controller->LoadControllerMappings( ); + } + else + { + controller->NotifyDisconnect( ); + } + xIC2 = NULL; + } + } +#endif + +//#ifdef RAD_DEBUG + char connectionMap[128] = "Controller status changed (connection : "; + + for( port = 0; port < Input::MaxPorts; port++) + { + for( slot = 0; slot < Input::MaxSlots; slot++) + { + int index = port * Input::MaxSlots + slot; + if(mControllerArray[ index ].IsConnected()) + { + strcat(connectionMap, "x"); + } + else + { + strcat(connectionMap, "o"); + } + } + strcat(connectionMap," "); + } +#ifdef RAD_PS2 + for(unsigned int i = (Input::MaxSlots * Input::MaxPorts); i < Input::MaxControllers; ++i ) + { + if ( mControllerArray[i].IsConnected() ) + { + strcat(connectionMap,"U"); + } + else + { + strcat(connectionMap, "o"); + } + } +#endif + strcat(connectionMap,")\n"); + + rReleaseString(connectionMap); +//#endif +} + +void InputManager::ReleaseAllControllers( void ) +{ + unsigned int i = 0; + for ( i = 0; i < Input::MaxControllers; i++ ) + { + mControllerArray[ i ].ReleaseRadController( ); + } +} + + +void InputManager::SetGameState( Input::ActiveState state ) +{ + // + // The only way to get out of the animated cam input state is to set it + // to the DEACTIVE_ANIM_CAM state, which actually sends you to active all. + // Perhaps the input system should really be a stack? + // + if( mGameState == Input::ACTIVE_ANIM_CAM ) + { + if( state == Input::DEACTIVE_ANIM_CAM ) + { + state = Input::ACTIVE_ALL; + } + else + { + state = Input::ACTIVE_ANIM_CAM; + } + } + else + { + if( state == Input::DEACTIVE_ANIM_CAM ) + { + return; + } + } + mChangeGameState = true; + mGameState = state; +} + +Input::ActiveState InputManager::GetGameState() const +{ + return static_cast<Input::ActiveState>(mGameState); +} + + +void +InputManager::RegisterControllerID( int playerID, int controllerID ) +{ + rAssert( playerID >= 0 && playerID < MAX_PLAYERS ); + + m_registeredControllerID[ playerID ] = controllerID; + + rTunePrintf( "*** Registered Controller ID [%d] for Player %d ***\n", + controllerID, playerID + 1 ); +} + +void +InputManager::UnregisterControllerID( int playerID ) +{ + rAssert( playerID >= 0 && playerID < MAX_PLAYERS ); + + m_registeredControllerID[ playerID ] = -1; +} + +void +InputManager::UnregisterAllControllerID() +{ + for( int i = 0; i < MAX_PLAYERS; i++ ) + { + UnregisterControllerID( i ); + } +} + +#ifdef RAD_WIN32 + +void InputManager::StartRumbleEffects() +{ + for( int i = 0; i < MAX_PLAYERS; i++ ) + { + SetRumbleForDevice(i, true); + } +} + +void InputManager::StopRumbleEffects() +{ + for( int i = 0; i < MAX_PLAYERS; i++ ) + { + SetRumbleForDevice(i, false); + } +} + +#endif + diff --git a/game/code/input/inputmanager.h b/game/code/input/inputmanager.h new file mode 100644 index 0000000..d21303e --- /dev/null +++ b/game/code/input/inputmanager.h @@ -0,0 +1,414 @@ +//============================================================================= +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: inputmanager.h +// +// Description: InputManager class declaration. +// +// History: + Created -- TBJ +// +//============================================================================= + +#ifndef InputManager_HPP +#define InputManager_HPP + +//======================================== +// System Includes +//======================================== +#include <radcontroller.hpp> + +//======================================== +// Project Includes +//======================================== +#include <data/gamedata.h> +#include <input/controller.h> +#ifdef RAD_WIN32 +#include <input/usercontrollerWin32.h> +#include <input/FEMouse.h> +#else +#include <input/usercontroller.h> +#endif +#include <constants/maxplayers.h> + +//======================================== +// Forward References +//======================================== +class UserController; +class Mappable; + +//============================================================================== +// +// Synopsis: Used to trigger events and route them to the listeners. +// +//============================================================================== +class InputManager : public IRadControllerConnectionChangeCallback, + public GameDataHandler +{ +public: +#ifdef RAD_XBOX + enum eButtonMap + { + DPadUp, + DPadDown, + DPadLeft, + DPadRight, + Start, + Back, + Select = Back, + LeftThumb, + L3 = LeftThumb, + RightThumb, + R3 = RightThumb, + A, + X = A, + B, + Circle = B, +// X, //This one is conflicting with PS2 + Square, //This is X + Y, + Triangle = Y, + AnalogA, + AnalogB, + AnalogX, + AnalogY, + Black, + White, + AnalogBlack, + AnalogWhite, + LeftTrigger, + AnalogL1 = LeftTrigger, + RightTrigger, + AnalogR1 = RightTrigger, + LeftStickX, + LeftStickY, + RightStickX, + RightStickY + }; +#elif defined(RAD_WIN32) // Clumsy because of win32<->console differences + enum eButtonMap + { + MoveUp, // These are the real buttons names + MoveDown, + MoveLeft, + MoveRight, + Attack, + Jump, + Sprint, + DoAction, + Accelerate, + Reverse, + SteerLeft, + SteerRight, + GetOutCar, + HandBrake, + Horn, + ResetCar, + CameraLeft, + CameraRight, + CameraMoveIn, + CameraMoveOut, + CameraZoom, + CameraLookUp, + CameraCarLeft, + CameraCarRight, + CameraCarLookUp, + CameraCarLookBack, + CameraToggle, + feBack, + feMoveUp, + feMoveDown, + feMoveLeft, + feMoveRight, + feSelect, + feFunction1, + feFunction2, + feMouseLeft, + feMouseRight, + feMouseUp, + feMouseDown, + + P1_KBD_Start, + P1_KBD_Gas, + P1_KBD_Brake, + P1_KBD_EBrake, + P1_KBD_Nitro, + P1_KBD_Left, + P1_KBD_Right, + Select = feBack, // These are mappings to PS2 buttons, needed sometimes. + Start = feSelect, + DPadUp = MoveUp, + DPadRight = MoveRight, + DPadDown = MoveDown, + DPadLeft = MoveLeft, + R1 = HandBrake, + Triangle = DoAction, + Circle = Sprint, + X = Jump, + Square = Attack, + L3 = Horn, + AnalogL1 = CameraZoom, + AnalogR1 = CameraLookUp, + LeftStickX = 200, // Must hack to get camera stuff to compile + LeftStickY = 201, // Must hack to get camera stuff to compile + KeyboardEsc = 202 // Cute hack to get escape only back buttons + }; +#elif defined(RAD_PS2) + enum eButtonMap + { + Select, + Start, + DPadUp, + DPadRight, + DPadDown, + DPadLeft, + L2, + R2, + L1, + R1, + Triangle, + Circle, + X, + Square, + L3, + R3, + RightStickX, + RightStickY, + LeftStickX, + LeftStickY, + AnalogDPadRight, + AnalogDPadLeft, + AnalogDPadUp, + AnalogDPadDown, + AnalogTriangle, + AnalogCircle, + AnalogX, + AnalogSquare, + AnalogL1, + AnalogR1, + AnalogL2, + AnalogR2, + }; +#else //RAD_GAMECUBE + enum eButtonMap + { + DPadLeft, + DPadRight, + DPadDown, + DPadUp, + TriggerZ, + L3 = TriggerZ, + TriggerR, + AnalogR1 = TriggerR, + TriggerL, + AnalogL1 = TriggerL, + A, + X = A, + B, + Square = B, +// X, //This one is conflicting with PS2 + Circle, //This is X + Y, + Triangle = Y, + Menu, + Start = Menu, + LeftStickX, + LeftStickY, + RightStickX, + RightStickY, + AnalogTriggerL, + LeftTrigger = AnalogTriggerL, + AnalogTriggerR, + RightTrigger = AnalogTriggerR, + AnalogA, + AnalogueX = AnalogA, + AnalogB, + AnalogSquare = AnalogB + }; +#endif + + // Static Methods for accessing this singleton. + static InputManager* CreateInstance( void ); + static InputManager* GetInstance( void ); + static void DestroyInstance( void ); + + // set everything up + void Init(); + + // per frame update + void Update ( unsigned int timeinms ); + + // various info + bool IsControllerInPort( int portnum ) const; + static unsigned int GetMaxControllers( void ) { return Input::MaxControllers; } + const char* GetName() const { return "Game Controller System"; } + + void ToggleRumble( bool on ); + void SetRumbleForDevice( int controllerId, bool bRumbleOn ); + bool IsRumbleOnForDevice( int controllerId ) const; + void TriggerRumblePulse( int controllerId ); + + void SetRumbleEnabled( bool isEnabled ); + bool IsRumbleEnabled() const; + +#ifdef RAD_WIN32 + void StartRumbleEffects(); + void StopRumbleEffects(); +#endif + + // Returns the value of the input point 'inputIndex' owned by the controller at + // controllerIndex. + float GetValue( unsigned int controllerIndex, unsigned int inputIndex ) const; + + // Get a physical controller + UserController* GetController( unsigned int controllerIndex ); + + // Associate this logical controller with the physical controller in slot "index" + int RegisterMappable( unsigned int index, Mappable *pMappable ); + + // Remove associations between a physical and logical controller + void UnregisterMappable( unsigned int index, int handle ); + void UnregisterMappable( unsigned int index, Mappable *pMappable ); + void UnregisterMappable( Mappable *pMappable ); + + // set the current game state for the input system (one of the enums in Input::Active state) + void SetGameState( Input::ActiveState state ); + Input::ActiveState GetGameState() const; + + // registration of controller ID to player ID + // + void RegisterControllerID( int playerID, int controllerID ); + void UnregisterControllerID( int playerID ); + void UnregisterAllControllerID(); + int GetControllerIDforPlayer( int playerID ) const; + int GetControllerPlayerIDforController( int controllerIndex ) const; + + // Implements GameDataHandler + // + virtual void LoadData( const GameDataByte* dataBuffer, unsigned int numBytes ); + virtual void SaveData( GameDataByte* dataBuffer, unsigned int numBytes ); + virtual void ResetData(); + + void EnableReset( bool reset ) { mResetEnabled = reset; }; + + bool IsProScanButtonsPressed() const { return m_isProScanButtonsPressed; } + +#ifdef RAD_WIN32 + FEMouse* GetFEMouse() const { return m_pFEMouse; } +#endif + +#ifdef RAD_PS2 + int GetLastMultitapStatus(int port) const {return mLastMultitapStatus[port];} + int GetCurMultitapStatus(int port) const {return mCurMultitapStatus[port];} +#endif + +private: + InputManager(); + ~InputManager(); + + // IRadControllerConnectionChangeCallback interface + // called when someone plugs in or pulls out a controller + void OnControllerConnectionStatusChange( IRadController* pIController ); + + void ReleaseAllControllers( void ); + void EnumerateControllers( void ); + + static InputManager* spInstance; + + ref< IRadControllerSystem > mxIControllerSystem2; + + UserController mControllerArray[ Input::MaxControllers ]; + + unsigned mGameState; + bool mChangeGameState : 1; + bool mConnectStateChanged : 1; + bool mIsRumbleEnabled : 1; + bool mIsResetting : 1; + bool mResetEnabled : 1; + + int m_registeredControllerID[ MAX_PLAYERS ]; + + unsigned int mResetTimeout; + + bool m_isProScanButtonsPressed : 1; + +#ifdef RAD_WIN32 + FEMouse* m_pFEMouse; +#endif +#ifdef RAD_PS2 + int mLastMultitapStatus[2]; + int mCurMultitapStatus[2]; +#endif +}; + + +// A little syntactic sugar for getting at this singleton. +inline InputManager* GetInputManager() { return( InputManager::GetInstance() ); } + +inline int +InputManager::GetControllerIDforPlayer( int playerID ) const +{ + int controllerID; + rAssert( playerID >= 0 && playerID < MAX_PLAYERS ); + + if ( playerID >= 0 && playerID < MAX_PLAYERS ) + { + controllerID = m_registeredControllerID[ playerID ]; + } + else + { + // Return error code + controllerID = -1; + } + #ifndef RAD_RELEASE + if( m_registeredControllerID[ playerID ] == -1 ) + { + // too much spew, we are polling this constantly for controller unplugged + // rTunePrintf( "*** WARNING: No controller ID registered for player %d!]\n", + // playerID + 1 ); + } + #endif + + return controllerID; +} + +//============================================================================= +// InputManager::GetControllerPlayerIDforController +//============================================================================= +// Description: Comment +// +// Parameters: ( int controllerIndex ) +// +// Return: int +// +//============================================================================= +inline int InputManager::GetControllerPlayerIDforController( int controllerIndex ) const +{ + int i; + for ( i = 0; i < MAX_PLAYERS; ++i ) + { + if ( m_registeredControllerID[ i ] == controllerIndex ) + { + return i; + } + } + + return -1; +} + +//============================================================================= +// InputManager::IsRumbleEnabled +//============================================================================= +// Description: Comment +// +// Parameters: none +// +// Return: bool +// +//============================================================================= +inline bool InputManager::IsRumbleEnabled() const +{ + return mIsRumbleEnabled; +} + + +#endif diff --git a/game/code/input/mappable.cpp b/game/code/input/mappable.cpp new file mode 100644 index 0000000..d0fc73f --- /dev/null +++ b/game/code/input/mappable.cpp @@ -0,0 +1,251 @@ +#include <input/mappable.h> + +#ifdef RAD_WIN32 +#include <input/usercontrollerWin32.h> +#else +#include <input/usercontroller.h> +#endif + +#include <input/inputmanager.h> + +#include <raddebug.hpp> + +Mappable::Mappable( unsigned active) + : +mButtonMask( 0 ), +mActiveMapper( 0 ), +mActiveState(active), +mActive(true), +mNeedResync(false) +{ +} + +Mappable::~Mappable( void ) +{ +} + +// Route the Button changes through the Active Mapper. +// +void Mappable::DispatchOnButton( int controllerId, int id, const Button* pButton ) +{ + if(!mActive) + { + return; + } + + // perform a lookup on this physical id and set state of the appropriate logical button + int destButtonID = GetActiveMapper( )->GetLogicalIndex(id); + + if ( destButtonID != Input::INVALID_CONTROLLERID && IsActive()) + { + // Grab the state of the button before we update the state. + bool bWasButtonDown = IsButtonDown( destButtonID ); + bool duplicate = mButton[ destButtonID ].TimeSinceChange() == 0; + + if(!duplicate || (duplicate && ( pButton->GetValue( ) >= mButton[ destButtonID].GetValue( ) ))) + { + UpdateButtonState( controllerId, destButtonID, pButton ); + + OnButton( controllerId, destButtonID, pButton ); + + if ( 0.0f == pButton->GetValue( ) ) + { + if ( bWasButtonDown ) + { + OnButtonUp( controllerId, destButtonID, pButton ); + } + } + else + { + if ( !bWasButtonDown ) + { + OnButtonDown( controllerId, destButtonID, pButton ); + } + } + } + } +} + +// load in a complete button state +// we only update the state, no edge-trigerred stuff (OnButton*) +void Mappable::InitButtons( int controllerId, const Button* pButtons ) +{ + for(unsigned int i = 0; i < Input::MaxPhysicalButtons; i++) + { + int destButtonID = GetActiveMapper( )->GetLogicalIndex(i); + + if ( destButtonID != Input::INVALID_CONTROLLERID ) + { + UpdateButtonState( controllerId, destButtonID, &pButtons[i] ); + } + } + +} + +void Mappable::OnControllerDisconnect( int id ) +{ + this->Reset(); +} + +void Mappable::OnControllerConnect( int id ) +{ +} + +// Update the internal variables that track the button state. +// Always tracks the button state, regardless of game state. +// OnButton will only be called in an active state. +// Values updated BEFORE OnButton is called. +// +void Mappable::UpdateButtonState( int controllerId, int buttonId, const Button* pButton ) +{ + if(!mActive) + { + return; + } + + unsigned int newButtonMask = 0; + unsigned int bit = 1 << buttonId; + + mButton[ buttonId ] = *pButton; + mButton[ buttonId ].ForceChange(); + + if ( 0.0f != mButton[ buttonId ].GetValue( ) ) + { + newButtonMask = bit | mButtonMask; + } + else + { + bit = ~bit; + newButtonMask = bit & mButtonMask; + } + mButtonMask = newButtonMask; +} + +// Returns the value of the logical output referenced by 'index'. +// +float Mappable::GetValue( unsigned int index ) const +{ + rAssert( index < Input::MaxLogicalButtons ); + if ( index < Input::MaxLogicalButtons ) + { + return mButton[ index ].GetValue( ); + } + + return 0.0f; +} + + +// Returns a const pointer to the Button at index. +// +Button* Mappable::GetButton( unsigned int index ) +{ + return &mButton [ index ]; +} + + +// To set up the different controller configurations. +// +void Mappable::SetControlMap( unsigned map ) +{ + mActiveMapper = map; +} + +// Returns the current control map enumeration value. +// +unsigned Mappable::GetControlMap( void ) const +{ + return mActiveMapper; +} + +// Returns a Mapper by index. +// +Mapper* Mappable::GetMapper( unsigned int index ) +{ + return &mMapper[ index ]; +} + +// Returns the Active mapper. +// +Mapper* Mappable::GetActiveMapper( void ) +{ + return &mMapper[ mActiveMapper ]; +} + +void Mappable::SetGameState(unsigned state) +{ + if(state & mActiveState) + { + mNeedResync = !mActive; + mActive = true; + } + else + { + mNeedResync = false; + mActive = false; + Reset(); + } +} + +// Is this mappable object active in this game state. +// +bool Mappable::IsActive( void ) const +{ + return mActive; +} + +// Is the button down? +// +bool Mappable::IsButtonDown( unsigned int id ) +{ + unsigned int bit = 1 << id; + return ( mButtonMask & bit ) != 0; +} + +// Is the button up? +// +bool Mappable::IsButtonUp( unsigned int id ) +{ + return !IsButtonDown( id ); +} + +// set up controller mappings. return false if cannot find name. +// +bool Mappable::Map( const char* pszName, int destination, unsigned int mapperIndex, unsigned int controllerId ) +{ + Mapper* pMapper = this->GetMapper( mapperIndex ); + //rValid( pMapper ); + + InputManager* pInputManager = InputManager::GetInstance( ); + rAssert( pInputManager ); + + const UserController* pUserController = pInputManager->GetController( controllerId ); + //rValid( pUserController ); + + int source = pUserController->GetIdByName( pszName ); + if ( source >=0 ) + { + pMapper->SetAssociation( source, destination ); + return true; + } + return false; +} + +// Clear all associations. +// +void Mappable::ClearMap( unsigned int mapperIndex ) +{ + Mapper* pMapper = GetMapper( mapperIndex ); + //rValid( pMapper ); + + pMapper->ClearAssociations( ); +} + +void Mappable::Reset( void ) +{ + for( unsigned int i = 0; i < Input::MaxLogicalButtons; i++) + { + mButton[i].SetValue(0.0f); + } + + mButtonMask = 0; +}
\ No newline at end of file diff --git a/game/code/input/mappable.h b/game/code/input/mappable.h new file mode 100644 index 0000000..23d7c17 --- /dev/null +++ b/game/code/input/mappable.h @@ -0,0 +1,138 @@ +#ifndef MAPPABLE_HPP_ +#define MAPPABLE_HPP_ + +#include <input/controller.h> +#include <input/button.h> +#include <input/mapper.h> + +#include <p3d/refcounted.hpp> + +struct ControlMap; +class UserController; + +class Mappable +: +public tRefCounted +{ +public: + Mappable( unsigned active = Input::ACTIVE_ALL & ~Input::ACTIVE_ANIM_CAM ); + + virtual ~Mappable( void ); + + //------------------------------------------- + //Stuff that derived classes should override + //------------------------------------------- + + // This method is called when ever a button is active (i.e. is non zero, or just went zero). + virtual void OnButton( int controllerId, int id, const Button* pButton ) = 0; + + // This method is called when a button changes state from "Pressed" to "Released". + virtual void OnButtonUp( int controllerId, int buttonId, const Button* pButton ) = 0; + + // This method is called when a button changes state from "Released" to "Pressed". + virtual void OnButtonDown( int controllerId, int buttonId, const Button* pButton ) = 0; + + // This is how we create our controller device mappings to logical game mappings. + // The mappings set up in this method are platform specific. + // + // The basic format of the calls is to "Map" a input, to a enumerated output id. + // The output of the specified input will be contained in the Button[] array. + // This id will also be sent as a the second parameter in the OnButton... messages. + virtual void LoadControllerMappings( unsigned int controllerId ) = 0; + + // should be overriden by dewrived calasses to do something if the controller + // attached to this mappable unplugs. + // there is a default implementation which does nothing. + virtual void OnControllerDisconnect( int id ); + + // should be overriden by dewrived calasses to do something if the controller + // attached to this mappable plugs in. + // there is a default implementation which does nothing. + virtual void OnControllerConnect( int id ); + + // --------------------- + // Regular functions + // --------------------- + + // Route the Button changes through the Mappers. + void DispatchOnButton( int controllerId, int id, const Button* pButton ); + + // load a complete physical button state + // This will set the internal state, but not generate any events (OnButton*) + void InitButtons( int controllerId, const Button* pButtons ); + + // Is the button down? + bool IsButtonDown( unsigned int id ); + + // Is the button up? + bool IsButtonUp( unsigned int id ); + + // Update the internal variables that track the button state. + // Always tracks the button state, regardless of game state. + // OnButton will only be called in an active state. + // Values updated BEFORE OnButton is called. + void UpdateButtonState( int controllerId, int id, const Button* pButton ); + + // set the current game state + void SetGameState(unsigned state); + + // Returns true if the mappable is active in the current game state. + bool IsActive( void ) const; + + // Returns the value of the logical output referenced by 'index'. + // Hint: make an enum with your own Logical Names. + float GetValue( unsigned int index ) const; + + // Returns a pointer to the Button at index. + Button* GetButton( unsigned int index ); + + // To set up the different controller configurations. + void SetControlMap( unsigned map ); + + // Returns the current control map enumeration value. + // + unsigned GetControlMap( void ) const; + + // Reset internal state (all vutton values go to 0) + void Reset( void ); + + bool GetResync(void) { return mNeedResync;} + void SetResync(bool b) { mNeedResync = b;} + + // Returns a Mapper by index. + // + Mapper* GetMapper( unsigned int index ); + +protected: + // set up controller mappings. return false if cannot find name. + // + bool Map( const char* pszName, int destination, unsigned int mapperIndex, unsigned int controllerId ); + + // Remove all associations. + // + void ClearMap( unsigned int mapperIndex ); + +private: + + // Returns the Active mapper. + // + Mapper* GetActiveMapper( void ); + // A 32 Bit button mask. + // + unsigned int mButtonMask; + + // State for all the (logical) buttons. + Button mButton[ Input::MaxLogicalButtons ]; + + // The button map. + Mapper mMapper[ Input::MaxMappings]; + + // The index of the currently active mapper. + unsigned mActiveMapper; + + unsigned mActiveState; + bool mActive; + bool mNeedResync; +}; + +#endif
\ No newline at end of file diff --git a/game/code/input/mapper.cpp b/game/code/input/mapper.cpp new file mode 100644 index 0000000..107749f --- /dev/null +++ b/game/code/input/mapper.cpp @@ -0,0 +1,39 @@ +#include <input/mapper.h> +#include <input/mappable.h> + +Mapper::Mapper( void ) +{ + ClearAssociations( ); +} + +int Mapper::SetAssociation( int sourceButtonID, int destButtonID ) +{ + buttonMap[sourceButtonID] = destButtonID; + return 0; +} + +int Mapper::GetLogicalIndex( int sourceButtonID ) const +{ + return buttonMap[sourceButtonID]; +} + +int Mapper::GetPhysicalIndex( int destButtonID ) const +{ + for ( unsigned i = 0; i < Input::MaxLogicalButtons; i++ ) + { + if ( buttonMap[i] == destButtonID) + { + return i; + } + } + return Input::INVALID_CONTROLLERID; +} + + +void Mapper::ClearAssociations( void ) +{ + for( unsigned int i = 0; i < Input::MaxLogicalButtons; i++) + { + buttonMap[i] = Input::INVALID_CONTROLLERID; + } +} diff --git a/game/code/input/mapper.h b/game/code/input/mapper.h new file mode 100644 index 0000000..4f93f5a --- /dev/null +++ b/game/code/input/mapper.h @@ -0,0 +1,40 @@ +#ifndef MAPPER_HPP +#define MAPPER_HPP + +#include <input/controller.h> +#include <input/button.h> + +class Mappable; + +// Holds mappings from physical inputs to logical inputs +// +// All inputs from controller system are passed through this table by the base Mappable +// class before being passed on to derived classes (for a particular gameplay state) +class Mapper +{ +public: + Mapper( void ); + + // Associate sourceButtonID with destButtonID. + int SetAssociation( int physicalIndex, int logicalIndex); + + // Remove all mappings. Set num associations to zero. + void ClearAssociations( void ); + + // Will return the physical button id ("X") associated with the logical + // input ("Gas"). Useful for controller config. + // Warning, could be miltiple mappings, it will only return the first one + int GetPhysicalIndex( int logicalIndex) const; + + // Will return the logical button id ("Gas") associated with the logical + // input ("X"). Useful for controller config. + int GetLogicalIndex( int physicalIndex ) const; + +private: + // Association structure and members + int buttonMap[Input::MaxPhysicalButtons]; +}; + + +#endif + diff --git a/game/code/input/rumbleeffect.cpp b/game/code/input/rumbleeffect.cpp new file mode 100644 index 0000000..8ecfcf4 --- /dev/null +++ b/game/code/input/rumbleeffect.cpp @@ -0,0 +1,464 @@ +//============================================================================= +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: rumbleeffect.cpp +// +// Description: Implement RumbleEffect +// +// History: 12/19/2002 + Created -- Cary Brisebois +// +//============================================================================= + +//======================================== +// System Includes +//======================================== +// Foundation Tech +#include <raddebug.hpp> +#include <raddebugwatch.hpp> + +//======================================== +// Project Includes +//======================================== +#include <input/rumbleeffect.h> + +//***************************************************************************** +// +// Global Data, Local Data, Local Classes +// +//***************************************************************************** +#ifdef DEBUGWATCH +int gRECount = -1; +#endif + +extern EffectValue VALUES[]; + +extern EffectValue DYNA_VALUES[]; + +float GAIN_FUDGE = 25.0f; + +//***************************************************************************** +// +// Public Member Functions +// +//***************************************************************************** + +//============================================================================= +// RumbleEffect::RumbleEffect +//============================================================================= +// Description: Constructor. +// +// Parameters: None. +// +// Return: N/A. +// +//============================================================================= +RumbleEffect::RumbleEffect() : + mWheelEffect( NULL ) +{ + unsigned int i; + for ( i = 0; i < Input::MaxOutputMotor; ++i ) + { + mMotors[ i ] = NULL; + mMotorUpdated[ i ] = false; + } + +#ifdef DEBUGWATCH + ++gRECount; + mEffectNum = gRECount; + char nameSpace[256]; + sprintf( nameSpace, "Controller\\RumbleEffect%d", mEffectNum ); + + char name[256]; + for ( i = 0; i < NUM_EFFECTS; ++i ) + { + sprintf( name, "%s Effect", VALUES[i].name ); + radDbgWatchAddUnsignedInt( &mCurrentEffects[i].mRumbleTimeLeft, name, nameSpace, NULL, NULL, 0, 100000 ); + } + + for ( i = 0; i < NUM_DYNA_EFFECTS; ++i ) + { + sprintf( name, "%s Dyna Effect", DYNA_VALUES[i].name ); + radDbgWatchAddUnsignedInt( &mCurrentDynaEffects[i].mRumbleTimeLeft, name, nameSpace, NULL, NULL, 0, 100000 ); + radDbgWatchAddFloat( &mCurrentDynaEffects[i].mMaxGain, name, nameSpace, NULL, NULL, 0.0f, 1.0f ); + } +#endif + + InitEffects(); +} + +//============================================================================= +// RumbleEffect::~RumbleEffect +//============================================================================= +// Description: Destructor. +// +// Parameters: None. +// +// Return: N/A. +// +//============================================================================= +RumbleEffect::~RumbleEffect() +{ + unsigned int i; + for ( i = 0; i < Input::MaxOutputMotor; ++i ) + { + if( mMotors[ i ] ) + { + mMotors[ i ]->Release(); + mMotors[ i ] = NULL; + } + } + +#ifdef DEBUGWATCH + gRECount--; + for ( i = 0; i < NUM_EFFECTS; ++i ) + { + radDbgWatchDelete( &mCurrentEffects[i].mRumbleTimeLeft ); + } + + for ( i = 0; i < NUM_DYNA_EFFECTS; ++i ) + { + radDbgWatchDelete( &mCurrentDynaEffects[i].mRumbleTimeLeft ); + radDbgWatchDelete( &mCurrentDynaEffects[i].mMaxGain ); + } +#endif + + ShutDownEffects(); +} + +//============================================================================= +// RumbleEffect::SetMotor +//============================================================================= +// Description: Comment +// +// Parameters: ( unsigned int whichMotor, IRadControllerOutputPoint* motor ) +// +// Return: void +// +//============================================================================= +void RumbleEffect::SetMotor( unsigned int whichMotor, IRadControllerOutputPoint* motor ) +{ + rAssert( whichMotor < Input::MaxOutputMotor ); + + if ( mMotors[ whichMotor ] ) + { + mMotors[ whichMotor ]->Release(); + } + + mMotors[ whichMotor ] = motor; + mMotors[ whichMotor ]->AddRef(); +} + +//============================================================================= +// RumbleEffect::SetEffect +//============================================================================= +// Description: Comment +// +// Parameters: ( Effect effect, unsigned int milliseconds ) +// +// Return: void +// +//============================================================================= +void RumbleEffect::SetEffect( Effect effect, unsigned int milliseconds ) +{ + if ( mCurrentEffects[ effect ].mRumbleTimeLeft < milliseconds ) + { + mCurrentEffects[ effect ].mRumbleTimeLeft = milliseconds; + } +} + +//============================================================================= +// RumbleEffect::SetDynaEffect +//============================================================================= +// Description: Comment +// +// Parameters: ( DynaEffect effect, unsigned int milliseconds, float gain ) +// +// Return: void +// +//============================================================================= +void RumbleEffect::SetDynaEffect( DynaEffect effect, unsigned int milliseconds, float gain ) +{ + if ( mCurrentDynaEffects[ effect ].mRumbleTimeLeft < milliseconds ) + { + mCurrentDynaEffects[ effect ].mRumbleTimeLeft = milliseconds; + + if ( gain > 1.0f ) + { + gain = 1.0f; + } + + mCurrentDynaEffects[ effect ].mMaxGain = gain * GAIN_FUDGE; + +#ifdef RAD_GAMECUBE + if ( gain * GAIN_FUDGE < 0.3f ) + { + mCurrentDynaEffects[ effect ].mMaxGain = 0; + } +#endif + } +} + +//============================================================================= +// RumbleEffect::Update +//============================================================================= +// Description: Comment +// +// Parameters: ( unsigned int milliseconds ) +// +// Return: void +// +//============================================================================= +void RumbleEffect::Update( unsigned int milliseconds ) +{ + //The heaviest effect with time left is the one that runs. + Effect currentEffect = NUM_EFFECTS; + + unsigned int i; + + //Update all the effects. + for ( i = 0; i < NUM_EFFECTS; ++i ) + { + if ( mCurrentEffects[ i ].mRumbleTimeLeft <= milliseconds ) + { + if ( mCurrentEffects[ i ].mRumbleTimeLeft > 0 ) + { + UpdateEffect( static_cast<Effect>(i), mCurrentEffects[ i ].mRumbleTimeLeft ); + } + + mCurrentEffects[ i ].mRumbleTimeLeft = 0; + } + else + { + mCurrentEffects[ i ].mRumbleTimeLeft -= milliseconds; + + UpdateEffect( static_cast<Effect>(i), milliseconds ); + } + } + + for ( i = 0; i < NUM_DYNA_EFFECTS; ++i ) + { + if ( mCurrentDynaEffects[ i ].mRumbleTimeLeft <= milliseconds ) + { + if ( mCurrentDynaEffects[ i ].mRumbleTimeLeft > 0 ) + { + UpdateDynaEffect( static_cast<DynaEffect>(i), mCurrentDynaEffects[ i ].mRumbleTimeLeft, mCurrentDynaEffects[ i ].mMaxGain ); + } + + mCurrentDynaEffects[ i ].mRumbleTimeLeft = 0; + } + else + { + mCurrentDynaEffects[ i ].mRumbleTimeLeft -= milliseconds; + + UpdateDynaEffect( static_cast<DynaEffect>(i), milliseconds, mCurrentDynaEffects[ i ].mMaxGain ); + } + } + + for ( i = 0; i < Input::MaxOutputMotor; ++i ) + { + //You only update a motor when you want to give it a positive value. + if ( !mMotorUpdated[ i ] ) + { + if ( mMotors[ i ]&& mMotors[ i ]->GetGain() > 0.0f ) + { +#ifdef RAD_GAMECUBE + mMotors[ i ]->SetGain( -1.0f ); //This stops the motor HARD +#else + mMotors[ i ]->SetGain( 0.0f ); +#endif + } + } + + //Reset them all. + mMotorUpdated[ i ] = false; + } +} + +//============================================================================= +// RumbleEffect::ShutDownEffects +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: void +// +//============================================================================= +void RumbleEffect::ShutDownEffects() +{ + unsigned int i; + for ( i = 0; i < NUM_EFFECTS; ++i ) + { + mCurrentEffects[ i ].mRumbleTimeLeft = 0; + } + + for ( i = 0; i < Input::MaxOutputMotor; ++i ) + { + if ( mMotors[ i ] && mMotors[ i ]->GetGain() > 0.0f ) + { +#ifdef RAD_GAMECUBE + mMotors[ i ]->SetGain( -1.0f ); //This stops the motor HARD +#else + mMotors[ i ]->SetGain( 0.0f ); +#endif + } + } + + OnShutDownEffects(); +} + +//***************************************************************************** +// +// Private Member Functions +// +//***************************************************************************** + +//============================================================================= +// RumbleEffect::UpdateEffect +//============================================================================= +// Description: Comment +// +// Parameters: ( Effect effect, unsigned int milliseconds ) +// +// Return: void +// +//============================================================================= +void RumbleEffect::UpdateEffect( Effect effect, unsigned int milliseconds ) +{ + if ( mCurrentEffects[ effect ].mRumbleTimeLeft % VALUES[effect].pulseTime < 32 ) //We use 32 because we hope to only do this once a frame (or twice) + { + if ( mMotors[ VALUES[effect].motor ] ) + { + float currMotorGain = mMotors[ VALUES[effect].motor ]->GetGain(); + float desiredGain = VALUES[effect].gain; + + if ( currMotorGain < desiredGain ) + { + mMotors[ VALUES[effect].motor ]->SetGain( VALUES[effect].gain ); + mMotorUpdated[ VALUES[effect].motor ] = true; + } +#ifdef RAD_GAMECUBE + // Michael Riegger - Gamecube is different from other platforms in rumble + // control in that motor control is basically turn on / turn off commands + // and that rumble just 'goes' in between those commands. No need to + // toggle on and off manually + // so set the updated flag to true always if its where we want. Otherwise + // gain will be reset to 0 or -1 automatically + else if ( currMotorGain == desiredGain ) + { + mMotorUpdated[ VALUES[effect].motor ] = true; + } +#endif + } + } + /* if ( mCurrentEffects[ effect ].mRumbleTimeLeft % VALUES[effect].pulseTime < 32 ) //We use 32 because we hope to only do this once a frame (or twice) + { + if ( mMotors[ VALUES[effect].motor ] ) + { + + + if ( currMotorGain == desiredGain ) + { + mMotorUpdated[ VALUES[effect].motor ] = true; + } + else if ( currMotorGain < desiredGain ) + { + mMotors[ VALUES[effect].motor ]->SetGain( VALUES[effect].gain ); + mMotorUpdated[ VALUES[effect].motor ] = true; + } + } + }*/ +} + +//============================================================================= +// RumbleEffect::UpdateDynaEffect +//============================================================================= +// Description: Comment +// +// Parameters: ( DynaEffect effect, unsigned int milliseconds, float gain ) +// +// Return: void +// +//============================================================================= +void RumbleEffect::UpdateDynaEffect( DynaEffect effect, unsigned int milliseconds, float gain ) //This is a pcnt +{ + if ( mCurrentDynaEffects[ effect ].mRumbleTimeLeft % DYNA_VALUES[effect].pulseTime < 32 ) //We use 32 because we hope to only do this once a frame (or twice) + { + if ( mMotors[ DYNA_VALUES[effect].motor ] && + mMotors[ DYNA_VALUES[effect].motor ]->GetGain() < DYNA_VALUES[effect].gain * gain ) + { + mMotors[ DYNA_VALUES[effect].motor ]->SetGain( DYNA_VALUES[effect].gain * gain ); + mMotorUpdated[ DYNA_VALUES[effect].motor ] = true; + } + } +} + + +//============================================================================= +// RumbleEffect::InitEffects +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: void +// +//============================================================================= +void RumbleEffect::InitEffects() +{ +#ifdef DEBUGWATCH + if ( gRECount == 0 ) + { + char name[256]; + unsigned int i; + for ( i = 0; i < NUM_EFFECTS; ++i ) + { + sprintf( name, "Controller\\%s Effect", VALUES[i].name ); + radDbgWatchAddUnsignedInt( &VALUES[i].pulseTime, "PulseTime", name, NULL, NULL, 1, 1000 ); + radDbgWatchAddFloat( &VALUES[i].gain, "Gain", name, NULL, NULL, 0.0f, 1.0f ); + radDbgWatchAddChar( &VALUES[i].motor, "Motor", name, NULL, NULL, 0, 1 ); + } + + for ( i = 0; i < NUM_DYNA_EFFECTS; ++i ) + { + sprintf( name, "Controller\\%s Dyna Effect", VALUES[i].name ); + radDbgWatchAddUnsignedInt( &DYNA_VALUES[i].pulseTime, "PulseTime", name, NULL, NULL, 1, 1000 ); + radDbgWatchAddFloat( &DYNA_VALUES[i].gain, "Gain", name, NULL, NULL, 0.0f, 1.0f ); + radDbgWatchAddChar( &DYNA_VALUES[i].motor, "Motor", name, NULL, NULL, 0, 1 ); + } + } +#endif +} + +//============================================================================= +// RumbleEffect::OnShutDownEffects +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: void +// +//============================================================================= +void RumbleEffect::OnShutDownEffects() +{ +#ifdef DEBUGWATCH + if ( gRECount == -1 ) + { + unsigned int i; + for ( i = 0; i < NUM_EFFECTS; ++i ) + { + radDbgWatchDelete( &VALUES[i].pulseTime ); + radDbgWatchDelete( &VALUES[i].gain ); + radDbgWatchDelete( &VALUES[i].motor ); + } + + for ( i = 0; i < NUM_DYNA_EFFECTS; ++i ) + { + radDbgWatchDelete( &DYNA_VALUES[i].pulseTime ); + radDbgWatchDelete( &DYNA_VALUES[i].gain ); + radDbgWatchDelete( &DYNA_VALUES[i].motor ); + } + } +#endif +}
\ No newline at end of file diff --git a/game/code/input/rumbleeffect.h b/game/code/input/rumbleeffect.h new file mode 100644 index 0000000..bd5746d --- /dev/null +++ b/game/code/input/rumbleeffect.h @@ -0,0 +1,116 @@ +//============================================================================= +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: rumbleeffect.h +// +// Description: Blahblahblah +// +// History: 12/19/2002 + Created -- Cary Brisebois +// +//============================================================================= + +#ifndef RUMBLEEFFECT_H +#define RUMBLEEFFECT_H + +//======================================== +// Nested Includes +//======================================== +#include <radcontroller.hpp> + +#include <input/controller.h> + +//======================================== +// Forward References +//======================================== + +//============================================================================= +// +// Synopsis: Blahblahblah +// +//============================================================================= + +struct EffectValue +{ + unsigned int pulseTime; + float gain; + char motor; + const char* name; +}; + +class RumbleEffect +{ +public: + enum Effect + { + LIGHT, + MEDIUM, + HARD1, + HARD2, + GROUND1, + GROUND2, + GROUND3, + GROUND4, + PULSE, + NUM_EFFECTS + }; + + enum DynaEffect + { + COLLISION1, + COLLISION2, + NUM_DYNA_EFFECTS + }; + + RumbleEffect(); + virtual ~RumbleEffect(); + + void SetWheelEffect( IRadControllerOutputPoint* wheelEffect ); + void SetMotor( unsigned int whichMotor, IRadControllerOutputPoint* motor ); + void SetEffect( Effect effect, unsigned int milliseconds ); + void SetDynaEffect( DynaEffect effect, unsigned int milliseconds, float gain ); + + void Update( unsigned int milliseconds ); + void ShutDownEffects(); + +private: + IRadControllerOutputPoint* mWheelEffect; + IRadControllerOutputPoint* mMotors[ Input::MaxOutputMotor ]; + bool mMotorUpdated[ Input::MaxOutputMotor ]; + + struct EffectInfo + { + EffectInfo() : mRumbleTimeLeft( 0 ) {}; + unsigned int mRumbleTimeLeft; + }; + + EffectInfo mCurrentEffects[ NUM_EFFECTS ]; + + struct DynaEffectInfo : public EffectInfo + { + DynaEffectInfo() : mMaxGain( 1.0f ) {}; + float mMaxGain; + }; + + DynaEffectInfo mCurrentDynaEffects[ NUM_DYNA_EFFECTS ]; + +#ifdef DEBUGWATCH + int mEffectNum; +#endif + + void InitEffects(); + void UpdateEffect( Effect effect, unsigned int milliseconds ); + void UpdateDynaEffect( DynaEffect effect, unsigned int milliseconds, float gain ); + void OnShutDownEffects(); + + //Prevent wasteful constructor creation. + RumbleEffect( const RumbleEffect& rumbleeffect ); + RumbleEffect& operator=( const RumbleEffect& rumbleeffect ); +}; + +//***************************************************************************** +// +//Inline Public Member Functions +// +//***************************************************************************** + +#endif //RUMBLEEFFECT_H diff --git a/game/code/input/rumblegc.cpp b/game/code/input/rumblegc.cpp new file mode 100644 index 0000000..9de065b --- /dev/null +++ b/game/code/input/rumblegc.cpp @@ -0,0 +1,49 @@ +#include <raddebug.hpp> +#include <raddebugwatch.hpp> + +#include <input/rumbleeffect.h> + +#ifdef DEBUGWATCH +extern int gRECount; +#endif + +EffectValue VALUES[] = +{ + // timeout gain motor name - Note: Do not change motor here! It is platform specific. + { 1, 0.6f, 0, "Light" }, + { 1, 0.8f, 0, "Med" }, + { 1, 1.0f, 0, "Hard1" }, + { 1, 1.0f, 0, "Hard2" }, + { 100, 0.3f, 0, "Ground 1" }, + { 120, 0.4f, 0, "Ground 2" }, + { 150, 0.35f, 0, "Ground 3" }, + { 120, 0.35f, 0, "Ground 4" }, + { 1, 1.0f, 0, "Pulse" }, +}; + +EffectValue DYNA_VALUES[] = +{ + // timeout gain motor name - Note: Do not change motor here! It is platform specific. + { 1, 1.0f, 0, "Collision1" }, + { 1, 1.0f, 0, "Collision2" } +}; + +//============================================================================= +// RumbleEffect::SetWheelEffect +//============================================================================= +// Description: Comment +// +// Parameters: ( IRadControllerOutputPoint* wheelEffect ) +// +// Return: void +// +//============================================================================= +void RumbleEffect::SetWheelEffect( IRadControllerOutputPoint* wheelEffect ) +{ +} + +//***************************************************************************** +// +//Private Member Functions +// +//***************************************************************************** diff --git a/game/code/input/rumbleps2.cpp b/game/code/input/rumbleps2.cpp new file mode 100644 index 0000000..5b15999 --- /dev/null +++ b/game/code/input/rumbleps2.cpp @@ -0,0 +1,44 @@ +#include <raddebug.hpp> +#include <raddebugwatch.hpp> + +#include <input/rumbleeffect.h> + +#ifdef DEBUGWATCH +extern int gRECount; +#endif + +EffectValue VALUES[] = +{ + // timeout gain motor name - Note: Do not change motor here! It is platform specific. + { 1, 0.6f, 1, "Light" }, + { 1, 0.8f, 1, "Med" }, + { 1, 1.0f, 1, "Hard1" }, + { 1, 1.0f, 0, "Hard2" }, + { 100, 0.3f, 1, "Ground 1" }, + { 120, 0.4f, 1, "Ground 2" }, + { 150, 0.35f, 1, "Ground 3" }, + { 120, 0.35f, 1, "Ground 4" }, + { 1, 1.0f, 0, "Pulse" }, +}; + +EffectValue DYNA_VALUES[] = +{ + // timeout gain motor name - Note: Do not change motor here! It is platform specific. + { 1, 1.0f, 0, "Collision1" }, + { 1, 1.0f, 1, "Collision2" } +}; + + +//============================================================================= +// RumbleEffect::SetWheelEffect +//============================================================================= +// Description: Comment +// +// Parameters: ( IRadControllerOutputPoint* wheelEffect ) +// +// Return: void +// +//============================================================================= +void RumbleEffect::SetWheelEffect( IRadControllerOutputPoint* wheelEffect ) +{ +}
\ No newline at end of file diff --git a/game/code/input/rumblewin32.cpp b/game/code/input/rumblewin32.cpp new file mode 100644 index 0000000..963b607 --- /dev/null +++ b/game/code/input/rumblewin32.cpp @@ -0,0 +1,68 @@ +//============================================================================= +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: rumblewin32.cpp +// +// Description: Implementation of rumble for win. This is probably just a +// dummy file.. we need to define some constants for rumble to +// compile, but who knows if we'll need them. +// +// History: 03/04/2003 + Created -- ziemek +// +//============================================================================= + +//======================================== +// System Includes +//======================================== + +#include <raddebug.hpp> +#include <raddebugwatch.hpp> + +#include <input/rumbleeffect.h> + +#ifdef DEBUGWATCH +extern int gRECount; +#endif + +EffectValue VALUES[] = +{ + // timeout gain motor name - Note: Do not change motor here! It is platform specific. + { 1, 0.6f, 1, "Light" }, + { 1, 0.8f, 1, "Med" }, + { 1, 1.0f, 1, "Hard1" }, + { 1, 1.0f, 0, "Hard2" }, + { 100, 0.3f, 1, "Ground 1" }, + { 120, 0.4f, 1, "Ground 2" }, + { 150, 0.35f, 1, "Ground 3" }, + { 120, 0.35f, 1, "Ground 4" }, + { 1, 1.0f, 0, "Pulse" }, +}; + +EffectValue DYNA_VALUES[] = +{ + // timeout gain motor name - Note: Do not change motor here! It is platform specific. + { 1, 1.0f, 0, "Collision1" }, + { 1, 1.0f, 1, "Collision2" } +}; + + +//============================================================================= +// RumbleEffect::SetWheelEffect +//============================================================================= +// Description: Comment +// +// Parameters: ( IRadControllerOutputPoint* wheelEffect ) +// +// Return: void +// +//============================================================================= +void RumbleEffect::SetWheelEffect( IRadControllerOutputPoint* wheelEffect ) +{ +} + +//***************************************************************************** +// +//Private Member Functions +// +//***************************************************************************** + diff --git a/game/code/input/rumblexbox.cpp b/game/code/input/rumblexbox.cpp new file mode 100644 index 0000000..276351b --- /dev/null +++ b/game/code/input/rumblexbox.cpp @@ -0,0 +1,51 @@ +#include <raddebug.hpp> +#include <raddebugwatch.hpp> + +#include <input/rumbleeffect.h> + +#ifdef DEBUGWATCH +extern int gRECount; +#endif + +EffectValue VALUES[] = +{ + // timeout gain motor name - Note: Do not change motor here! It is platform specific. + { 1, 0.6f, 0, "Light" }, + { 1, 0.8f, 0, "Med" }, + { 1, 1.0f, 0, "Hard1" }, + { 1, 1.0f, 1, "Hard2" }, + { 100, 0.9f, 1, "Ground 1" }, + { 120, 1.0f, 1, "Ground 2" }, + { 150, 0.95f, 1, "Ground 3" }, + { 120, 0.95f, 1, "Ground 4" }, + { 1, 1.0f, 1, "Pulse" }, +}; + +EffectValue DYNA_VALUES[] = +{ + // timeout gain motor name - Note: Do not change motor here! It is platform specific. + { 1, 1.0f, 1, "Collision1" }, + { 1, 1.0f, 1, "Collision2" } +}; + + +//============================================================================= +// RumbleEffect::SetWheelEffect +//============================================================================= +// Description: Comment +// +// Parameters: ( IRadControllerOutputPoint* wheelEffect ) +// +// Return: void +// +//============================================================================= +void RumbleEffect::SetWheelEffect( IRadControllerOutputPoint* wheelEffect ) +{ +} + +//***************************************************************************** +// +//Private Member Functions +// +//***************************************************************************** + diff --git a/game/code/input/steeringspring.cpp b/game/code/input/steeringspring.cpp new file mode 100644 index 0000000..d78d4f0 --- /dev/null +++ b/game/code/input/steeringspring.cpp @@ -0,0 +1,187 @@ +//============================================================================= +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: SteeringSpring.cpp +// +// Description: Implement SteeringSpring +// +// History: 10/21/2002 + Created -- Cary Brisebois +// Modified -- Neil Haran +// +//============================================================================= + +//======================================== +// System Includes +//======================================== +// Foundation Tech +#include <raddebug.hpp> + +//======================================== +// Project Includes +//======================================== +#include <input/SteeringSpring.h> +#include <input/wheeldefines.h> + +//****************************************************************************** +// +// Global Data, Local Data, Local Classes +// +//****************************************************************************** + +//****************************************************************************** +// +// Public Member Functions +// +//****************************************************************************** + +//============================================================================== +// SteeringSpring::SteeringSpring +//============================================================================== +// Description: Constructor. +// +// Parameters: None. +// +// Return: N/A. +// +//============================================================================== +SteeringSpring::SteeringSpring() +{ + //Setup the respective force effect structures. +#ifdef RAD_WIN32 + m_conditon.lOffset = 0; + m_conditon.lDeadBand = 0; + m_conditon.lPositiveCoefficient = 127; + m_conditon.lNegativeCoefficient = 127; + m_conditon.dwPositiveSaturation = 127; + m_conditon.dwNegativeSaturation = 127; + + mForceEffect.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + mForceEffect.dwDuration = INFINITE; + mForceEffect.dwGain = DI_FFNOMINALMAX; + mForceEffect.dwTriggerButton = DIEB_NOTRIGGER; + mForceEffect.cAxes = 1; + mForceEffect.rgdwAxes = m_rgdwAxes; + mForceEffect.rglDirection = m_rglDirection; + mForceEffect.lpEnvelope = NULL; + mForceEffect.cbTypeSpecificParams = sizeof(DICONDITION); + mForceEffect.lpvTypeSpecificParams = &m_conditon; + mForceEffect.dwStartDelay = 0; +#else + mForceEffect.type = LG_TYPE_SPRING; + mForceEffect.duration = LG_DURATION_INFINITE; + mForceEffect.startDelay = 0; + mForceEffect.p.condition[0].offset = 0; + mForceEffect.p.condition[0].deadband = 0; + mForceEffect.p.condition[0].saturationNeg = 127; + mForceEffect.p.condition[0].saturationPos = 127; + mForceEffect.p.condition[0].coefficientNeg = 127; + mForceEffect.p.condition[0].coefficientPos = 127; +#endif +} + +//============================================================================== +// SteeringSpring::~SteeringSpring +//============================================================================== +// Description: Destructor. +// +// Parameters: None. +// +// Return: N/A. +// +//============================================================================== +SteeringSpring::~SteeringSpring() +{ +} + +//============================================================================= +// SteeringSpring::OnInit +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: void +// +//============================================================================= +void SteeringSpring::OnInit() +{ +} + +//============================================================================= +// SteeringSpring::SetCenterPoint +//============================================================================= +// Description: Comment +// +// Parameters: ( s8 point, u8 deadband ) +// +// Return: void +// +//============================================================================= +void SteeringSpring::SetCenterPoint( s8 point, u8 deadband ) +{ +#ifdef RAD_WIN32 + m_conditon.lOffset = point; + m_conditon.lDeadBand = deadband; +#else + mForceEffect.p.condition[0].offset = point; + mForceEffect.p.condition[0].deadband = deadband; +#endif + mEffectDirty = true; +} + +//============================================================================= +// SteeringSpring::SetSpringStrength +//============================================================================= +// Description: Comment +// +// Parameters: ( u8 strength ) +// +// Return: void +// +//============================================================================= +#ifdef RAD_WIN32 +void SteeringSpring::SetSpringStrength( u16 strength ) +#else +void SteeringSpring::SetSpringStrength( u8 strength ) +#endif +{ +#ifdef RAD_WIN32 + m_conditon.dwPositiveSaturation = strength; + m_conditon.dwNegativeSaturation = strength; +#else + mForceEffect.p.condition[0].saturationNeg = strength; + mForceEffect.p.condition[0].saturationPos = strength; +#endif + + mEffectDirty = true; +} + +//============================================================================= +// SteeringSpring::SetSpringCoefficient +//============================================================================= +// Description: Comment +// +// Parameters: ( s16 coeff ) +// +// Return: void +// +//============================================================================= +void SteeringSpring::SetSpringCoefficient( s16 coeff ) +{ +#ifdef RAD_WIN32 + m_conditon.lPositiveCoefficient = coeff; + m_conditon.lNegativeCoefficient = coeff; +#else + mForceEffect.p.condition[0].coefficientNeg = coeff; + mForceEffect.p.condition[0].coefficientPos = coeff; +#endif + + mEffectDirty = true; +} + + +//****************************************************************************** +// +// Private Member Functions +// +//****************************************************************************** diff --git a/game/code/input/steeringspring.h b/game/code/input/steeringspring.h new file mode 100644 index 0000000..d28530f --- /dev/null +++ b/game/code/input/steeringspring.h @@ -0,0 +1,59 @@ +//============================================================================= +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: steeringspring.h +// +// Description: Blahblahblah +// +// History: 10/19/2002 + Created -- Cary Brisebois +// +//============================================================================= + +#ifndef STEERINGSPRING_H +#define STEERINGSPRING_H + +//======================================== +// Nested Includes +//======================================== +#include <radcontroller.hpp> +#include <input/forceeffect.h> + +//======================================== +// Forward References +//======================================== + +//============================================================================= +// +// Synopsis: Blahblahblah +// +//============================================================================= + +class SteeringSpring : public ForceEffect +{ +public: + SteeringSpring(); + virtual ~SteeringSpring(); + + void OnInit(); + void SetCenterPoint( s8 degrees, u8 deadband ); //Where 0 is straight up. +#ifdef RAD_WIN32 + void SetSpringStrength( u16 strength ); +#else + void SetSpringStrength( u8 strength ); +#endif + void SetSpringCoefficient( s16 coeff ); + +private: + +#ifdef RAD_WIN32 + DICONDITION m_conditon; +#endif + //Prevent wasteful constructor creation. + SteeringSpring( const SteeringSpring& steeringspring ); + SteeringSpring& operator=( const SteeringSpring& steeringspring ); +}; + + +#endif //STEERINGSPRING_H + + diff --git a/game/code/input/usercontroller.cpp b/game/code/input/usercontroller.cpp new file mode 100644 index 0000000..e740374 --- /dev/null +++ b/game/code/input/usercontroller.cpp @@ -0,0 +1,726 @@ +#include <input/usercontroller.h> +#include <input/mappable.h> +#include <input/mapper.h> +#include <input/button.h> + +#include <radcontroller.hpp> +#include <raddebug.hpp> +#include <radmath/radmath.hpp> + +#if defined(RAD_PS2) || defined(RAD_GAMECUBE) +#include <input/wheeldefines.h> +#endif + + + +#ifndef WORLD_BUILDER +#include <main/commandlineoptions.h> +#endif + +#ifdef WORLD_BUILDER +#ifdef CONTROLLER_DEBUG +#undef CONTROLLER_DEBUG +#endif +enum { CLO_NO_HAPTIC, CLO_RANDOM_BUTTONS }; +namespace CommandLineOptions +{ + static bool Get( int i ) { return false; }; +}; +#endif + +// We use ::strcmp() +// +#include <string.h> + +#include <raddebugwatch.hpp> +#ifdef DEBUGWATCH +#include <input/inputmanager.h> + + +struct ButtonData +{ + ButtonData() : controllerID( -1 ), button( -1 ), range( 1.0f ) {}; + int controllerID; + int button; + float range; +}; + +static ButtonData gData[Input::MaxPhysicalButtons]; + +void ButtonCallback( void* userData ) +{ + ButtonData* data = static_cast<ButtonData*>( userData ); + + if ( data->button != Input::INVALID_CONTROLLERID ) + { + UserController* controller = GetInputManager()->GetController( data->controllerID ); + + Button* button = controller->GetInputButton( data->button ); + button->SetValue( 1.0f ); + button->ForceChange(); + + for ( unsigned j = 0; j < Input::MaxMappables; j++ ) + { + Mappable* mappable = controller->GetMappable( j ); + if ( mappable ) + { + mappable->DispatchOnButton( data->controllerID, data->button, button ); + } + } + + button->SetValue( 0.0f ); + button->ForceChange(); + + for ( unsigned j = 0; j < Input::MaxMappables; j++ ) + { + Mappable* mappable = controller->GetMappable( j ); + if ( mappable ) + { + mappable->DispatchOnButton( data->controllerID, data->button, button ); + } + } + } +} + +#endif + +//This enables the random button pressing. +#define CONTROLLER_DEBUG +#ifdef CONTROLLER_DEBUG + +#define MAX_BUTTON_TIME 3000 +#define MAX_BUTTON_PRESSES 8 +struct RandomButton +{ + RandomButton() : + mRandomButtonEnable( false ), + mRandomButtonTiming( 0 ), + mRadomizeButtonTiming( false ), + mButtonTimeout( 0 ), + mMaxButtons( MAX_BUTTON_PRESSES ), + mCurrentButton( 0 ) + { + int i; + for ( i = 0; i < MAX_BUTTON_PRESSES; ++i ) + { + mLastButton[ i ] = -1; + } + } + + bool mRandomButtonEnable; + unsigned int mRandomButtonTiming; + bool mRadomizeButtonTiming; + int mButtonTimeout; + int mLastButton[ MAX_BUTTON_PRESSES ]; + unsigned int mMaxButtons; + unsigned int mCurrentButton; +}; + +RandomButton gRandomButtoners[ Input::MaxControllers ]; + +#endif + +//****************************************************************************** +// +// Constructors, Destructors and Operators +// +//****************************************************************************** +UserController::UserController( ) +: +m_iPlayerIndex( -1 ), +m_xIController2( NULL ), +m_controllerId( -1 ), +m_bConnected( false ), +mbInputPointsRegistered( false ), +mGameState( Input::ACTIVE_ALL ), +mbIsRumbleOn( false ) +{ + unsigned int i = 0; + for ( i = 0; i < Input::MaxMappables; i++ ) + { + this->mMappable[ i ] = 0; + } + +#if defined(RAD_PS2) || defined(RAD_GAMECUBE) + mHeavyWheelRumble.SetRumbleType( LG_TYPE_SQUARE ); +#endif +} + +void UserController::NotifyConnect( void ) +{ + if ( !IsConnected( ) ) + { + m_bConnected = true; + + for ( unsigned int i = 0; i < Input::MaxMappables; i++ ) + { + if (mMappable[ i ]) + mMappable[ i ]->OnControllerConnect( GetControllerId( ) ); + } + } +} +void UserController::NotifyDisconnect( void ) +{ + if ( IsConnected( ) ) + { + m_bConnected = false; + + for ( unsigned int i = 0; i < Input::MaxMappables; i++ ) + { + if (mMappable[ i ]) + mMappable[ i ]->OnControllerDisconnect( GetControllerId( ) ); + } + } +} + +void UserController::Create( int id ) +{ + m_controllerId = id; +} + +void UserController::SetGameState( unsigned state) +{ + mGameState = state; + for ( unsigned i = 0; i < Input::MaxMappables; i++ ) + { + if(mMappable[ i ]) + { + mMappable[ i ]->SetGameState( state ); + + // if the game state change involved and inactive mappable being activated + // wwe need to reload the current button state + if(mMappable[ i ]->GetResync()) + { + mMappable[ i ]->InitButtons( m_controllerId, mButtonArray); + mMappable[ i ]->SetResync(false); + } + } + } +} + +void UserController::OnControllerInputPointChange( unsigned int buttonId, float value ) +{ + // We need to query the input point directly to get the value + // remapped to the requested range. + + float fLastValue = mButtonArray[ buttonId ].GetValue( ); + float fDeadZone = mButtonDeadZones[buttonId]; + + value = m_xIController2->GetInputPointByIndex( buttonId )->GetCurrentValue( ); + + if ( rmt::Epsilon( value, 0.0f, fDeadZone ) ) + { + value = 0.0f; + } + else + { + float sign = rmt::Sign( value ); + float calibratedButtonData = rmt::Fabs( value ) - fDeadZone; + calibratedButtonData *= 1.0f / ( 1.0f - fDeadZone ); + calibratedButtonData *= sign; + bool bChanged = !( rmt::Epsilon( fLastValue, calibratedButtonData, 0.05f ) ); + + if ( bChanged ) + { + // go with the deadzone corrected value. + value = calibratedButtonData; + } + else + { + // restore the old deadzone corrected value. + value = fLastValue; + } + } + + mButtonArray[ buttonId ].SetValue( value ); +} + +void UserController::Initialize( IRadController* pIController2 ) +{ + // if we are being called while initialized, something is wrong + rAssert(!mbInputPointsRegistered && !m_xIController2); + + m_xIController2 = pIController2; + + if( !mbInputPointsRegistered && m_xIController2 != NULL ) + { + // register input point callbacks + unsigned int i; + + for( i = 0; i < Input::MaxPhysicalButtons; i++ ) + { + mButtonNames[i] = 0; + } + + // get number of input points on controller + mNumButtons = m_xIController2->GetNumberOfInputPoints(); + rAssert(mNumButtons < Input::MaxPhysicalButtons); + + // register all input points + for( i = 0; i < mNumButtons; i++ ) + { + IRadControllerInputPoint* pInputPoint = m_xIController2->GetInputPointByIndex( i ); + if( pInputPoint != NULL ) + { + const char* inputPointType = pInputPoint->GetType(); + + if( ::strcmp( inputPointType, "Button" ) == 0 ) + { + pInputPoint->SetTolerance( 1.0f ); + mButtonDeadZones[ i ] = 0.0f; + } + else if( strcmp( inputPointType, "XAxis" ) == 0 + || strcmp( inputPointType, "YAxis" ) == 0) + { + pInputPoint->SetTolerance( 0.01f ); + pInputPoint->SetRange( -1.0f, 1.0f ); + + if ( strcmp( pInputPoint->GetName(), "Wheel" ) == 0 ) + { + mButtonDeadZones[ i ] = 0.025f; + } + else + { + mButtonDeadZones[ i ] = 0.25f; + } + } + else // Analog? + { + pInputPoint->SetTolerance( 0.01f ); + pInputPoint->SetRange( 0.0f, 1.0f ); + mButtonDeadZones[ i ] = 0.0f; + } + mButtonNames[ i ] = radMakeKey(pInputPoint->GetName( ) ); + pInputPoint->RegisterControllerInputPointCallback( static_cast< IRadControllerInputPointCallback* >( this ), i ); + + // [ps] Initialize the input points + OnControllerInputPointChange( i , pInputPoint->GetCurrentValue( ) ); + +#ifdef DEBUGWATCH + char name[64]; + sprintf( name, "%s Button", pInputPoint->GetName() ); + char nameSpace[64]; + sprintf( nameSpace, "Controller\\Input%d", m_controllerId ); + gData[m_controllerId].controllerID = m_controllerId; + gData[m_controllerId].button = static_cast<InputManager::eButtonMap>(i); + float min, max; + pInputPoint->GetRange( &min, &max ); + gData[m_controllerId].range = max; + radDbgWatchAddFunction( name, &ButtonCallback, &gData[m_controllerId], nameSpace ); +#endif + } + } + + mbInputPointsRegistered = true; + +#if defined(RAD_GAMECUBE) || defined(RAD_PS2) + //Get the steering spring. + IRadControllerOutputPoint* p_OutputPoint = m_xIController2->GetOutputPointByName( "CenterSpring" ); + if ( p_OutputPoint ) + { + mSteeringSpring.Init( p_OutputPoint ); + } + + p_OutputPoint = m_xIController2->GetOutputPointByName( "BaseDamper" ); + if ( p_OutputPoint ) + { + mSteeringDamper.Init( p_OutputPoint ); + } + + p_OutputPoint = m_xIController2->GetOutputPointByName( "Constant" ); + if ( p_OutputPoint ) + { + mConstantEffect.Init( p_OutputPoint ); + } + + p_OutputPoint = m_xIController2->GetOutputPointByName( "Rumble" ); + if ( p_OutputPoint ) + { + mWheelRumble.Init( p_OutputPoint ); + } + + p_OutputPoint = m_xIController2->GetOutputPointByName( "HeavyRumble" ); + if ( p_OutputPoint ) + { + mHeavyWheelRumble.Init( p_OutputPoint ); + } +#endif + +#ifdef RAD_GAMECUBE + p_OutputPoint = m_xIController2->GetOutputPointByName( "Motor" ); + if ( p_OutputPoint ) + { + mRumbleEffect.SetMotor( 0, p_OutputPoint ); + } +#elif defined( RAD_PS2 ) + p_OutputPoint = m_xIController2->GetOutputPointByName( "SmallMotor" ); + if ( p_OutputPoint ) + { + mRumbleEffect.SetMotor( 0, p_OutputPoint ); + } + + p_OutputPoint = m_xIController2->GetOutputPointByName( "LargeMotor" ); + if ( p_OutputPoint ) + { + mRumbleEffect.SetMotor( 1, p_OutputPoint ); + } +#else + IRadControllerOutputPoint* p_OutputPoint = m_xIController2->GetOutputPointByName( "LeftMotor" ); + if ( p_OutputPoint ) + { + mRumbleEffect.SetMotor( 0, p_OutputPoint ); + } + + p_OutputPoint = m_xIController2->GetOutputPointByName( "RightMotor" ); + if ( p_OutputPoint ) + { + mRumbleEffect.SetMotor( 1, p_OutputPoint ); + } +#endif + } + +#ifdef CONTROLLER_DEBUG +#ifdef DEBUGWATCH + char nameSpace[64]; + sprintf( nameSpace, "Controller\\Input%d", m_controllerId ); + RandomButton& rb = gRandomButtoners[ m_controllerId ]; + radDbgWatchAddBoolean( &rb.mRandomButtonEnable, "Enable Random Buttons", nameSpace ); + radDbgWatchAddUnsignedInt( &rb.mRandomButtonTiming, "Button Timing", nameSpace, NULL, NULL, 0, MAX_BUTTON_TIME ); + radDbgWatchAddBoolean( &rb.mRadomizeButtonTiming, "Randomize Timing", nameSpace ); + radDbgWatchAddUnsignedInt( &rb.mMaxButtons, "Max Simul. Buttons", nameSpace, NULL, NULL, 1, MAX_BUTTON_PRESSES ); +#endif +#endif +} + +void UserController::ReleaseRadController( void ) +{ + // deregister input point callbacks + if( mbInputPointsRegistered && m_xIController2 != NULL ) + { + // get number of input points on controller. + // + const unsigned int NUM_INPUT_POINTS = m_xIController2->GetNumberOfInputPoints(); + unsigned int i; + + // unregister all input points. + // + for( i = 0; i < NUM_INPUT_POINTS; i++ ) + { + IRadControllerInputPoint* pInputPoint = m_xIController2->GetInputPointByIndex( i ); + if( pInputPoint != NULL ) + { + pInputPoint->UnRegisterControllerInputPointCallback( static_cast< IRadControllerInputPointCallback* >( this ) ); +#ifdef DEBUGWATCH + char name[64]; + sprintf( name, "%s Button", pInputPoint->GetName() ); + radDbgWatchDelete( &name ); +#endif + } + mButtonArray[ i ].SetValue(0.0f); + } + + mbInputPointsRegistered = false; + } + + mRumbleEffect.ShutDownEffects(); + + this->m_xIController2 = NULL; + +#ifdef CONTROLLER_DEBUG +#ifdef DEBUGWATCH + RandomButton& rb = gRandomButtoners[ m_controllerId ]; + radDbgWatchDelete( &rb.mRandomButtonEnable ); + radDbgWatchDelete( &rb.mRandomButtonTiming ); + radDbgWatchDelete( &rb.mRadomizeButtonTiming ); + radDbgWatchDelete( &rb.mMaxButtons ); +#endif +#endif +} + +void UserController::SetRumble( bool bRumbleOn, bool pulse ) +{ +#if defined(RAD_GAMECUBE) || defined(RAD_PS2) + if ( bRumbleOn && !mbIsRumbleOn && !CommandLineOptions::Get( CLO_NO_HAPTIC ) ) + { + mSteeringSpring.Start(); + mSteeringDamper.Start(); + mConstantEffect.Start(); + mWheelRumble.Start(); + mHeavyWheelRumble.Start(); + } + else if ( !bRumbleOn && mbIsRumbleOn ) + { + mSteeringSpring.Stop(); + mSteeringDamper.Stop(); + mConstantEffect.Stop(); + mWheelRumble.Stop(); + mHeavyWheelRumble.Stop(); + } +#endif + + if ( pulse ) + { + PulseRumble(); + } + + if ( !bRumbleOn && mbIsRumbleOn ) + { + mRumbleEffect.ShutDownEffects(); + } + + mbIsRumbleOn = bRumbleOn; +} + +bool UserController::IsRumbleOn( void ) const +{ + return mbIsRumbleOn; +} + +void UserController::PulseRumble() +{ + mRumbleEffect.SetEffect( RumbleEffect::PULSE, 500 ); +} + +void UserController::ApplyEffect( RumbleEffect::Effect effect, unsigned int durationms ) +{ + if ( mbIsRumbleOn && !CommandLineOptions::Get( CLO_NO_HAPTIC ) ) + { + mRumbleEffect.SetEffect( effect, durationms ); + } +} + +void UserController::ApplyDynaEffect( RumbleEffect::DynaEffect effect, unsigned int durationms, float gain ) +{ + if ( mbIsRumbleOn && !CommandLineOptions::Get( CLO_NO_HAPTIC ) ) + { +#ifdef RAD_XBOX + gain *= 2.0f; +#endif + mRumbleEffect.SetDynaEffect( effect, durationms, gain ); + } +} + +void UserController::Update( unsigned timeins ) +{ + if(!IsConnected()) + return; + +#ifdef CONTROLLER_DEBUG + if ( gRandomButtoners[ m_controllerId ].mRandomButtonEnable || CommandLineOptions::Get( CLO_RANDOM_BUTTONS ) ) + { + RandomButton& rb = gRandomButtoners[ m_controllerId ]; + rb.mButtonTimeout -= static_cast<int>( timeins ); + if ( rb.mButtonTimeout < 0 ) + { + rb.mButtonTimeout = 0; + } + + if ( rb.mButtonTimeout == 0 ) + { + //Reset the last button. + if ( rb.mLastButton[ rb.mCurrentButton ] != -1 ) + { + mButtonArray[ rb.mLastButton[ rb.mCurrentButton ] ].SetValue( 0.0f ); + mButtonArray[ rb.mLastButton[ rb.mCurrentButton ] ].ForceChange(); + + for ( unsigned j = 0; j < Input::MaxMappables; j++ ) + { + if ( mMappable[ j ] ) + { + mMappable[ j ]->DispatchOnButton( m_controllerId, rb.mLastButton[ rb.mCurrentButton ], &mButtonArray[ rb.mLastButton[ rb.mCurrentButton ] ] ); + } + } + } + + rb.mLastButton[ rb.mCurrentButton ] = rand() % Input::MaxPhysicalButtons; + mButtonArray[ rb.mLastButton[ rb.mCurrentButton ] ].SetValue( 1.0f ); + mButtonArray[ rb.mLastButton[ rb.mCurrentButton ] ].ForceChange(); + + for ( unsigned j = 0; j < Input::MaxMappables; j++ ) + { + if ( mMappable[ j ] ) + { + mMappable[ j ]->DispatchOnButton( m_controllerId, rb.mLastButton[ rb.mCurrentButton ], &mButtonArray[ rb.mLastButton[ rb.mCurrentButton ] ] ); + } + } + + //Increment the current button + rb.mCurrentButton = (rb.mCurrentButton + 1) % rb.mMaxButtons; + + if ( rb.mRadomizeButtonTiming ) + { + rb.mRandomButtonTiming = rand() % MAX_BUTTON_TIME; + } + + rb.mButtonTimeout = rb.mRandomButtonTiming; + } + } + +#endif + + // update the logical controller button values + for(unsigned int i = 0; i < Input::MaxPhysicalButtons; i++) + { + // always rebrodcast non-zero button values (otherwise multiple physical -> single logical + // button mappiung will screw up in some cases) + if((mButtonArray[ i ].TimeSinceChange() == 0) || (mButtonArray[ i ].IsDown())) + { + for ( unsigned j = 0; j < Input::MaxMappables; j++ ) + { + if ( mMappable[ j ] ) + { + mMappable[ j ]->DispatchOnButton( m_controllerId, i, &mButtonArray[ i ] ); + } + } + } + } + +#ifdef RAD_GAMECUBE + if ( mbIsRumbleOn ) + { +#endif + +#if defined(RAD_GAMECUBE) || defined(RAD_PS2) + mSteeringSpring.Update(); + mSteeringDamper.Update(); + mConstantEffect.Update(); + mWheelRumble.Update(); + mHeavyWheelRumble.Update(); +#endif + + //I leave this out so the FE can rumble me anyway. + mRumbleEffect.Update( timeins ); + +#ifdef RAD_GAMECUBE + } +#endif +} + +// Returns the value stored by input point at index. +float UserController::GetInputValue( unsigned int index ) const +{ + return mButtonArray[ index ].GetValue( ); +} + +// Returns the real-time value of the input point at index. +float UserController::GetInputValueRT( unsigned int index ) const +{ + rAssert( m_xIController2 != NULL ); + + IRadControllerInputPoint* pInputPoint = m_xIController2->GetInputPointByIndex( index ); + if( pInputPoint != NULL ) + { + return pInputPoint->GetCurrentValue(); + } + else + { + return 0.0f; + } +} + +Button* UserController::GetInputButton( unsigned int index ) +{ + return &mButtonArray[ index ]; +} + + +UserController::~UserController( void ) +{ + unsigned int i = 0; + for ( i = 0; i < Input::MaxMappables; i++ ) + { + if( this->mMappable[ i ] != NULL ) + { + mMappable[ i ]->Release( ); + mMappable[ i ] = 0; + } + } +} + +int UserController::RegisterMappable( Mappable *pMappable ) +{ + // Find a slot. + unsigned int i = 0; + for ( i = 0; i < Input::MaxMappables; i++ ) + { + if( this->mMappable[ i ] == NULL ) + { + break; + } + } + + // Assign the mappable. + if ( i < Input::MaxMappables ) + { + this->mMappable[ i ] = pMappable; + mMappable[ i ]->AddRef( ); + mMappable[ i ]->LoadControllerMappings( m_controllerId ); + mMappable[ i ]->InitButtons( m_controllerId, mButtonArray); + } + else + { + rAssertMsg( false, "Not enough mappables allocated.\n" ); + return -1; + } + + // make sure the input state get correctly set up for newly bound mappables + pMappable->SetResync(true); + pMappable->SetGameState(mGameState); + + return (int)i; +} + +void UserController::UnregisterMappable( int handle ) +{ + rAssert( handle < static_cast< int >( Input::MaxMappables ) ); + if ( mMappable[ handle ] ) + { + mMappable[ handle ]->Reset( ); + mMappable[ handle ]->Release( ); + mMappable[ handle ] = 0; + LoadControllerMappings(); + } +} + +void UserController::UnregisterMappable( Mappable* mappable) +{ + for ( unsigned i = 0; i < Input::MaxMappables; i++ ) + { + if( this->mMappable[ i ] == mappable ) + { + mMappable[ i ]->Reset( ); + mMappable[ i ]->Release( ); + mMappable[ i ] = 0; + LoadControllerMappings(); + return; + } + } +} + +void UserController::LoadControllerMappings( void ) +{ + unsigned int i = 0; + for ( i = 0; i < Input::MaxMappables; i++ ) + { + if( this->mMappable[ i ] != NULL ) + { + this->mMappable[ i ]->LoadControllerMappings( m_controllerId ); + mMappable[ i ]->InitButtons( m_controllerId, mButtonArray); + } + } +} + +// return the button id from the name. +int UserController::GetIdByName( const char* pszName ) const +{ + radKey key = radMakeKey(pszName); + unsigned int i; + for( i = 0; i < Input::MaxPhysicalButtons; i++ ) + { + if (mButtonNames[i] == key) + { + return i; + } + } + return -1; +} diff --git a/game/code/input/usercontroller.h b/game/code/input/usercontroller.h new file mode 100644 index 0000000..922164a --- /dev/null +++ b/game/code/input/usercontroller.h @@ -0,0 +1,139 @@ +#ifndef USERCONTROLLER_HPP +#define USERCONTROLLER_HPP + +#include <input/controller.h> +#include <input/button.h> +#include <input/rumbleeffect.h> +#include <radcontroller.hpp> +#include <radkey.hpp> + +#if defined(RAD_GAMECUBE) || defined(RAD_PS2) +#include <input/steeringspring.h> +#include <input/baseDamper.h> +#include <input/constanteffect.h> +#include <input/wheelrumble.h> +#endif + +class Mappable; +class Mapper; + + +class UserController : + public IRadControllerInputPointCallback +{ +public: + UserController( void ); + virtual ~UserController( void ); + + // initial set up of controller (called once at input ystem init) + virtual void Create( int id ); + + // set up actual controller mapping (called once at startup and prior to any time input + // connection state changes) + virtual void Initialize( IRadController* pIController2 ); + + // release ftech controllers (called prior to input connection state change) + virtual void ReleaseRadController( void ); + + // get the index of this controller + unsigned int GetControllerId( void ) const { return m_controllerId; } + + // per-frame update + void Update( unsigned timeins ); + + // set the current game state (to activate / deactivate appropriate logical controllerts) + void SetGameState(unsigned); + + // Rumble (not yet implimented) + void SetRumble( bool bRumbleOn, bool pulse = false ); + bool IsRumbleOn( void ) const; + void PulseRumble(); + void ApplyEffect( RumbleEffect::Effect effect, unsigned int durationms ); + void ApplyDynaEffect( RumbleEffect::DynaEffect effect, unsigned int durationms, float gain ); + + + // set the player index associated with this controller + void SetPlayerIndex( int i ) { m_iPlayerIndex = i; } + int GetPlayerIndex( void ) const { return m_iPlayerIndex; } + + // connection status + bool IsConnected( void ) const { return m_bConnected; } + void NotifyConnect( void ); + void NotifyDisconnect( void ); + + // Returns the value stored by input point at index. + float GetInputValue( unsigned int index ) const; + Button* GetInputButton( unsigned int index ); + + // Returns the current 'real-time' value of the input point + float GetInputValueRT( unsigned int index ) const; + + // Attaches an logical controller this physical controller + int RegisterMappable( Mappable* pMappable ); + + // Detach a logical controller + void UnregisterMappable( int handle ); + void UnregisterMappable( Mappable* pMappable ); + + // Set up the physical-logical button mappings. + void LoadControllerMappings( void ); + + // return the button id from the name. + int GetIdByName( const char* pszName ) const; + +#if defined(RAD_GAMECUBE) || defined(RAD_PS2) + SteeringSpring* GetSpring() { return mSteeringSpring.IsInit() ? &mSteeringSpring : NULL; }; + BaseDamper* GetDamper() { return mSteeringDamper.IsInit() ? &mSteeringDamper : NULL; }; + ConstantEffect* GetConstantEffect() { return mConstantEffect.IsInit() ? &mConstantEffect : NULL; }; + WheelRumble* GetWheelRumble() { return mWheelRumble.IsInit() ? &mWheelRumble : NULL; }; + WheelRumble* GetHeavyWheelRumble() { return mHeavyWheelRumble.IsInit() ? &mHeavyWheelRumble : NULL; }; +#endif + + Mappable* GetMappable( unsigned int which ) { return mMappable[ which ]; }; + + bool IsWheel() + { +#if defined(RAD_GAMECUBE) || defined(RAD_PS2) + return mSteeringSpring.IsInit(); +#else + return false; +#endif + } +protected: + // Implements IRadControllerInputPointCallback + void OnControllerInputPointChange( unsigned int buttonId, float value ); + + // the player index we are controlling. + // + int m_iPlayerIndex; + + ref< IRadController > m_xIController2; + + int m_controllerId; + + bool m_bConnected; + + Mappable* mMappable[ Input::MaxMappables ]; + bool mbInputPointsRegistered; + + unsigned mNumButtons; + Button mButtonArray[ Input::MaxPhysicalButtons ]; + radKey mButtonNames[ Input::MaxPhysicalButtons ]; + float mButtonDeadZones[ Input::MaxPhysicalButtons ]; + + unsigned mGameState; + +#if defined(RAD_GAMECUBE) || defined(RAD_PS2) + SteeringSpring mSteeringSpring; + BaseDamper mSteeringDamper; + ConstantEffect mConstantEffect; + WheelRumble mWheelRumble; + WheelRumble mHeavyWheelRumble; +#endif + bool mbIsRumbleOn; + + RumbleEffect mRumbleEffect; +}; + +#endif + diff --git a/game/code/input/usercontrollerWin32.cpp b/game/code/input/usercontrollerWin32.cpp new file mode 100644 index 0000000..47231d5 --- /dev/null +++ b/game/code/input/usercontrollerWin32.cpp @@ -0,0 +1,1443 @@ +//=========================================================================== +// Copyright (C) 2003 Radical Entertainment Ltd. All rights reserved. +// +// Component: UserController +// +// Description: Implementation of the usercontroller class for win32. +// +// History: Branched from the console UserController class. +// +//=========================================================================== + +//======================================== +// System Includes +//======================================== + +#include <radcontroller.hpp> +#include <raddebug.hpp> +#include <radmath/radmath.hpp> + +#define DIRECTINPUT_VERSION 0x0800 +#include <dinput.h> +#include <string.h> + +//======================================== +// Project Includes +//======================================== + +#include <input/usercontrollerWin32.h> +#include <input/mappable.h> +#include <input/mapper.h> +#include <input/button.h> +#include <input/Mouse.h> +#include <input/Keyboard.h> +#include <input/Gamepad.h> +#include <input/SteeringWheel.h> +#include <input/inputmanager.h> + +#include <input/steeringspring.h> +#include <input/baseDamper.h> +#include <input/constanteffect.h> +#include <input/wheelrumble.h> +#include <presentation/tutorialmanager.h> + +#include <console/fbstricmp.h> +#include <data/config/gameconfigmanager.h> + +#ifndef WORLD_BUILDER +#include <main/commandlineoptions.h> +#endif + +#include <gameflow/gameflow.h> +#include <contexts/context.h> + +// needed for the mouse reset hack. +static int maxes[] = { DIMOFS_X, DIMOFS_Y, DIMOFS_Z }; + +#ifdef WORLD_BUILDER +#ifdef CONTROLLER_DEBUG +#undef CONTROLLER_DEBUG +#endif +enum { CLO_NO_HAPTIC, CLO_RANDOM_BUTTONS }; +namespace CommandLineOptions +{ + static bool Get( int i ) { return false; }; +}; +#endif + +//This enables the random button pressing. +#define CONTROLLER_DEBUG +#ifdef CONTROLLER_DEBUG + +#define MAX_BUTTON_TIME 3000 +#define MAX_BUTTON_PRESSES 8 +struct RandomButton +{ + RandomButton() : + mRandomButtonEnable( false ), + mRandomButtonTiming( 0 ), + mRadomizeButtonTiming( false ), + mButtonTimeout( 0 ), + mMaxButtons( MAX_BUTTON_PRESSES ), + mCurrentButton( 0 ) + { + int i; + for ( i = 0; i < MAX_BUTTON_PRESSES; ++i ) + { + mLastButton[ i ] = -1; + } + } + + bool mRandomButtonEnable; + unsigned int mRandomButtonTiming; + bool mRadomizeButtonTiming; + int mButtonTimeout; + int mLastButton[ MAX_BUTTON_PRESSES ]; + unsigned int mMaxButtons; + unsigned int mCurrentButton; +}; + +RandomButton gRandomButtoners[ Input::MaxControllers ]; + +#endif + +//============================================================================= +// Class: InputCode +//============================================================================= +// +// Description: Need this for compressing ( Controller / directX key code / +// direction ) triplets into one integer. Then we can re-use the +// Mapper class for virtual maps. +// +//============================================================================= + +class InputCode +{ +public: + InputCode( unsigned int inputcode ) { mInputCode = inputcode; } + InputCode( eControllerType controller, int dxKey, eDirectionType direction ) + { + mInputCode = dxKey | (direction << 24) | (controller << 28); + rAssert( controller == GetController() ); + rAssert( dxKey == GetDxKeyCode() ); + rAssert( direction == GetDirection() ); + } + + eControllerType GetController() const + { + rAssert( (mInputCode >> 28) < NUM_CONTROLLERTYPES ); + return eControllerType( mInputCode >> 28 ); + } + int GetDxKeyCode() const + { + return mInputCode & 0xFFFFFF; + } + eDirectionType GetDirection() const + { + rAssert( ((mInputCode >> 24) & 0xF) <= NUM_DIRTYPES ); + return eDirectionType( (mInputCode >> 24) & 0xF ); + } + + int GetInputCode() const { return mInputCode; } + +private: + unsigned int mInputCode; +}; + +//****************************************************************************** +// +// Constructors, Destructors and Operators +// +//****************************************************************************** +UserController::UserController( ) +: +m_controllerId( -1 ), +mIsConnected( false ), +mGameState( Input::ACTIVE_ALL ), +mbInputPointsRegistered( false ), +mKeyboardBack( false ), +mbIsRumbleOn( false ), +m_bIsWheel( false ), +m_bTutorialDisabled(true) +{ + int i = 0; + for ( i = 0; i < Input::MaxMappables; i++ ) + { + mMappable[ i ] = 0; + } + + for( i = 0; i < 3; i++ ) + { + mResetMouseCounter[ i ] = 0; + } + + // Set up the virtual buttons. + mNumButtons = VirtualInputs::GetNumber(); + rAssert(mNumButtons < Input::MaxPhysicalButtons); + + for( i = 0; i < mNumButtons; i++ ) + { + // Define the button names for the virtual keys + mButtonNames[ i ] = radMakeKey( VirtualInputs::GetName( i ) ); + + mButtonDeadZones[ i ] = 0.10f; + mButtonSticky[ i ] = false; + } + + // Set up the controllers for each type. + m_pController[GAMEPAD] = new Gamepad(); + m_pController[KEYBOARD] = new Keyboard(); + m_pController[MOUSE] = new Mouse(); + m_pController[STEERINGWHEEL] = new Gamepad(); + + m_pSteeringSpring = new SteeringSpring; + m_pSteeringDamper = new BaseDamper; + m_pConstantEffect = new ConstantEffect; + m_pWheelRumble = new WheelRumble; + m_pHeavyWheelRumble = new WheelRumble; + + // + // Register with the game config manager + // + GetGameConfigManager()->RegisterConfig( this ); +} + +void UserController::NotifyConnect( void ) +{ + if ( !IsConnected( ) ) + { + for( int i = 0; i < NUM_CONTROLLERTYPES; i++ ) + { + m_pController[i]->Connect(); + } + + for ( unsigned int i = 0; i < Input::MaxMappables, this->mMappable[ i ]; i++ ) + { + mMappable[ i ]->OnControllerConnect( GetControllerId( ) ); + } + + mIsConnected = true; + } +} +void UserController::NotifyDisconnect( void ) +{ + if ( IsConnected( ) ) + { + for( int i = 0; i < NUM_CONTROLLERTYPES; i++ ) + { + m_pController[i]->Disconnect(); + } + + for ( unsigned int i = 0; i < Input::MaxMappables, this->mMappable[ i ]; i++ ) + { + mMappable[ i ]->OnControllerDisconnect( GetControllerId( ) ); + } + + mIsConnected = false; + } +} + +bool UserController::IsConnected() const +{ + return mIsConnected; +} + +void UserController::Create( int id ) +{ + m_controllerId = id; + + // Now that we know our controller id, + // load the default controller mappings. + // + LoadDefaults(); +} + +void UserController::SetGameState( unsigned state) +{ + mGameState = state; + for ( unsigned i = 0; i < Input::MaxMappables; i++ ) + { + if(mMappable[ i ]) + { + mMappable[ i ]->SetGameState( state ); + + // if the game state change involved and inactive mappable being activated + // wwe need to reload the current button state + if(mMappable[ i ]->GetResync()) + { + mMappable[ i ]->InitButtons( m_controllerId, mButtonArray); + mMappable[ i ]->SetResync(false); + } + } + } +} + +void UserController::SetButtonValue( unsigned int buttonId, float value, bool sticky ) +{ + float fLastValue = mButtonArray[ buttonId ].GetValue( ); + float fDeadZone = mButtonDeadZones[ buttonId ]; + + if( mButtonSticky[ buttonId ] && !sticky ) + { + return; // don't overwrite a sticky button. + } + + if ( rmt::Epsilon( value, 0.0f, fDeadZone ) ) + { + value = 0.0f; + } + else + { + //Clamp our values. + value = rmt::Clamp( value, MIN_AXIS_THRESH, MAX_AXIS_THRESH ); + + // Recalibrate them from [deadzone..1] to [0..1]. + float sign = rmt::Sign( value ); + float calibratedButtonData = rmt::Fabs( value ) - fDeadZone; + + calibratedButtonData *= 1.0f / ( 1.0f - fDeadZone ); + calibratedButtonData *= sign; + + bool bChanged = !( rmt::Epsilon( fLastValue, calibratedButtonData, 0.05f ) ); + + if ( bChanged ) + { + // go with the deadzone corrected value. + value = calibratedButtonData; + } + else + { + // restore the old deadzone corrected value. + value = fLastValue; + } + } + + if( value > 0.0f || fLastValue > 0.0f ) + { + mButtonArray[ buttonId ].SetValue( value ); + } + + // Reset the sticky flag. + mButtonSticky[ buttonId ] = sticky; + if( sticky && value == 0.0f ) + { + mButtonSticky[ buttonId ] = false; + } +} + +void UserController::OnControllerInputPointChange( unsigned int code, float value ) +{ + // Decode the virtual button code. + InputCode icode( code ); + + eControllerType cont = icode.GetController(); + int dxKey = icode.GetDxKeyCode(); + + // Set the IsWheel boolean if this is a steering wheel axis input + m_bIsWheel = STEERINGWHEEL == cont && m_pController[ cont ]->IsInputAxis( dxKey ); + + // Set the keyboard back value + if( KEYBOARD == cont && dxKey == DIK_ESCAPE && value > 0 ) + { + mKeyboardBack = true; + } + + // Derive the directional values + float dvalues[ NUM_DIRTYPES ]; + int ndirections = DeriveDirectionValues( cont, dxKey, value, dvalues ); + + // Check if we're remapping a key. + if( mMapData.MapNext ) + { + Remap( cont, dxKey, dvalues, ndirections ); + return; + } + + // Look up what virtual buttons have been mapped to this input, then update them. + for( int map = 0; map < NUM_MAPTYPES; map++ ) + { + for( int dir = 0; dir < ndirections; dir++ ) + { + int vButton = m_pController[ cont ]->GetMap( dxKey, (eDirectionType) dir, (eMapType) map ); + if( vButton != Input::INVALID_CONTROLLERID ) + { + SetButtonValue( vButton, dvalues[ dir ], cont == KEYBOARD ); + } + if( vButton == InputManager::feBack && cont != KEYBOARD ) + { + mKeyboardBack = false; + } + } + } +} + +int UserController::DeriveDirectionValues( eControllerType type, int dxKey, float value, float* values ) +{ + // Reset the directional values + values[ DIR_UP ] = values[ DIR_DOWN ] = values[ DIR_RIGHT ] = values[ DIR_LEFT ] = 0.0f; + + // Calculate the values based on the type of input. + if( m_pController[ type ]->IsInputAxis( dxKey ) ) + { + // Normalize the axis. + value = ( MAX_AXIS_THRESH - MIN_AXIS_THRESH ) * value + MIN_AXIS_THRESH; + + // Assign the values. + values[ DIR_UP ] = ( value >= 0 ) ? value : 0.0f; + values[ DIR_DOWN ] = ( value >= 0 ) ? 0.0f : -value; + + return 2; + } + else if( m_pController[ type ]->IsMouseAxis( dxKey ) ) + { + // Translate mouse val to -1..1 axis value. + value = ((Mouse*)m_pController[MOUSE])->CalculateMouseAxis( dxKey, value ); + + // Invert if necessary + if( dxKey == DIMOFS_X && m_bInvertMouseX || + dxKey == DIMOFS_Y && m_bInvertMouseY ) + { + value *= -1.0f; + } + + if( dxKey == DIMOFS_X ) + { + value *= m_fMouseSensitivityX; + } + else if( dxKey == DIMOFS_Y ) + { + value *= m_fMouseSensitivityY; + } + + // Assign the values. + values[ DIR_UP ] = ( value >= 0 ) ? value : 0.0f; + values[ DIR_DOWN ] = ( value >= 0 ) ? 0.0f : -value; + + // Initiate the mouse reset hack + for( int i = 0; i < 3; i++ ) + { + if( maxes[ i ] == dxKey && value != 0.0f ) + { + mResetMouseCounter[ i ] = 1; + } + } + + return 2; + } + else if( m_pController[ type ]->IsPovHat( dxKey ) ) + { + ((Gamepad*)m_pController[GAMEPAD])->CalculatePOV( value, &values[DIR_UP], &values[DIR_DOWN], + &values[DIR_RIGHT], &values[DIR_LEFT] ); + + return 4; + } + else // It's a button. + { + values[ DIR_UP ] = value; + + return 1; + } +} + +void UserController::Initialize( RADCONTROLLER* pIController ) +{ + // if we are being called while initialized, something is wrong + rAssert(!mbInputPointsRegistered); + + // Initialize the controllers. + // + for( int i = 0; i < NUM_CONTROLLERTYPES; i++ ) + { + m_pController[i]->Init( pIController[i] ); + } + + // Register the input points now. + // + RegisterInputPoints(); + + RADCONTROLLER pSteeringWheel = m_pController[STEERINGWHEEL]->getController(); + + static bool bSteeringSet = false; + if( pSteeringWheel /*&& !bSteeringSet*/ ) + { + //Get the steering spring. + IRadControllerOutputPoint* p_OutputPoint = pSteeringWheel->GetOutputPointByName( "Spring" ); + if ( p_OutputPoint ) + { + m_pSteeringSpring->Init( p_OutputPoint ); + } + + p_OutputPoint = pSteeringWheel->GetOutputPointByName( "Damper" ); + if ( p_OutputPoint ) + { + m_pSteeringDamper->Init( p_OutputPoint ); + } + + p_OutputPoint = pSteeringWheel->GetOutputPointByName( "Constant" ); + if ( p_OutputPoint ) + { + m_pConstantEffect->Init( p_OutputPoint ); + } + + p_OutputPoint = pSteeringWheel->GetOutputPointByName( "Sine Wave" ); + if ( p_OutputPoint ) + { + m_pWheelRumble->Init( p_OutputPoint ); + m_pWheelRumble->SetResetTime( 1000 ); + } + + p_OutputPoint = pSteeringWheel->GetOutputPointByName( "Square Wave" ); + if ( p_OutputPoint ) + { + m_pHeavyWheelRumble->Init( p_OutputPoint ); + m_pHeavyWheelRumble->SetResetTime( 1000 ); + } + bSteeringSet = true; + } + + // Set up rumbling for the gamepad. + // + RADCONTROLLER pGamepad = m_pController[GAMEPAD]->getController(); + if( pGamepad != NULL ) + { + IRadControllerOutputPoint* p_OutputPoint = pGamepad->GetOutputPointByName( "LeftMotor" ); + if ( p_OutputPoint ) + { + mRumbleEffect.SetMotor( 0, p_OutputPoint ); + } + + p_OutputPoint = pGamepad->GetOutputPointByName( "RightMotor" ); + if ( p_OutputPoint ) + { + mRumbleEffect.SetMotor( 1, p_OutputPoint ); + } + } +} + +void UserController::ReleaseRadController( void ) +{ + // deregister input point callbacks + if( mbInputPointsRegistered ) + { + //unregister the inputpoints associated with the controllers. + int i; + for( i = 0; i < NUM_CONTROLLERTYPES; i++ ) + { + if( m_pController[ i ] != NULL ) + { + m_pController[ i ]->ReleaseInputPoints( this ); + } + } + + for( i = 0; i < mNumButtons; i++ ) + { + mButtonArray[ i ].SetValue(0.0f); + } + + mbInputPointsRegistered = false; + } + + if( m_pSteeringSpring ) m_pSteeringSpring->ShutDownEffects(); + if( m_pSteeringDamper ) m_pSteeringDamper->ShutDownEffects(); + if( m_pConstantEffect ) m_pConstantEffect->ShutDownEffects(); + if( m_pWheelRumble ) m_pWheelRumble->ShutDownEffects(); + if( m_pHeavyWheelRumble ) m_pHeavyWheelRumble->ShutDownEffects(); + + mRumbleEffect.ShutDownEffects(); +} + +void UserController::SetRumble( bool bRumbleOn, bool pulse ) +{ + if ( bRumbleOn && !mbIsRumbleOn && !CommandLineOptions::Get( CLO_NO_HAPTIC ) && m_bForceFeedback ) + { + StartForceEffects(); + } + else if ( !bRumbleOn && mbIsRumbleOn && m_bForceFeedback ) + { + StopForceEffects(); + } + + if ( pulse && m_bForceFeedback ) + { + PulseRumble(); + } + + if ( !bRumbleOn && mbIsRumbleOn && m_bForceFeedback ) + { + mRumbleEffect.ShutDownEffects(); + } + mbIsRumbleOn = bRumbleOn; +} + +bool UserController::IsRumbleOn( void ) const +{ + return mbIsRumbleOn; +} + +void UserController::PulseRumble() +{ + mRumbleEffect.SetEffect( RumbleEffect::PULSE, 500 ); +} + +void UserController::ApplyEffect( RumbleEffect::Effect effect, unsigned int durationms ) +{ + if ( mbIsRumbleOn && !CommandLineOptions::Get( CLO_NO_HAPTIC ) ) + { + mRumbleEffect.SetEffect( effect, durationms ); + } +} + +void UserController::ApplyDynaEffect( RumbleEffect::DynaEffect effect, unsigned int durationms, float gain ) +{ + if ( mbIsRumbleOn && !CommandLineOptions::Get( CLO_NO_HAPTIC ) ) + { + mRumbleEffect.SetDynaEffect( effect, durationms, gain ); + } +} + +void UserController::Update( unsigned timeins ) +{ + if(!IsConnected()) + return; + +#ifdef CONTROLLER_DEBUG + if ( gRandomButtoners[ m_controllerId ].mRandomButtonEnable || CommandLineOptions::Get( CLO_RANDOM_BUTTONS ) ) + { + RandomButton& rb = gRandomButtoners[ m_controllerId ]; + rb.mButtonTimeout -= static_cast<int>( timeins ); + if ( rb.mButtonTimeout < 0 ) + { + rb.mButtonTimeout = 0; + } + + if ( rb.mButtonTimeout == 0 ) + { + //Reset the last button. + if ( rb.mLastButton[ rb.mCurrentButton ] != -1 ) + { + mButtonArray[ rb.mLastButton[ rb.mCurrentButton ] ].SetValue( 0.0f ); + mButtonArray[ rb.mLastButton[ rb.mCurrentButton ] ].ForceChange(); + + for ( unsigned j = 0; j < Input::MaxMappables; j++ ) + { + if ( mMappable[ j ] ) + { + mMappable[ j ]->DispatchOnButton( m_controllerId, rb.mLastButton[ rb.mCurrentButton ], &mButtonArray[ rb.mLastButton[ rb.mCurrentButton ] ] ); + } + } + } + + rb.mLastButton[ rb.mCurrentButton ] = rand() % Input::MaxPhysicalButtons; + mButtonArray[ rb.mLastButton[ rb.mCurrentButton ] ].SetValue( 1.0f ); + mButtonArray[ rb.mLastButton[ rb.mCurrentButton ] ].ForceChange(); + + for ( unsigned j = 0; j < Input::MaxMappables; j++ ) + { + if ( mMappable[ j ] ) + { + mMappable[ j ]->DispatchOnButton( m_controllerId, rb.mLastButton[ rb.mCurrentButton ], &mButtonArray[ rb.mLastButton[ rb.mCurrentButton ] ] ); + } + } + + //Increment the current button + rb.mCurrentButton = (rb.mCurrentButton + 1) % rb.mMaxButtons; + + if ( rb.mRadomizeButtonTiming ) + { + rb.mRandomButtonTiming = rand() % MAX_BUTTON_TIME; + } + + rb.mButtonTimeout = rb.mRandomButtonTiming; + } + } + +#endif + + // Reset any mouse inputs that have gone stale. + ResetMouseAxes(); + + // update the logical controller button values + for(unsigned int i = 0; i < Input::MaxPhysicalButtons; i++) + { + // always rebrodcast non-zero button values (otherwise multiple physical -> single logical + // button mapping will screw up in some cases) + unsigned int timesincechange = mButtonArray[ i ].TimeSinceChange(); + bool bIsDown = mButtonArray[ i ].IsDown(); + if((timesincechange == 0) || bIsDown) + { + for ( unsigned j = 0; j < Input::MaxMappables; j++ ) + { + if ( mMappable[ j ] ) + { + mMappable[ j ]->DispatchOnButton( m_controllerId, i, &mButtonArray[ i ] ); + } + } + } + } + + m_pSteeringSpring->Update(); + m_pSteeringDamper->Update(); + m_pConstantEffect->Update(); + m_pWheelRumble->Update(timeins); + m_pHeavyWheelRumble->Update(timeins); + + //I leave this out so the FE can rumble me anyway. + mRumbleEffect.Update( timeins ); +} + +void UserController::StartForceEffects() +{ + m_pSteeringSpring->Start(); + m_pSteeringDamper->Start(); + m_pConstantEffect->Start(); + m_pWheelRumble->Start(); + m_pHeavyWheelRumble->Start(); +} + +void UserController::StopForceEffects() +{ + m_pSteeringSpring->Stop(); + m_pSteeringDamper->Stop(); + m_pConstantEffect->Stop(); + m_pWheelRumble->Stop(); + m_pHeavyWheelRumble->Stop(); +} + +// Returns the value stored by input point at index. +float UserController::GetInputValue( unsigned int index ) const +{ + switch( index ) + { + case InputManager::LeftStickX: + { + float up = mButtonArray[ InputManager::CameraRight ].GetValue(); + float down = mButtonArray[ InputManager::CameraLeft ].GetValue(); + return ( up > down ) ? up : -down; + } + case InputManager::LeftStickY: + { + float up = mButtonArray[ InputManager::CameraMoveIn ].GetValue(); + float down = mButtonArray[ InputManager::CameraMoveOut ].GetValue(); + return ( up > down ) ? up : -down; + } + case InputManager::KeyboardEsc: + { + return mKeyboardBack ? 1.0f : 0.0f; + } + default: + return mButtonArray[ index ].GetValue( ); + } +} + +float UserController::GetInputValueRT( unsigned int index ) const +{ + // not supported. + return 0.0f; +} + +Button* UserController::GetInputButton( unsigned int index ) +{ + return &mButtonArray[ index ]; +} + +UserController::~UserController( void ) +{ + unsigned int i = 0; + for ( i = 0; i < Input::MaxMappables; i++ ) + { + if( this->mMappable[ i ] != NULL ) + { + mMappable[ i ]->Release( ); + mMappable[ i ] = 0; + } + } + for( int i = 0; i < NUM_CONTROLLERTYPES; i++ ) + { + delete m_pController[i]; + m_pController[i] = NULL; + } + + delete m_pSteeringSpring; + m_pSteeringSpring = NULL; + delete m_pSteeringDamper; + m_pSteeringDamper = NULL; + delete m_pConstantEffect; + m_pConstantEffect = NULL; + delete m_pWheelRumble; + m_pWheelRumble = NULL; + delete m_pHeavyWheelRumble; + m_pHeavyWheelRumble = NULL; +} + +int UserController::RegisterMappable( Mappable *pMappable ) +{ + // Find a slot. + unsigned int i = 0; + for ( i = 0; i < Input::MaxMappables; i++ ) + { + if( this->mMappable[ i ] == NULL ) + { + break; + } + } + + // Assign the mappable. + if ( i < Input::MaxMappables ) + { + this->mMappable[ i ] = pMappable; + mMappable[ i ]->AddRef( ); + mMappable[ i ]->LoadControllerMappings( m_controllerId ); + mMappable[ i ]->InitButtons( m_controllerId, mButtonArray); + } + else + { + rAssertMsg( false, "Not enough mappables allocated.\n" ); + return -1; + } + + // make sure the input state get correctly set up for newly bound mappables + pMappable->SetResync(true); + pMappable->SetGameState(mGameState); + + return (int)i; +} + +void UserController::UnregisterMappable( int handle ) +{ + rAssert( handle < static_cast< int >( Input::MaxMappables ) ); + if ( mMappable[ handle ] ) + { + mMappable[ handle ]->Reset( ); + mMappable[ handle ]->Release( ); + mMappable[ handle ] = 0; + LoadControllerMappings(); + } +} + +void UserController::UnregisterMappable( Mappable* mappable) +{ + for ( unsigned i = 0; i < Input::MaxMappables; i++ ) + { + if( this->mMappable[ i ] == mappable ) + { + mMappable[ i ]->Reset( ); + mMappable[ i ]->Release( ); + mMappable[ i ] = 0; + LoadControllerMappings(); + return; + } + } +} + +void UserController::LoadControllerMappings( void ) +{ + unsigned int i = 0; + for ( i = 0; i < Input::MaxMappables; i++ ) + { + if( this->mMappable[ i ] != NULL ) + { + this->mMappable[ i ]->LoadControllerMappings( m_controllerId ); + mMappable[ i ]->InitButtons( m_controllerId, mButtonArray); + } + } +} + +// return the button id from the name. +int UserController::GetIdByName( const char* pszName ) const +{ + radKey key = radMakeKey(pszName); + unsigned int i; + for( i = 0; i < Input::MaxPhysicalButtons; i++ ) + { + if (mButtonNames[i] == key) + { + return i; + } + } + return -1; +} + +SteeringSpring* UserController::GetSpring() +{ + return m_pSteeringSpring->IsInit() ? m_pSteeringSpring : NULL; +} + +BaseDamper* UserController::GetDamper() +{ + return m_pSteeringDamper->IsInit() ? m_pSteeringDamper : NULL; +} + +ConstantEffect* UserController::GetConstantEffect() +{ + return m_pConstantEffect->IsInit() ? m_pConstantEffect : NULL; +} + +WheelRumble* UserController::GetWheelRumble() +{ + return m_pWheelRumble->IsInit() ? m_pWheelRumble : NULL; +} + +WheelRumble* UserController::GetHeavyWheelRumble() +{ + return m_pHeavyWheelRumble->IsInit() ? m_pHeavyWheelRumble : NULL; +} + +void UserController::RegisterInputPoints() +{ + // If we've already registered, then return. + if( mbInputPointsRegistered ) + { + return; + } + + // Register input points for each controller. + for( int type = 0; type < NUM_CONTROLLERTYPES; type++ ) + { + // Retrieve the controller.. If not connected, skip. + RADCONTROLLER pController = m_pController[type]->getController(); + if( pController == NULL ) + { + continue; + } + + // Go through each input point of the controller. + unsigned num = pController->GetNumberOfInputPoints(); + for( unsigned ip = 0; ip < num; ip++ ) + { + RegisterInputPoint( (eControllerType) type, ip ); + } + } + + mbInputPointsRegistered = true; +} + +void UserController::RegisterInputPoint( eControllerType type, int inputpoint ) +{ + // Can only map when the controller connected.. otherwise no work. + RADCONTROLLER pController = m_pController[type]->getController(); + rAssert( pController != NULL ); + + IRadControllerInputPoint* pInputPoint = pController->GetInputPointByIndex( inputpoint ); + rAssert( pInputPoint != NULL ); + + int dxKey = m_pController[type]->GetDICode( inputpoint ); + + // For banned input points, return right away + if( dxKey != Input::INVALID_CONTROLLERID && !m_pController[type]->IsBannedInput( dxKey ) ) + { + // Register the callback. + // the direction value below is unimportant & ignored. + InputCode icode( type, dxKey, NUM_DIRTYPES ); + pInputPoint->RegisterControllerInputPointCallback( this, icode.GetInputCode() ); + m_pController[type]->AddInputPoints( pInputPoint ); + } +} + +const char* UserController::GetConfigName() const +{ + // do this unfortunate switch cause of multiplayer possibilities :/ + // maybe clean it up later. + switch( m_controllerId ) + { + case -1: + return "Control-default"; + case 0: + return "Controller"; + case 1: + return "Controller1"; + case 2: + return "Controller2"; + case 3: + return "Controller3"; + default: + rAssert( false ); + return "Controller3"; + } +} + +int UserController::GetNumProperties() const +{ + return Input::MaxVirtualMappings * Input::MaxPhysicalButtons + 8; +} + +void UserController::LoadDefaults() +{ + ClearMappings(); + + if ( m_controllerId == 0 ) + { + // The primary mapping - to the keyboard & mouse. + SetMap( SLOT_PRIMARY, InputManager::MoveUp, KEYBOARD, DIK_W ); + SetMap( SLOT_PRIMARY, InputManager::MoveDown, KEYBOARD, DIK_S ); + SetMap( SLOT_PRIMARY, InputManager::MoveLeft, KEYBOARD, DIK_A ); + SetMap( SLOT_PRIMARY, InputManager::MoveRight, KEYBOARD, DIK_D ); + SetMap( SLOT_PRIMARY, InputManager::Jump, KEYBOARD, DIK_SPACE ); + SetMap( SLOT_PRIMARY, InputManager::Sprint, KEYBOARD, DIK_LSHIFT ); + + SetMap( SLOT_PRIMARY, InputManager::Accelerate, KEYBOARD, DIK_W ); + SetMap( SLOT_PRIMARY, InputManager::Reverse, KEYBOARD, DIK_S ); + SetMap( SLOT_PRIMARY, InputManager::SteerLeft, KEYBOARD, DIK_A ); + SetMap( SLOT_PRIMARY, InputManager::SteerRight, KEYBOARD, DIK_D ); + SetMap( SLOT_PRIMARY, InputManager::Horn, KEYBOARD, DIK_LSHIFT ); + SetMap( SLOT_PRIMARY, InputManager::ResetCar, KEYBOARD, DIK_SPACE ); + + SetMap( SLOT_PRIMARY, InputManager::CameraLeft, KEYBOARD, DIK_NUMPAD4 ); + SetMap( SLOT_PRIMARY, InputManager::CameraRight, KEYBOARD, DIK_NUMPAD6 ); + SetMap( SLOT_PRIMARY, InputManager::CameraMoveIn, KEYBOARD, DIK_NUMPAD8 ); + SetMap( SLOT_PRIMARY, InputManager::CameraMoveOut, KEYBOARD, DIK_NUMPAD2 ); + SetMap( SLOT_PRIMARY, InputManager::CameraZoom, KEYBOARD, DIK_NUMPAD5 ); + SetMap( SLOT_PRIMARY, InputManager::CameraLookUp, KEYBOARD, DIK_NUMPAD0 ); + SetMap( SLOT_PRIMARY, InputManager::CameraToggle, KEYBOARD, DIK_NUMPAD0 ); + SetMap( SLOT_PRIMARY, InputManager::CameraCarLeft, KEYBOARD, DIK_NUMPAD4 ); + SetMap( SLOT_PRIMARY, InputManager::CameraCarRight, KEYBOARD, DIK_NUMPAD6 ); + SetMap( SLOT_PRIMARY, InputManager::CameraCarLookUp, KEYBOARD, DIK_NUMPAD8 ); + SetMap( SLOT_PRIMARY, InputManager::CameraCarLookBack, KEYBOARD, DIK_NUMPAD2 ); + } + + SetMap( SLOT_PRIMARY, InputManager::Attack, MOUSE, DIMOFS_BUTTON1 ); + SetMap( SLOT_PRIMARY, InputManager::DoAction, MOUSE, DIMOFS_BUTTON0 ); + + SetMap( SLOT_PRIMARY, InputManager::GetOutCar, MOUSE, DIMOFS_BUTTON0 ); + SetMap( SLOT_PRIMARY, InputManager::HandBrake, MOUSE, DIMOFS_BUTTON1 ); + + // The secondary mapping - to the gamepad. + SetMap( SLOT_SECONDARY, InputManager::MoveUp, GAMEPAD, DIJOFS_Y, DIR_UP ); + SetMap( SLOT_SECONDARY, InputManager::MoveDown, GAMEPAD, DIJOFS_Y, DIR_DOWN ); + SetMap( SLOT_SECONDARY, InputManager::MoveLeft, GAMEPAD, DIJOFS_X, DIR_DOWN ); + SetMap( SLOT_SECONDARY, InputManager::MoveRight, GAMEPAD, DIJOFS_X, DIR_UP ); + SetMap( SLOT_SECONDARY, InputManager::Attack, GAMEPAD, DIJOFS_BUTTON0 ); + SetMap( SLOT_SECONDARY, InputManager::Jump, GAMEPAD, DIJOFS_BUTTON3 ); + SetMap( SLOT_SECONDARY, InputManager::Sprint, GAMEPAD, DIJOFS_BUTTON7 ); + SetMap( SLOT_SECONDARY, InputManager::DoAction, GAMEPAD, DIJOFS_BUTTON4 ); + + SetMap( SLOT_SECONDARY, InputManager::Accelerate, GAMEPAD, DIJOFS_BUTTON7 ); + SetMap( SLOT_SECONDARY, InputManager::Reverse, GAMEPAD, DIJOFS_BUTTON6 ); + SetMap( SLOT_SECONDARY, InputManager::SteerLeft, GAMEPAD, DIJOFS_X, DIR_DOWN ); + SetMap( SLOT_SECONDARY, InputManager::SteerRight, GAMEPAD, DIJOFS_X, DIR_UP ); + SetMap( SLOT_SECONDARY, InputManager::GetOutCar, GAMEPAD, DIJOFS_BUTTON4 ); + SetMap( SLOT_SECONDARY, InputManager::HandBrake, GAMEPAD, DIJOFS_BUTTON1 ); + SetMap( SLOT_SECONDARY, InputManager::Horn, GAMEPAD, DIJOFS_BUTTON2 ); + SetMap( SLOT_SECONDARY, InputManager::ResetCar, GAMEPAD, DIJOFS_BUTTON5 ); + + SetMap( SLOT_SECONDARY, InputManager::CameraLeft, GAMEPAD, DIJOFS_Z, DIR_DOWN ); + SetMap( SLOT_SECONDARY, InputManager::CameraRight, GAMEPAD, DIJOFS_Z, DIR_UP ); + SetMap( SLOT_SECONDARY, InputManager::CameraMoveIn, GAMEPAD, DIJOFS_RZ, DIR_UP ); + SetMap( SLOT_SECONDARY, InputManager::CameraMoveOut, GAMEPAD, DIJOFS_RZ, DIR_DOWN ); + SetMap( SLOT_SECONDARY, InputManager::CameraZoom, GAMEPAD, DIJOFS_BUTTON6 ); + SetMap( SLOT_SECONDARY, InputManager::CameraLookUp, GAMEPAD, DIJOFS_BUTTON7 ); + SetMap( SLOT_SECONDARY, InputManager::CameraToggle, GAMEPAD, DIJOFS_BUTTON5 ); + SetMap( SLOT_SECONDARY, InputManager::CameraCarLeft, GAMEPAD, DIJOFS_Z, DIR_DOWN ); + SetMap( SLOT_SECONDARY, InputManager::CameraCarRight, GAMEPAD, DIJOFS_Z, DIR_UP ); + SetMap( SLOT_SECONDARY, InputManager::CameraCarLookUp, GAMEPAD, DIJOFS_RZ, DIR_UP ); + SetMap( SLOT_SECONDARY, InputManager::CameraCarLookBack, GAMEPAD, DIJOFS_RZ, DIR_DOWN ); + + + // Initialize the game settings + m_bMouseLook = true; + m_bInvertMouseX = false; + m_bInvertMouseY = false; + m_bForceFeedback = false; + m_bTutorialDisabled = false; + m_fMouseSensitivityX = 0.35f; + m_fMouseSensitivityY = 0.5f; + m_fWheelSensitivityX = 0.5f; + m_fWheelSensitivityY = 0.5f; + + //Enable the tutorials if controls are reverted. + TutorialManager* pTutorialManager = GetTutorialManager(); + if( pTutorialManager ) + pTutorialManager->EnableTutorialMode( m_bTutorialDisabled ); +} + +void UserController::LoadConfig( ConfigString& config ) +{ + ClearMappings(); + + char property[ ConfigString::MaxLength ]; + char value[ ConfigString::MaxLength ]; + + int map; + int virtualKey; + int cont; + int dxKey; + int dir; + + // Load the mappings. + while ( config.ReadProperty( property, value ) ) + { + if( _stricmp( property, "buttonmap" ) == 0 ) + { + int ret = sscanf( value, "%d, %d: ( %d %d %d )", &map, &virtualKey, &cont, &dxKey, &dir ); + + if( ret == 5 && + map >= 0 && map < Input::MaxVirtualMappings && + virtualKey >= 0 && virtualKey < (int) mNumButtons && + VirtualInputs::GetType( virtualKey ) != MAP_FRONTEND && + cont >= 0 && cont < NUM_CONTROLLERTYPES && + m_pController[ cont ]->IsValidInput( dxKey ) && + dir >= 0 && dir < NUM_DIRTYPES + ) + { + SetMap( map, virtualKey, (eControllerType) cont, dxKey, (eDirectionType) dir ); + } + } + else if( _stricmp( property, "mouselook" ) == 0 ) + { + if( strcmp( value, "yes" ) == 0 ) + { + m_bMouseLook = true; + } + else if( strcmp( value, "no" ) == 0 ) + { + m_bMouseLook = false; + } + } + else if( _stricmp( property, "invertmousex" ) == 0 ) + { + if( strcmp( value, "yes" ) == 0 ) + { + m_bInvertMouseX = true; + } + else if( strcmp( value, "no" ) == 0 ) + { + m_bInvertMouseX = false; + } + } + else if( _stricmp( property, "invertmousey" ) == 0 ) + { + if( strcmp( value, "yes" ) == 0 ) + { + m_bInvertMouseY = true; + } + else if( strcmp( value, "no" ) == 0 ) + { + m_bInvertMouseY = false; + } + } + else if( _stricmp( property, "useforcefeedback" ) == 0 ) + { + if( strcmp( value, "yes" ) == 0 ) + { + m_bForceFeedback = true; + } + else if( strcmp( value, "no" ) == 0 ) + { + m_bForceFeedback= false; + } + } + else if( _stricmp( property, "disabletutorials" ) == 0 ) + { + if( strcmp( value, "yes" ) == 0 ) + { + m_bTutorialDisabled = true; + } + else if( strcmp( value, "no" ) == 0 ) + { + m_bTutorialDisabled = false; + } + } + else if( _stricmp( property, "mousesensitivityx" ) == 0 ) + { + float val = (float) atof( value ); + if( val > 0 ) + { + m_fMouseSensitivityX = val; + } + } + else if( _stricmp( property, "mousesensitivityy" ) == 0 ) + { + float val = (float) atof( value ); + if( val > 0 ) + { + m_fMouseSensitivityY = val; + } + } + else if( _stricmp( property, "wheelsensitivityx" ) == 0 ) + { + float val = (float) atof( value ); + if( val > 0 ) + { + m_fWheelSensitivityX = val; + } + } + else if( _stricmp( property, "wheelsensitivityy" ) == 0 ) + { + float val = (float) atof( value ); + if( val > 0 ) + { + m_fWheelSensitivityY = val; + } + } + } +} + +void UserController::SaveConfig( ConfigString& config ) +{ + char value[ ConfigString::MaxLength ]; + eControllerType cont; + int dxKey; + eDirectionType dir; + + // For each of our mappings... + for( int map = 0; map < Input::MaxVirtualMappings; map++ ) + { + // For each virtual button... + for( int vk = 0; vk < (int) mNumButtons; vk++ ) + { + // Save any mapped key. + if( VirtualInputs::GetType( vk ) != MAP_FRONTEND && + GetMap( map, vk, cont, dxKey, dir ) ) + { + sprintf( value, "%d, %d: ( %d %d %d )", map, vk, cont, dxKey, dir ); + config.WriteProperty( "buttonmap", value ); + } + } + } + + // Save the other controller settings + config.WriteProperty( "mouselook", m_bMouseLook ? "yes" : "no" ); + config.WriteProperty( "invertmousex", m_bInvertMouseX ? "yes" : "no" ); + config.WriteProperty( "invertmousey", m_bInvertMouseY ? "yes" : "no" ); + config.WriteProperty( "useforcefeedback", m_bForceFeedback ? "yes" : "no" ); + config.WriteProperty( "disabletutorials", m_bTutorialDisabled ? "yes" : "no" ); + + sprintf( value, "%f", m_fMouseSensitivityX ); + config.WriteProperty( "mousesensitivityx", value ); + + sprintf( value, "%f", m_fMouseSensitivityY ); + config.WriteProperty( "mousesensitivityy", value ); + + sprintf( value, "%f", m_fWheelSensitivityX ); + config.WriteProperty( "wheelsensitivityx", value ); + + sprintf( value, "%f", m_fWheelSensitivityY ); + config.WriteProperty( "wheelsensitivityy", value ); + +} + +void UserController::RemapButton( int map, int VirtualButton, ButtonMappedCallback* callback ) +{ + rAssert( map >= 0 && map < Input::MaxVirtualMappings ); + rAssert( VirtualButton >= 0 && VirtualButton < mNumButtons ); + rAssert( VirtualInputs::GetType( VirtualButton ) != MAP_FRONTEND ); + + // Save the data. Button gets mapped asynchronously in OnControllerInputPointChange() + mMapData.MapNext = true; + mMapData.map = map; + mMapData.virtualButton = VirtualButton; + mMapData.callback = callback; +} + +void UserController::SetMap( int map, int virtualKey, eControllerType cont, int dxKey, eDirectionType dir ) +{ + // Check over the inputs. + rAssert( map >= 0 && map < Input::MaxVirtualMappings ); + rAssert( virtualKey >= 0 && virtualKey < mNumButtons ); + rAssert( m_pController[ cont ]->IsValidInput( dxKey ) ); + rAssert( VirtualInputs::GetType( virtualKey ) != MAP_FRONTEND ); + + // Create the compressed key code + InputCode icode( cont, dxKey, dir ); + + // Clear the previous key that was used for this virtual button. + eControllerType oldcont; + int olddxKey; + eDirectionType olddir; + if( GetMap( map, virtualKey, oldcont, olddxKey, olddir ) ) + { + m_pController[ oldcont ]->ClearMap( olddxKey, olddir, virtualKey ); + } + + // Clear any previous virtual button mapped to this controller/key/direction + eMapType maptype = VirtualInputs::GetType( virtualKey ); + int old_vb = m_pController[ cont ]->GetMap( dxKey, dir, maptype ); + if( old_vb != Input::INVALID_CONTROLLERID ) + { + for( int i = 0; i < Input::MaxVirtualMappings; i++ ) + { + if( mVirtualMap[ i ].GetLogicalIndex( old_vb ) == icode.GetInputCode() ) + { + mVirtualMap[ i ].SetAssociation( old_vb, Input::INVALID_CONTROLLERID ); + } + } + } + + + // Save the new mapping + mVirtualMap[ map ].SetAssociation( virtualKey, icode.GetInputCode() ); + + // Propagate the mapping to the controller + m_pController[ cont ]->SetMap( dxKey, dir, virtualKey ); +} + +bool UserController::GetMap( int map, int virtualKey, eControllerType& type, int& dxKey, eDirectionType& dir ) const +{ + // Check over the inputs. + rAssert( map >= 0 && map < Input::MaxVirtualMappings ); + rAssert( virtualKey >= 0 && virtualKey < mNumButtons ); + + // Load the mapping + int code = mVirtualMap[ map ].GetLogicalIndex( virtualKey ); + + if( code != Input::INVALID_CONTROLLERID ) + { + InputCode icode = code; + type = icode.GetController(); + dxKey = icode.GetDxKeyCode(); + dir = icode.GetDirection(); + } + + return code != Input::INVALID_CONTROLLERID; +} + +const char* UserController::GetMap( int map, int virtualKey, int& numDirs, eControllerType& cont, eDirectionType& dir ) const +{ + int dxKey; + + // Retrieve the mapping for the key. + // If the controller is not plugged in, return null. + if( !GetMap( map, virtualKey, cont, dxKey, dir ) || + m_pController[ cont ]->getController() == NULL ) + { + return NULL; + } + + // figure out how many directions there are for this input + if( m_pController[ cont ]->IsInputAxis( dxKey ) || m_pController[ cont ]->IsMouseAxis( dxKey ) ) + { + numDirs = 2; + } + else if( m_pController[ cont ]->IsPovHat( dxKey ) ) + { + numDirs = 4; + } + else + { + numDirs = 1; + } + + // return the name of the input point + return m_pController[ cont ]->GetInputName( dxKey ); +} + +void UserController::Remap( eControllerType cont, int dxKey, float* dvalues, int ndirections ) +{ + if( cont == KEYBOARD && + m_pController[ cont ]->GetMap( dxKey, DIR_UP, MAP_FRONTEND ) == InputManager::feBack ) + { + // If the user pressed back on the keyboard, cancel the mapping. + mMapData.MapNext = false; + mMapData.callback->OnButtonMapped( NULL, cont, 1, NUM_DIRTYPES ); + } + else if( cont == MOUSE && ( dxKey == DIMOFS_X || dxKey == DIMOFS_Y ) ) + { + // Not allowed to map these. + } + else + { + // Find out which direction the user is pressing in. + for( int dir = 0; dir < ndirections; dir++ ) + { + if( dvalues[ dir ] >= MAPPING_DEADZONE ) + { + SetMap( mMapData.map, mMapData.virtualButton, cont, dxKey, (eDirectionType) dir ); + + // Call back the mapper. + mMapData.MapNext = false; + mMapData.callback->OnButtonMapped( m_pController[ cont ]->GetInputName( dxKey ), cont, ndirections, (eDirectionType) dir ); + + break; + } + } + } +} + +void UserController::ClearMappings() +{ + for( int i = 0; i < Input::MaxVirtualMappings; i++ ) + { + mVirtualMap[ i ].ClearAssociations(); + } + + for( int j = 0; j < NUM_CONTROLLERTYPES; j++ ) + { + m_pController[ j ]->ClearMappedButtons(); + } + + // Make sure these are always loaded. + LoadFEMappings(); +} + +void UserController::LoadFEMappings() +{ + switch ( m_controllerId ) + { + case 0: + { + m_pController[KEYBOARD]->SetMap( DIK_ESCAPE, DIR_UP, InputManager::feBack ); + m_pController[KEYBOARD]->SetMap( DIK_UP, DIR_UP, InputManager::feMoveUp ); + m_pController[KEYBOARD]->SetMap( DIK_DOWN, DIR_UP, InputManager::feMoveDown ); + m_pController[KEYBOARD]->SetMap( DIK_LEFT, DIR_UP, InputManager::feMoveLeft ); + m_pController[KEYBOARD]->SetMap( DIK_RIGHT, DIR_UP, InputManager::feMoveRight ); + m_pController[KEYBOARD]->SetMap( DIK_RETURN, DIR_UP, InputManager::feSelect ); + m_pController[KEYBOARD]->SetMap( DIK_NUMPAD8, DIR_UP, InputManager::feMoveUp ); + m_pController[KEYBOARD]->SetMap( DIK_NUMPAD2, DIR_UP, InputManager::feMoveDown ); + m_pController[KEYBOARD]->SetMap( DIK_NUMPAD4, DIR_UP, InputManager::feMoveLeft ); + m_pController[KEYBOARD]->SetMap( DIK_NUMPAD6, DIR_UP, InputManager::feMoveRight ); + m_pController[KEYBOARD]->SetMap( DIK_NUMPADENTER, DIR_UP, InputManager::feSelect ); + m_pController[KEYBOARD]->SetMap( DIK_F1, DIR_UP, InputManager::feFunction1 ); + m_pController[KEYBOARD]->SetMap( DIK_F2, DIR_UP, InputManager::feFunction2 ); + break; + } + case 3: + { + //P4 + m_pController[KEYBOARD]->SetMap( DIK_F4, DIR_UP, InputManager::P1_KBD_Start ); + m_pController[KEYBOARD]->SetMap( DIK_O, DIR_UP, InputManager::P1_KBD_Gas ); + m_pController[KEYBOARD]->SetMap( DIK_L, DIR_UP, InputManager::P1_KBD_Brake ); + m_pController[KEYBOARD]->SetMap( DIK_RETURN, DIR_UP, InputManager::P1_KBD_EBrake ); + m_pController[KEYBOARD]->SetMap( DIK_RSHIFT, DIR_UP, InputManager::P1_KBD_Nitro ); + m_pController[KEYBOARD]->SetMap( DIK_K, DIR_UP, InputManager::P1_KBD_Left ); + m_pController[KEYBOARD]->SetMap( DIK_SEMICOLON, DIR_UP, InputManager::P1_KBD_Right ); + break; + } + } + + m_pController[MOUSE]->SetMap( DIMOFS_BUTTON1, DIR_UP, InputManager::feBack ); + m_pController[MOUSE]->SetMap( DIMOFS_X, DIR_UP, InputManager::feMouseRight ); + m_pController[MOUSE]->SetMap( DIMOFS_X, DIR_DOWN, InputManager::feMouseLeft ); + m_pController[MOUSE]->SetMap( DIMOFS_Y, DIR_UP, InputManager::feMouseUp ); + m_pController[MOUSE]->SetMap( DIMOFS_Y, DIR_DOWN, InputManager::feMouseDown ); + m_pController[MOUSE]->SetMap( DIMOFS_Z, DIR_UP, InputManager::feMoveRight ); + m_pController[MOUSE]->SetMap( DIMOFS_Z, DIR_DOWN, InputManager::feMoveLeft ); + + m_pController[GAMEPAD]->SetMap( DIJOFS_Y, DIR_UP, InputManager::feMoveUp ); + m_pController[GAMEPAD]->SetMap( DIJOFS_Y, DIR_DOWN, InputManager::feMoveDown ); + m_pController[GAMEPAD]->SetMap( DIJOFS_X, DIR_UP, InputManager::feMoveRight ); + m_pController[GAMEPAD]->SetMap( DIJOFS_X, DIR_DOWN, InputManager::feMoveLeft ); + m_pController[GAMEPAD]->SetMap( DIJOFS_BUTTON0, DIR_UP, InputManager::feSelect ); + m_pController[GAMEPAD]->SetMap( DIJOFS_BUTTON1, DIR_UP, InputManager::feBack ); + m_pController[GAMEPAD]->SetMap( DIJOFS_POV(0), DIR_UP, InputManager::feMoveUp ); + m_pController[GAMEPAD]->SetMap( DIJOFS_POV(0), DIR_DOWN, InputManager::feMoveDown ); + m_pController[GAMEPAD]->SetMap( DIJOFS_POV(0), DIR_RIGHT, InputManager::feMoveRight ); + m_pController[GAMEPAD]->SetMap( DIJOFS_POV(0), DIR_LEFT, InputManager::feMoveLeft ); +} + +void UserController::ResetMouseAxes() +{ + for( int i = 0; i < 3; i++ ) + { + if( mResetMouseCounter[ i ] > 1 ) + { + // Reset this mouse axis. + InputCode icode( MOUSE, maxes[ i ], NUM_DIRTYPES ); + OnControllerInputPointChange( icode.GetInputCode(), 0.0f ); + + mResetMouseCounter[ i ] = 0; + } + else if( mResetMouseCounter[ i ] > 0 ) + { + mResetMouseCounter[ i ]++; + } + } +} diff --git a/game/code/input/usercontrollerWin32.h b/game/code/input/usercontrollerWin32.h new file mode 100644 index 0000000..7d85957 --- /dev/null +++ b/game/code/input/usercontrollerWin32.h @@ -0,0 +1,294 @@ +//============================================================================= +// Copyright (C) 2003 Radical Entertainment Ltd. All rights reserved. +// +// Component: UserController +// +// Description: An input/output controller for a given player in the game. It +// bundles a number of actual controllers together to allow the +// player to use different devices (keyboard, mouse, gamepad...). +// This is the input interface between the game and the player, +// sending inputs to registered input processing classes, letting +// the player drive, move around, control the front end... +// +// This specific class is an implementation of the UserController +// class strictly for win32. +// +// History: Branched from the console UserController class. +// +//============================================================================= + +#ifndef USERCONTROLLER_HPP +#define USERCONTROLLER_HPP + +//======================================== +// Platform check +//======================================== + +#ifndef RAD_WIN32 +#error 'This implementation of the user controller is specific to Win32.' +#endif + +//======================================== +// System Includes +//======================================== + +#include <radcontroller.hpp> +#include <radkey.hpp> + +//======================================== +// Nested Includes +//======================================== + +#include <data/config/gameconfig.h> +#include <input/controller.h> +#include <input/button.h> +#include <input/mapper.h> +#include <input/rumbleeffect.h> +#include <input/RealController.h> + +//============================================================================= +// Forward Class Declarations +//============================================================================= + +class Mappable; +class Mapper; +class SteeringSpring; +class BaseDamper; +class ConstantEffect; +class WheelRumble; + +//============================================================================= +// Enumerations +//============================================================================= + +enum eVirtualMapSlot +{ + SLOT_PRIMARY = 0, + SLOT_SECONDARY +}; + +#define MAX_AXIS_THRESH 1.0f +#define MIN_AXIS_THRESH -1.0f + +#define MAPPING_DEADZONE 0.5f + +//============================================================================= +// Interface: ButtonMappedCallback +//============================================================================= +// +// Description: Callback interface for the UserController::RemapButton method. +// Implement the method to receive notification for when a button +// has been mapped. +// +//============================================================================= + +struct ButtonMappedCallback +{ + virtual void OnButtonMapped( const char* InputName, eControllerType cont, int num_dirs, eDirectionType direction ) = 0; +}; + +//============================================================================= +// Struct: ButtonMapData +//============================================================================= +// +// Description: Internal struct for user controller. +// +//============================================================================= + +struct ButtonMapData +{ + ButtonMapData() : MapNext(false) {}; + + bool MapNext; + int map; + int virtualButton; + ButtonMappedCallback* callback; +}; + +//============================================================================= +// Class: UserController +//============================================================================= +// +// Description: The controller interface between the user and the game. It +// encapsulates a number of radControllers for a given player. +// +//============================================================================= + +class UserController : + public IRadControllerInputPointCallback, + public GameConfigHandler +{ +public: + UserController( void ); + virtual ~UserController( void ); + + // initial set up of controller (called once at input ystem init) + virtual void Create( int id ); + + // set up actual controller mapping (called once at startup and prior to any time input + // connection state changes) + virtual void Initialize( RADCONTROLLER* pIController ); + + // release ftech controllers (called prior to input connection state change) + virtual void ReleaseRadController( void ); + + RealController* GetRealController( eControllerType type ) { return m_pController[type]; } + // get the index of this controller + unsigned int GetControllerId( void ) const { return m_controllerId; } + + // per-frame update + void Update( unsigned timeins ); + + void StartForceEffects(); + void StopForceEffects(); + + // set the current game state (to activate / deactivate appropriate logical controllerts) + void SetGameState(unsigned); + + // Rumble (not yet implimented) + void SetRumble( bool bRumbleOn, bool pulse = false ); + bool IsRumbleOn( void ) const; + void PulseRumble(); + void ApplyEffect( RumbleEffect::Effect effect, unsigned int durationms ); + void ApplyDynaEffect( RumbleEffect::DynaEffect effect, unsigned int durationms, float gain ); + + // connection status + bool IsConnected( void ) const; + void NotifyConnect( void ); + void NotifyDisconnect( void ); + + // Returns the value stored by input point at index. + float GetInputValue( unsigned int index ) const; + Button* GetInputButton( unsigned int index ); + + // Returns the current 'real-time' value of the input point + float GetInputValueRT( unsigned int index ) const; + + // Attaches an logical controller this physical controller + int RegisterMappable( Mappable* pMappable ); + + // Detach a logical controller + void UnregisterMappable( int handle ); + void UnregisterMappable( Mappable* pMappable ); + + // Set up the physical-logical button mappings. + void LoadControllerMappings( void ); + + // return the button id from the name. + int GetIdByName( const char* pszName ) const; + + SteeringSpring* GetSpring(); + BaseDamper* GetDamper(); + ConstantEffect* GetConstantEffect(); + WheelRumble* GetWheelRumble(); + WheelRumble* GetHeavyWheelRumble(); + + Mappable* GetMappable( unsigned int which ) { return mMappable[ which ]; }; + + bool IsWheel() const { return m_bIsWheel; } + + // Implementation of the GameConfigHandler interface + virtual const char* GetConfigName() const; + virtual int GetNumProperties() const; + virtual void LoadDefaults(); + virtual void LoadConfig( ConfigString& config ); + virtual void SaveConfig( ConfigString& config ); + + // Public mapping functions for the user controller. + const char* GetMap( int map, int virtualKey, int& numDirs, eControllerType& cont, eDirectionType& dir ) const; + void RemapButton( int map, int VirtualButton, ButtonMappedCallback* callback ); + + void SetMouseLook( bool bMouseLook ) { m_bMouseLook = bMouseLook; } + void SetInvertMouseX( bool bInvertMouseX ) { m_bInvertMouseX = bInvertMouseX; } + void SetInvertMouseY( bool bInvertMouseY ) { m_bInvertMouseY = bInvertMouseY; } + void SetForceFeedback( bool bForceFeedback ) { m_bForceFeedback = bForceFeedback; } + void SetTutorialDisabled( bool bDisabled ) { m_bTutorialDisabled = bDisabled; } + void SetMouseSensitivityX( float fValue ) { m_fMouseSensitivityX = fValue; } + void SetMouseSensitivityY( float fValue ) { m_fMouseSensitivityY = fValue; } + void SetWheelSensitivityX( float fValue ) { m_fWheelSensitivityX = fValue; } + void SetWheelSensitivityY( float fValue ) { m_fWheelSensitivityY = fValue; } + + bool IsMouseLookOn() const { return m_bMouseLook; } + bool IsMouseXInverted() const { return m_bInvertMouseX; } + bool IsMouseYInverted() const { return m_bInvertMouseY; } + bool IsForceFeedbackOn() const { return m_bForceFeedback; } + bool IsTutorialDisabled() const { return m_bTutorialDisabled; } + + float GetMouseSensitivityX() const { return m_fMouseSensitivityX; } + float GetMouseSensitivityY() const { return m_fMouseSensitivityY; } + float GetWheelSensitivityX() const { return m_fWheelSensitivityX; } + float GetWheelSensitivityY() const { return m_fWheelSensitivityY; } + +protected: + + // These register our callbacks with the RadControllers. + void RegisterInputPoints(); + void RegisterInputPoint( eControllerType type, int inputpoint ); + + // Callback for when keys/inputs are pressed by the user. + void OnControllerInputPointChange( unsigned int buttonId, float value ); + + // These process input point values as received by the input point callback. + int DeriveDirectionValues( eControllerType type, int dxKey, float value, float* dir_values ); + void SetButtonValue( unsigned int virtualButton, float value, bool sticky ); + + // Needed to get mouse axes to function properly + void ResetMouseAxes(); + + // Private mapping functions for the user controller. + void SetMap( int map, int virtualKey, eControllerType cont, int dxKey, eDirectionType dir = DIR_UP ); + bool GetMap( int map, int virtualKey, eControllerType& cont, int& dxKey, eDirectionType& dir ) const; + void Remap( eControllerType cont, int dxKey, float* dvalues, int directions ); + void ClearMappings(); + void LoadFEMappings(); + +private: + + int m_controllerId; + bool mIsConnected; + + unsigned mGameState; + bool mbInputPointsRegistered; + + RealController* m_pController[ NUM_CONTROLLERTYPES ]; + + SteeringSpring* m_pSteeringSpring; + BaseDamper* m_pSteeringDamper; + ConstantEffect* m_pConstantEffect; + WheelRumble* m_pWheelRumble; + WheelRumble* m_pHeavyWheelRumble; + + Mappable* mMappable[ Input::MaxMappables ]; + + // Virtual mapping data. + Mapper mVirtualMap[ Input::MaxVirtualMappings ]; + ButtonMapData mMapData; + + // Button data. + int mNumButtons; + Button mButtonArray[ Input::MaxPhysicalButtons ]; + radKey mButtonNames[ Input::MaxPhysicalButtons ]; + float mButtonDeadZones[ Input::MaxPhysicalButtons ]; + bool mButtonSticky[ Input::MaxPhysicalButtons ]; + + bool mKeyboardBack; + + bool mbIsRumbleOn; + bool m_bIsWheel; + RumbleEffect mRumbleEffect; + + bool m_bMouseLook, + m_bInvertMouseX, + m_bInvertMouseY, + m_bForceFeedback; + bool m_bTutorialDisabled; + + float m_fMouseSensitivityX, + m_fMouseSensitivityY, + m_fWheelSensitivityX, // The wheel + m_fWheelSensitivityY; // The pedals + + int mResetMouseCounter[3]; // Hack needed for proper mouse inputs. +}; + +#endif diff --git a/game/code/input/virtualinputs.cpp b/game/code/input/virtualinputs.cpp new file mode 100644 index 0000000..d4de3f3 --- /dev/null +++ b/game/code/input/virtualinputs.cpp @@ -0,0 +1,178 @@ +//=========================================================================== +// Copyright (C) 2003 Radical Entertainment Ltd. All rights reserved. +// +// Component: VirtualInputs +// +// Description: Implementation of the virtual input class. +// +// History: 03/28/2003 + Created -- Ziemek +// +//=========================================================================== + +#include <input/virtualinputs.hpp> +#include <input/inputmanager.h> + +static const char* szVirtualInputs[] = +{ + "MoveUp", + "MoveDown", + "MoveLeft", + "MoveRight", + "Attack", + "Jump", + "Sprint", + "DoAction", + + "Accelerate", + "Reverse", + "SteerLeft", + "SteerRight", + "GetOutCar", + "HandBrake", + "Horn", + "ResetCar", + + "CameraLeft", + "CameraRight", + "CameraMoveIn", + "CameraMoveOut", + "CameraZoom", + "CameraLookUp", + "CameraCarLeft", + "CameraCarRight", + "CameraCarLookUp", + "CameraCarLookBack", + "CameraToggle", + + "feBack", // Do not allow the user to configure any fe buttons! + "feMoveUp", // These are standard, unconfigurable + "feMoveDown", + "feMoveLeft", + "feMoveRight", + "feSelect", + "feFunction1", + "feFunction2", + "feMouseLeft", + "feMouseRight", + "feMouseUp", + "feMouseDown", + + "P1_KBD_Start", + "P1_KBD_Gas", + "P1_KBD_Brake", + "P1_KBD_EBrake", + "P1_KBD_Nitro", + "P1_KBD_Left", + "P1_KBD_Right" +}; + +//============================================================================== +// VirtualInputs::GetName +//============================================================================== +// +// Description: Returns the name of the given input +// +// Parameters: virtualinput - input to look up +// +// Return: name of input +// +//============================================================================== + +const char* VirtualInputs::GetName( int VirtualInput ) +{ + rAssert( VirtualInput >= 0 && VirtualInput < GetNumber() ); + + return szVirtualInputs[ VirtualInput ]; +} + +//============================================================================== +// VirtualInputs::GetType +//============================================================================== +// +// Description: Returns the type of a virtual input +// +// Parameters: virtualinput - input to look up +// +// Return: type of input +// +//============================================================================== + +eMapType VirtualInputs::GetType( int VirtualInput ) +{ + rAssert( VirtualInput >= 0 && VirtualInput < GetNumber() ); + + switch( VirtualInput ) + { + case InputManager::MoveUp: + case InputManager::MoveDown: + case InputManager::MoveLeft: + case InputManager::MoveRight: + case InputManager::Attack: + case InputManager::Jump: + case InputManager::Sprint: + case InputManager::DoAction: + case InputManager::CameraLeft: + case InputManager::CameraRight: + case InputManager::CameraMoveIn: + case InputManager::CameraMoveOut: + case InputManager::CameraZoom: + case InputManager::CameraLookUp: + return MAP_CHARACTER; + case InputManager::Accelerate: + case InputManager::Reverse: + case InputManager::SteerLeft: + case InputManager::SteerRight: + case InputManager::GetOutCar: + case InputManager::HandBrake: + case InputManager::Horn: + case InputManager::ResetCar: + case InputManager::CameraCarLeft: + case InputManager::CameraCarRight: + case InputManager::CameraCarLookUp: + case InputManager::CameraCarLookBack: + case InputManager::CameraToggle: + return MAP_VEHICLE; + case InputManager::feBack: + case InputManager::feMoveUp: + case InputManager::feMoveDown: + case InputManager::feMoveLeft: + case InputManager::feMoveRight: + case InputManager::feSelect: + case InputManager::feFunction1: + case InputManager::feFunction2: + case InputManager::feMouseLeft: + case InputManager::feMouseRight: + case InputManager::feMouseUp: + case InputManager::feMouseDown: + return MAP_FRONTEND; + default: + { + if ( VirtualInput >= InputManager::P1_KBD_Start && VirtualInput <= InputManager::P1_KBD_Right ) + { + return MAP_FRONTEND; + } + else + { + return MAP_CHARACTER; + } + } + } +} +//============================================================================== +// VirtualInputs::GetNumber +//============================================================================== +// +// Description: Returns the number of virtual inputs +// +// Parameters: n/a +// +// Return: number of virtual inputs +// +//============================================================================== + +int VirtualInputs::GetNumber() +{ + static int NumVirtualInputs = sizeof( szVirtualInputs ) / sizeof( szVirtualInputs[0] ); + + return NumVirtualInputs; +} diff --git a/game/code/input/virtualinputs.hpp b/game/code/input/virtualinputs.hpp new file mode 100644 index 0000000..214bb07 --- /dev/null +++ b/game/code/input/virtualinputs.hpp @@ -0,0 +1,31 @@ +//============================================================================= +// Copyright (C) 2003 Radical Entertainment Ltd. All rights reserved. +// +// Component: VirtualInput +// +// Description: Small helper class for dealing with virtual inputs. +// +// History: Created 19/08/03. +// +//============================================================================= + +#ifndef VIRTUALINPUTS_HPP +#define VIRTUALINPUTS_HPP + +enum eMapType +{ + MAP_CHARACTER = 0, + MAP_VEHICLE, + MAP_FRONTEND, + NUM_MAPTYPES +}; + +class VirtualInputs +{ +public: + static const char* GetName( int VirtualInput ); + static eMapType GetType( int VirtualInput ); + static int GetNumber(); +}; + +#endif
\ No newline at end of file diff --git a/game/code/input/wheeldefines.h b/game/code/input/wheeldefines.h new file mode 100644 index 0000000..32533cf --- /dev/null +++ b/game/code/input/wheeldefines.h @@ -0,0 +1,53 @@ +#ifndef WHEEL_DEFINES +#define WHEEL_DEFINES + +#ifdef RAD_PS2 +typedef struct lgDevForceEffect LGForceEffect; +#endif + +#ifdef RAD_PS2 +//Why the hell are these different? +#define LG_TYPE_DAMPER LGTYPE_DAMPER +#define LG_TYPE_SPRING LGTYPE_SPRING +#define LG_TYPE_CONSTANT LGTYPE_CONSTANT +#define LG_TYPE_TRIANGLE LGTYPE_TRIANGLE +#define LG_TYPE_SQUARE LGTYPE_SQUARE +#define LG_DURATION_INFINITE LGDURATION_INFINITE +#define type Type +#define duration Duration +#define startDelay StartDelay +#define magnitude Magnitude +#define direction Direction +#define offset Offset +#define deadband Deadband +#define saturationNeg SaturationNeg +#define saturationPos SaturationPos +#define coefficientNeg CoefficientNeg +#define coefficientPos CoefficientPos +#define period Period +#define phase Phase +#define attackTime AttackTime +#define fadeTime FadeTime +#define attackLevel AttackLevel +#define fadeLevel FadeLevel +#endif + +#ifdef RAD_WIN32 +enum eForceTypes +{ + CONSTANT_FORCE, + RAMP_FORCE, + SQUARE, + SINE, + TRIANGLE, + SAWTOOTH_UP, + SAWTOOTH_DOWN, + SPRING, + DAMPER, + INERTIA, + FRICTION, + CUSTOM_FORCE +}; +#endif + +#endif
\ No newline at end of file diff --git a/game/code/input/wheelrumble.cpp b/game/code/input/wheelrumble.cpp new file mode 100644 index 0000000..c9f4df3 --- /dev/null +++ b/game/code/input/wheelrumble.cpp @@ -0,0 +1,214 @@ +//============================================================================= +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: wheelrumble.cpp +// +// Description: Implement WheelRumble +// +// History: 6/25/2003 + Created -- Cary Brisebois +// +//============================================================================= + +//======================================== +// System Includes +//======================================== +// Foundation Tech +#include <raddebug.hpp> + + +//======================================== +// Project Includes +//======================================== +#include <input/wheelrumble.h> +#include <input/wheeldefines.h> +#include <input/inputmanager.h> + +//***************************************************************************** +// +// Global Data, Local Data, Local Classes +// +//***************************************************************************** + +//***************************************************************************** +// +// Public Member Functions +// +//***************************************************************************** + +//============================================================================= +// WheelRumble::WheelRumble +//============================================================================= +// Description: Constructor. +// +// Parameters: None. +// +// Return: N/A. +// +//============================================================================= +WheelRumble::WheelRumble() +{ +#ifdef RAD_WIN32 + m_diPeriodic.dwMagnitude = 0; + m_diPeriodic.lOffset = 0; + m_diPeriodic.dwPhase = 0; + m_diPeriodic.dwPeriod = 80; + + m_diEnvelope.dwSize = sizeof(DIENVELOPE); + m_diEnvelope.dwAttackLevel = 0; + m_diEnvelope.dwAttackTime = (DWORD)(0.5 * DI_SECONDS); + m_diEnvelope.dwFadeLevel = 0; + m_diEnvelope.dwFadeTime = (DWORD)(1 * DI_SECONDS); + + mForceEffect.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + mForceEffect.dwDuration = INFINITE; + mForceEffect.dwSamplePeriod = 0; + mForceEffect.dwGain = DI_FFNOMINALMAX; + mForceEffect.dwTriggerButton = DIEB_NOTRIGGER; + mForceEffect.dwTriggerRepeatInterval = 0; + mForceEffect.cAxes = 1; + mForceEffect.rgdwAxes = m_rgdwAxes; + mForceEffect.rglDirection = m_rglDirection; + mForceEffect.lpEnvelope = &m_diEnvelope; + mForceEffect.cbTypeSpecificParams = sizeof(DIPERIODIC); + mForceEffect.lpvTypeSpecificParams = &m_diPeriodic; + mForceEffect.dwStartDelay = 0; +#else + mForceEffect.type = LG_TYPE_TRIANGLE; + mForceEffect.duration = 500; + mForceEffect.startDelay = 0; + mForceEffect.p.periodic.magnitude = 0; + mForceEffect.p.periodic.direction = 90; + mForceEffect.p.periodic.period = 80; + mForceEffect.p.periodic.phase = 0; + mForceEffect.p.periodic.offset = 0; + mForceEffect.p.periodic.envelope.attackTime = 0; + mForceEffect.p.periodic.envelope.fadeTime = 0; + mForceEffect.p.periodic.envelope.attackLevel = 0; + mForceEffect.p.periodic.envelope.fadeLevel = 0; +#endif +} + +//============================================================================= +// WheelRumble::~WheelRumble +//============================================================================= +// Description: Destructor. +// +// Parameters: None. +// +// Return: N/A. +// +//============================================================================= +WheelRumble::~WheelRumble() +{ +} + +//============================================================================= +// WheelRumble::OnInit +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: void +// +//============================================================================= +void WheelRumble::OnInit() +{ +#ifdef RAD_WIN32 + m_diPeriodic.dwMagnitude = 0; +#else + mForceEffect.p.periodic.magnitude = 0; +#endif +} + +//============================================================================= +// WheelRumble::SetMagDir +//============================================================================= +// Description: Comment +// +// Parameters: ( u8 mag, u16 dir ) +// +// Return: void +// +//============================================================================= +#ifdef RAD_WIN32 +void WheelRumble::SetMagDir( u16 mag, u16 dir ) +#else +void WheelRumble::SetMagDir( u8 mag, u16 dir ) +#endif +{ +#ifdef RAD_WIN32 + LONG rglDirection[2] = { dir, 0 }; + m_diPeriodic.dwMagnitude = mag; + mForceEffect.rglDirection = rglDirection; +#else + mForceEffect.p.periodic.magnitude = mag; + mForceEffect.p.periodic.direction = dir; +#endif + + mEffectDirty = true; +} + +//============================================================================= +// WheelRumble::SetPPO +//============================================================================= +// Description: Comment +// +// Parameters: ( u16 per, u16 phas, s16 offset ) +// +// Return: void +// +//============================================================================= +void WheelRumble::SetPPO( u16 per, u16 phas, s16 offset ) +{ +#ifdef RAD_WIN32 + m_diPeriodic.dwPeriod = per; + m_diPeriodic.dwPhase = phas; + m_diPeriodic.lOffset = offset; +#else + mForceEffect.p.periodic.period = per; + mForceEffect.p.periodic.phase = phas; + mForceEffect.p.periodic.offset = offset; +#endif + + mEffectDirty = true; +} + +//============================================================================= +// WheelRumble::SetRumbleType +//============================================================================= +// Description: Comment +// +// Parameters: ( u8 type ) +// +// Return: void +// +//============================================================================= +void WheelRumble::SetRumbleType( u8 type ) +{ +#ifdef RAD_WIN32 + +#else + mForceEffect.type = type; +#endif + +}; + +#ifdef RAD_WIN32 +void WheelRumble::Update(unsigned timeins) +{ + m_currentTime += timeins; + if( m_currentTime > m_effectTime ) + { + SetMagDir(0,0); + m_currentTime = 0; + } + ForceEffect::Update(); +} +#endif + +//***************************************************************************** +// +// Private Member Functions +// +//***************************************************************************** diff --git a/game/code/input/wheelrumble.h b/game/code/input/wheelrumble.h new file mode 100644 index 0000000..2971833 --- /dev/null +++ b/game/code/input/wheelrumble.h @@ -0,0 +1,67 @@ +//============================================================================= +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: wheelrumble.h +// +// Description: Blahblahblah +// +// History: 6/25/2003 + Created -- Cary Brisebois +// +//============================================================================= + +#ifndef WHEELRUMBLE_H +#define WHEELRUMBLE_H + +//======================================== +// Nested Includes +//======================================== +#include <input/forceeffect.h> + +//======================================== +// Forward References +//======================================== + +//============================================================================= +// +// Synopsis: Blahblahblah +// +//============================================================================= + +class WheelRumble : public ForceEffect +{ +public: + WheelRumble(); + virtual ~WheelRumble(); + + void OnInit(); + +#ifdef RAD_WIN32 + void SetMagDir( u16 mag, u16 dir ); +#else + void SetMagDir( u8 mag, u16 dir ); +#endif + void SetPPO( u16 per, u16 phas, s16 offset ); + + void SetRumbleType( u8 type ); +#ifdef RAD_WIN32 + void Update(unsigned timeins = 0); +#endif + +private: + +#ifdef RAD_WIN32 + DIPERIODIC m_diPeriodic; + DIENVELOPE m_diEnvelope; +#endif + //Prevent wasteful constructor creation. + WheelRumble( const WheelRumble& wheelrumble ); + WheelRumble& operator=( const WheelRumble& wheelrumble ); +}; + +//***************************************************************************** +// +//Inline Public Member Functions +// +//***************************************************************************** + +#endif //WHEELRUMBLE_H |