//============================================================================= // 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 #include //======================================== // Project Includes //======================================== #include //***************************************************************************** // // 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(i), mCurrentEffects[ i ].mRumbleTimeLeft ); } mCurrentEffects[ i ].mRumbleTimeLeft = 0; } else { mCurrentEffects[ i ].mRumbleTimeLeft -= milliseconds; UpdateEffect( static_cast(i), milliseconds ); } } for ( i = 0; i < NUM_DYNA_EFFECTS; ++i ) { if ( mCurrentDynaEffects[ i ].mRumbleTimeLeft <= milliseconds ) { if ( mCurrentDynaEffects[ i ].mRumbleTimeLeft > 0 ) { UpdateDynaEffect( static_cast(i), mCurrentDynaEffects[ i ].mRumbleTimeLeft, mCurrentDynaEffects[ i ].mMaxGain ); } mCurrentDynaEffects[ i ].mRumbleTimeLeft = 0; } else { mCurrentDynaEffects[ i ].mRumbleTimeLeft -= milliseconds; UpdateDynaEffect( static_cast(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 }