Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

868 lines
24 KiB

  1. //======= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: Rumble effects mixer for XBox
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #include "c_rumble.h"
  10. #include "rumble_shared.h"
  11. #include "inputsystem/iinputsystem.h"
  12. #include "iinput.h"
  13. #ifdef _PS3
  14. #include "ps3/ps3_core.h"
  15. #endif
  16. // NOTE: This has to be the last file included!
  17. #include "tier0/memdbgon.h"
  18. void StopAllRumbleEffects( int userID );
  19. ConVar cl_rumblescale( "cl_rumblescale", "1.0", FCVAR_ARCHIVE | FCVAR_SS, "Scale sensitivity of rumble effects (0 to 1.0)" );
  20. ConVar cl_debugrumble( "cl_debugrumble", "0", FCVAR_ARCHIVE, "Turn on rumble debugging spew" );
  21. #define MAX_RUMBLE_CHANNELS 3 // Max concurrent rumble effects per player
  22. #define NUM_WAVE_SAMPLES 30 // Effects play at 10hz
  23. typedef struct
  24. {
  25. float amplitude_left[NUM_WAVE_SAMPLES];
  26. float amplitude_right[NUM_WAVE_SAMPLES];
  27. int numSamples;
  28. } RumbleWaveform_t;
  29. //=========================================================
  30. // Structure for a rumble effect channel. This is akin to
  31. // a sound channel that is playing a sound.
  32. //=========================================================
  33. typedef struct
  34. {
  35. float starttime; // When did this effect start playing? (gpGlobals->curtime)
  36. int waveformIndex; // Type of effect waveform used (an enum from rumble_shared.h)
  37. int priority; // How important this effect is (for making replacement decisions)
  38. bool in_use; // Is this channel in use?? (true if effect is currently playing, false if done or otherwise available)
  39. unsigned char rumbleFlags; // Flags pertaining to the effect currently playing on this channel.
  40. float scale; // Some effects are updated while they are running.
  41. } RumbleChannel_t;
  42. //=========================================================
  43. // This structure contains parameters necessary to generate
  44. // a sine or sawtooth waveform.
  45. //=========================================================
  46. typedef struct tagWaveGenParams
  47. {
  48. float cycles; // AKA frequency
  49. float amplitudescale;
  50. bool leftChannel; // If false, generating for the right channel
  51. float maxAmplitude; // Clamping
  52. float minAmplitude;
  53. void Set( float c_cycles, float c_amplitudescale, bool c_leftChannel, float c_minAmplitude, float c_maxAmplitude )
  54. {
  55. cycles = c_cycles;
  56. amplitudescale = c_amplitudescale;
  57. leftChannel = c_leftChannel;
  58. minAmplitude = c_minAmplitude;
  59. maxAmplitude = c_maxAmplitude;
  60. }
  61. // CTOR
  62. tagWaveGenParams( float c_cycles, float c_amplitudescale, bool c_leftChannel, float c_minAmplitude, float c_maxAmplitude )
  63. {
  64. Set( c_cycles, c_amplitudescale, c_leftChannel, c_minAmplitude, c_maxAmplitude );
  65. }
  66. } WaveGenParams_t;
  67. //---------------------------------------------------------
  68. //---------------------------------------------------------
  69. void TerminateWaveform( RumbleWaveform_t *pWaveform, int samples )
  70. {
  71. if( samples <= NUM_WAVE_SAMPLES )
  72. {
  73. pWaveform->numSamples = samples;
  74. }
  75. }
  76. //---------------------------------------------------------
  77. //---------------------------------------------------------
  78. void EaseInWaveform( RumbleWaveform_t *pWaveform, int samples, bool left )
  79. {
  80. float step = 1.0f / ((float)samples);
  81. float factor = 0.0f;
  82. for( int i = 0 ; i < samples ; i++ )
  83. {
  84. if( left )
  85. {
  86. pWaveform->amplitude_left[i] *= factor;
  87. }
  88. else
  89. {
  90. pWaveform->amplitude_right[i] *= factor;
  91. }
  92. factor += step;
  93. }
  94. }
  95. //---------------------------------------------------------
  96. //---------------------------------------------------------
  97. void EaseOutWaveform( RumbleWaveform_t *pWaveform, int samples, bool left )
  98. {
  99. float step = 1.0f / ((float)samples);
  100. float factor = 0.0f;
  101. int i = NUM_WAVE_SAMPLES - 1;
  102. for( int j = 0 ; j < samples ; j++ )
  103. {
  104. if( left )
  105. {
  106. pWaveform->amplitude_left[i] *= factor;
  107. }
  108. else
  109. {
  110. pWaveform->amplitude_right[i] *= factor;
  111. }
  112. factor += step;
  113. i--;
  114. }
  115. }
  116. //---------------------------------------------------------
  117. //---------------------------------------------------------
  118. void GenerateSawtoothEffect( RumbleWaveform_t *pWaveform, const WaveGenParams_t &params )
  119. {
  120. float delta = params.maxAmplitude - params.minAmplitude;
  121. int waveLength = NUM_WAVE_SAMPLES / params.cycles;
  122. float vstep = (delta / waveLength);
  123. float amplitude = params.minAmplitude;
  124. for( int i = 0 ; i < NUM_WAVE_SAMPLES ; i++ )
  125. {
  126. if( params.leftChannel )
  127. {
  128. pWaveform->amplitude_left[i] = amplitude;
  129. }
  130. else
  131. {
  132. pWaveform->amplitude_right[i] = amplitude;
  133. }
  134. amplitude += vstep;
  135. if( amplitude > params.maxAmplitude )
  136. {
  137. amplitude = params.minAmplitude;
  138. }
  139. }
  140. }
  141. //---------------------------------------------------------
  142. //---------------------------------------------------------
  143. void GenerateSquareWaveEffect( RumbleWaveform_t *pWaveform, const WaveGenParams_t &params )
  144. {
  145. int i = 0;
  146. int j;
  147. int steps = ((float)NUM_WAVE_SAMPLES) / (params.cycles*2.0f);
  148. while( i < NUM_WAVE_SAMPLES )
  149. {
  150. for( j = 0 ; j < steps ; j++ )
  151. {
  152. if( params.leftChannel )
  153. {
  154. pWaveform->amplitude_left[i++] = params.minAmplitude;
  155. }
  156. else
  157. {
  158. pWaveform->amplitude_right[i++] = params.minAmplitude;
  159. }
  160. }
  161. for( j = 0 ; j < steps ; j++ )
  162. {
  163. if( params.leftChannel )
  164. {
  165. pWaveform->amplitude_left[i++] = params.maxAmplitude;
  166. }
  167. else
  168. {
  169. pWaveform->amplitude_right[i++] = params.maxAmplitude;
  170. }
  171. }
  172. }
  173. }
  174. //---------------------------------------------------------
  175. // If you pass a numSamples, this wave will only be that many
  176. // samples long.
  177. //---------------------------------------------------------
  178. void GenerateFlatEffect( RumbleWaveform_t *pWaveform, const WaveGenParams_t &params )
  179. {
  180. for( int i = 0 ; i < NUM_WAVE_SAMPLES ; i++ )
  181. {
  182. if( params.leftChannel )
  183. {
  184. pWaveform->amplitude_left[i] = params.maxAmplitude;
  185. }
  186. else
  187. {
  188. pWaveform->amplitude_right[i] = params.maxAmplitude;
  189. }
  190. }
  191. }
  192. //---------------------------------------------------------
  193. //---------------------------------------------------------
  194. void GenerateSineWaveEffect( RumbleWaveform_t *pWaveform, const WaveGenParams_t &params )
  195. {
  196. float step = (360.0f * (params.cycles * 0.5f) ) / ((float)NUM_WAVE_SAMPLES);
  197. float degrees = 180.0f + step; // 180 to start at 0
  198. for( int i = 0 ; i < NUM_WAVE_SAMPLES ; i++ )
  199. {
  200. float radians = DEG2RAD(degrees);
  201. float value = fabs( sin(radians) );
  202. value *= params.amplitudescale;
  203. if( value < params.minAmplitude )
  204. value = params.minAmplitude;
  205. if( value > params.maxAmplitude )
  206. value = params.maxAmplitude;
  207. if( params.leftChannel )
  208. {
  209. pWaveform->amplitude_left[i] = value;
  210. }
  211. else
  212. {
  213. pWaveform->amplitude_right[i] = value;
  214. }
  215. degrees += step;
  216. }
  217. }
  218. //=========================================================
  219. //=========================================================
  220. class CRumbleEffects
  221. {
  222. public:
  223. CRumbleEffects()
  224. {
  225. Init();
  226. }
  227. void Init();
  228. void SetOutputEnabled( bool bEnable );
  229. void StartEffect( int userID, unsigned char effectIndex, unsigned char rumbleData, unsigned char rumbleFlags );
  230. void StopEffect( int userID, int effectIndex );
  231. void StopAllEffects( int userID );
  232. void ComputeAmplitudes( RumbleChannel_t *pChannel, float curtime, float *pLeft, float *pRight );
  233. void UpdateEffects( int userID, float curtime );
  234. void UpdateScreenShakeRumble( int userID, float shake, float balance );
  235. RumbleChannel_t *FindExistingChannel( int userID, int index );
  236. RumbleChannel_t *FindAvailableChannel( int userID, int priority );
  237. public:
  238. RumbleChannel_t m_Channels[ MAX_SPLITSCREEN_PLAYERS ][ MAX_RUMBLE_CHANNELS ];
  239. RumbleWaveform_t m_Waveforms[ NUM_RUMBLE_EFFECTS ];
  240. float m_flScreenShake[ MAX_SPLITSCREEN_PLAYERS ];
  241. bool m_bOutputEnabled;
  242. };
  243. CRumbleEffects g_RumbleEffects;
  244. //---------------------------------------------------------
  245. //---------------------------------------------------------
  246. void CRumbleEffects::Init()
  247. {
  248. SetOutputEnabled( true );
  249. int userID,channel;
  250. for( userID = 0 ; userID < MAX_SPLITSCREEN_PLAYERS ; userID++ )
  251. {
  252. for( channel = 0 ; channel < MAX_RUMBLE_CHANNELS ; channel++ )
  253. {
  254. m_Channels[userID][channel].in_use = false;
  255. m_Channels[userID][channel].priority = 0;
  256. }
  257. }
  258. // Every effect defaults to this many samples. Call TerminateWaveform() to trim these.
  259. for ( int i = 0 ; i < NUM_RUMBLE_EFFECTS ; i++ )
  260. {
  261. m_Waveforms[i].numSamples = NUM_WAVE_SAMPLES;
  262. }
  263. // Jeep Idle
  264. WaveGenParams_t params( 1, 1.0f, false, 0.0f, 0.15f );
  265. GenerateFlatEffect( &m_Waveforms[RUMBLE_JEEP_ENGINE_LOOP], params );
  266. // Pistol
  267. params.Set( 1, 1.0f, false, 0.0f, 0.6f );
  268. GenerateFlatEffect( &m_Waveforms[RUMBLE_PISTOL], params );
  269. TerminateWaveform( &m_Waveforms[RUMBLE_PISTOL], 1 );
  270. // SMG1
  271. params.Set( 1, 1.0f, true, 0.0f, 0.4f );
  272. GenerateFlatEffect( &m_Waveforms[RUMBLE_SMG1], params );
  273. params.Set( 1, 1.0f, false, 0.0f, 0.3f );
  274. GenerateFlatEffect( &m_Waveforms[RUMBLE_SMG1], params );
  275. TerminateWaveform( &m_Waveforms[RUMBLE_SMG1], 1 );
  276. // AR2
  277. params.Set( 1, 1.0f, true, 0.0f, 0.55f );
  278. GenerateFlatEffect( &m_Waveforms[RUMBLE_AR2], params );
  279. params.Set( 1, 1.0f, false, 0.0f, 0.3f );
  280. GenerateFlatEffect( &m_Waveforms[RUMBLE_AR2], params );
  281. TerminateWaveform( &m_Waveforms[RUMBLE_AR2], 1 );
  282. // AR2 Alt
  283. params.Set( 1, 1.0f, true, 0.0, 0.5f );
  284. GenerateFlatEffect( &m_Waveforms[RUMBLE_AR2_ALT_FIRE], params );
  285. EaseInWaveform( &m_Waveforms[RUMBLE_AR2_ALT_FIRE], 5, true );
  286. params.Set( 1, 1.0f, false, 0.0, 0.7f );
  287. GenerateFlatEffect( &m_Waveforms[RUMBLE_AR2_ALT_FIRE], params );
  288. EaseInWaveform( &m_Waveforms[RUMBLE_AR2_ALT_FIRE], 5, false );
  289. TerminateWaveform( &m_Waveforms[RUMBLE_AR2_ALT_FIRE], 7 );
  290. // 357
  291. params.Set( 1, 1.0f, true, 0.0f, 0.75f );
  292. GenerateFlatEffect( &m_Waveforms[RUMBLE_357], params );
  293. params.Set( 1, 1.0f, false, 0.0f, 0.75f );
  294. GenerateFlatEffect( &m_Waveforms[RUMBLE_357], params );
  295. TerminateWaveform( &m_Waveforms[RUMBLE_357], 2 );
  296. // Shotgun
  297. params.Set( 1, 1.0f, true, 0.0f, 0.7f );
  298. GenerateFlatEffect( &m_Waveforms[RUMBLE_SHOTGUN_SINGLE], params );
  299. params.Set( 1, 1.0f, false, 0.0f, 0.7f );
  300. GenerateFlatEffect( &m_Waveforms[RUMBLE_SHOTGUN_SINGLE], params );
  301. TerminateWaveform( &m_Waveforms[RUMBLE_SHOTGUN_SINGLE], 3 );
  302. params.Set( 1, 1.0f, true, 0.0f, 1.0f );
  303. GenerateFlatEffect( &m_Waveforms[RUMBLE_SHOTGUN_DOUBLE], params );
  304. params.Set( 1, 1.0f, false, 0.0f, 1.0f );
  305. GenerateFlatEffect( &m_Waveforms[RUMBLE_SHOTGUN_DOUBLE], params );
  306. TerminateWaveform( &m_Waveforms[RUMBLE_SHOTGUN_DOUBLE], 3 );
  307. // RPG Missile
  308. params.Set( 1, 1.0f, false, 0.0f, 0.3f );
  309. GenerateFlatEffect( &m_Waveforms[RUMBLE_RPG_MISSILE], params );
  310. EaseOutWaveform( &m_Waveforms[RUMBLE_RPG_MISSILE], 30, false );
  311. TerminateWaveform( &m_Waveforms[RUMBLE_RPG_MISSILE], 6 );
  312. // Physcannon open forks
  313. params.Set( 1, 1.0f, false, 0.0f, 0.25f );
  314. GenerateFlatEffect( &m_Waveforms[RUMBLE_PHYSCANNON_OPEN], params );
  315. TerminateWaveform( &m_Waveforms[RUMBLE_PHYSCANNON_OPEN], 4 );
  316. // Physcannon holding something
  317. params.Set( 1, 1.0f, true, 0.0f, 0.2f );
  318. GenerateFlatEffect( &m_Waveforms[RUMBLE_PHYSCANNON_LOW], params );
  319. params.Set( 6, 1.0f, false, 0.0f, 0.25f );
  320. GenerateSquareWaveEffect( &m_Waveforms[RUMBLE_PHYSCANNON_LOW], params );
  321. // Crowbar
  322. params.Set( 1, 1.0f, false, 0.0f, 0.25f );
  323. GenerateFlatEffect( &m_Waveforms[RUMBLE_CROWBAR_SWING], params );
  324. EaseOutWaveform( &m_Waveforms[RUMBLE_CROWBAR_SWING], 30, false );
  325. TerminateWaveform( &m_Waveforms[RUMBLE_CROWBAR_SWING], 3 );
  326. // Airboat gun
  327. params.Set( 1, 1.0f, false, 0.0f, 0.4f );
  328. GenerateFlatEffect( &m_Waveforms[RUMBLE_AIRBOAT_GUN], params );
  329. params.Set( 12, 1.0f, true, 0.0f, 0.5f );
  330. GenerateSawtoothEffect( &m_Waveforms[RUMBLE_AIRBOAT_GUN], params );
  331. // Generic flat effects.
  332. params.Set( 1, 1.0f, true, 0.0f, 1.0f );
  333. GenerateFlatEffect( &m_Waveforms[RUMBLE_FLAT_LEFT], params );
  334. params.Set( 1, 1.0f, false, 0.0f, 1.0f );
  335. GenerateFlatEffect( &m_Waveforms[RUMBLE_FLAT_RIGHT], params );
  336. params.Set( 1, 1.0f, true, 0.0f, 1.0f );
  337. GenerateFlatEffect( &m_Waveforms[RUMBLE_FLAT_BOTH], params );
  338. params.Set( 1, 1.0f, false, 0.0f, 1.0f );
  339. GenerateFlatEffect( &m_Waveforms[RUMBLE_FLAT_BOTH], params );
  340. // Impact from a long fall
  341. params.Set( 1, 1.0f, false, 0.0f, 0.5f );
  342. GenerateFlatEffect( &m_Waveforms[RUMBLE_FALL_LONG], params );
  343. params.Set( 1, 1.0f, true, 0.0f, 0.5f );
  344. GenerateFlatEffect( &m_Waveforms[RUMBLE_FALL_LONG], params );
  345. TerminateWaveform( &m_Waveforms[RUMBLE_FALL_LONG], 3 );
  346. // Impact from a short fall
  347. params.Set( 1, 1.0f, false, 0.0f, 0.3f );
  348. GenerateFlatEffect( &m_Waveforms[RUMBLE_FALL_SHORT], params );
  349. params.Set( 1, 1.0f, true, 0.0f, 0.3f );
  350. GenerateFlatEffect( &m_Waveforms[RUMBLE_FALL_SHORT], params );
  351. TerminateWaveform( &m_Waveforms[RUMBLE_FALL_SHORT], 2 );
  352. // Portalgun left (blue) shot
  353. params.Set( 1, 1.0f, true, 0.0f, 0.3f );
  354. GenerateFlatEffect( &m_Waveforms[RUMBLE_PORTALGUN_LEFT], params );
  355. TerminateWaveform( &m_Waveforms[RUMBLE_PORTALGUN_LEFT], 2 );
  356. // Portalgun right (red) shot
  357. params.Set( 1, 1.0f, false, 0.0f, 0.3f );
  358. GenerateFlatEffect( &m_Waveforms[RUMBLE_PORTALGUN_RIGHT], params );
  359. TerminateWaveform( &m_Waveforms[RUMBLE_PORTALGUN_RIGHT], 2 );
  360. // Portal failed to place feedback
  361. params.Set( 4, 1.0f, true, 0.0f, 0.25f );
  362. GenerateSquareWaveEffect( &m_Waveforms[RUMBLE_PORTAL_PLACEMENT_FAILURE], params );
  363. params.Set( 4, 1.0f, false, 0.0f, 0.25f );
  364. GenerateSquareWaveEffect( &m_Waveforms[RUMBLE_PORTAL_PLACEMENT_FAILURE], params );
  365. TerminateWaveform( &m_Waveforms[RUMBLE_PORTAL_PLACEMENT_FAILURE], 6 );
  366. // RUMBLE_DMG_LOW (copied from 357)
  367. params.Set( 1, 1.0f, true, 0.0f, 0.75f );
  368. GenerateFlatEffect( &m_Waveforms[RUMBLE_DMG_LOW], params );
  369. params.Set( 1, 1.0f, false, 0.0f, 0.75f );
  370. GenerateFlatEffect( &m_Waveforms[RUMBLE_DMG_LOW], params );
  371. TerminateWaveform( &m_Waveforms[RUMBLE_DMG_LOW], 2 );
  372. // RUMBLE_DMG_HIGH (copied from AR2)
  373. params.Set( 1, 1.0f, true, 0.0f, 0.5f );
  374. GenerateFlatEffect( &m_Waveforms[RUMBLE_DMG_HIGH], params );
  375. params.Set( 1, 1.0f, false, 0.0f, 0.3f );
  376. GenerateFlatEffect( &m_Waveforms[RUMBLE_DMG_HIGH], params );
  377. TerminateWaveform( &m_Waveforms[RUMBLE_DMG_HIGH], 1 );
  378. }
  379. //---------------------------------------------------------
  380. //---------------------------------------------------------
  381. RumbleChannel_t *CRumbleEffects::FindExistingChannel( int userID, int index )
  382. {
  383. RumbleChannel_t *pChannel;
  384. for( int i = 0 ; i < MAX_RUMBLE_CHANNELS ; i++ )
  385. {
  386. pChannel = &m_Channels[userID][i];
  387. if( pChannel->in_use && pChannel->waveformIndex == index )
  388. {
  389. // This effect is already playing. Provide this channel for the
  390. // effect to be re-started on.
  391. return pChannel;
  392. }
  393. }
  394. return NULL;
  395. }
  396. //---------------------------------------------------------
  397. // priority - the priority of the effect we want to play.
  398. //---------------------------------------------------------
  399. RumbleChannel_t *CRumbleEffects::FindAvailableChannel( int userID, int priority )
  400. {
  401. RumbleChannel_t *pChannel;
  402. int i;
  403. for( i = 0 ; i < MAX_RUMBLE_CHANNELS ; i++ )
  404. {
  405. pChannel = &m_Channels[userID][i];
  406. if( !pChannel->in_use )
  407. {
  408. return pChannel;
  409. }
  410. }
  411. int lowestPriority = priority;
  412. RumbleChannel_t *pBestChannel = NULL;
  413. float oldestChannel = FLT_MAX;
  414. // All channels already in use. Find a channel to slam. Make sure it belongs to this userID
  415. for( i = 0 ; i < MAX_RUMBLE_CHANNELS ; i++ )
  416. {
  417. pChannel = &m_Channels[userID][i];
  418. if( (pChannel->rumbleFlags & RUMBLE_FLAG_LOOP) )
  419. continue;
  420. if( pChannel->priority < lowestPriority )
  421. {
  422. // Always happily slam a lower priority sound.
  423. pBestChannel = pChannel;
  424. lowestPriority = pChannel->priority;
  425. }
  426. else if( pChannel->priority == lowestPriority )
  427. {
  428. // Priority is the same, so replace the oldest.
  429. if( pBestChannel )
  430. {
  431. // If we already have a channel of the same priority to discard, make sure we discard the oldest.
  432. float age = gpGlobals->curtime - pChannel->starttime;
  433. if( age > oldestChannel )
  434. {
  435. pBestChannel = pChannel;
  436. oldestChannel = age;
  437. }
  438. }
  439. else
  440. {
  441. // Take it.
  442. pBestChannel = pChannel;
  443. oldestChannel = gpGlobals->curtime - pChannel->starttime;
  444. }
  445. }
  446. }
  447. return pBestChannel; // Can still be NULL if we couldn't find a channel to slam.
  448. }
  449. //---------------------------------------------------------
  450. //---------------------------------------------------------
  451. void CRumbleEffects::SetOutputEnabled( bool bEnable )
  452. {
  453. m_bOutputEnabled = bEnable;
  454. if( !bEnable )
  455. {
  456. // Tell the hardware to shut down motors right now, in case this gets called
  457. // and some other process blocks us before the next rumble system update.
  458. for( int i = 0 ; i < MAX_SPLITSCREEN_PLAYERS ; i++ )
  459. {
  460. m_flScreenShake[ i ] = 0.0f;
  461. StopAllRumbleEffects( i );
  462. }
  463. }
  464. }
  465. //---------------------------------------------------------
  466. //---------------------------------------------------------
  467. void CRumbleEffects::StartEffect( int userID, unsigned char effectIndex, unsigned char rumbleData, unsigned char rumbleFlags )
  468. {
  469. if( effectIndex == RUMBLE_STOP_ALL )
  470. {
  471. StopAllEffects( userID );
  472. return;
  473. }
  474. if( rumbleFlags & RUMBLE_FLAG_STOP )
  475. {
  476. StopEffect( userID, effectIndex );
  477. return;
  478. }
  479. if ( !input->ControllerModeActive() )
  480. return;
  481. int priority = 1;
  482. RumbleChannel_t *pChannel = NULL;
  483. if( (rumbleFlags & RUMBLE_FLAG_RESTART) )
  484. {
  485. // Try to find any active instance of this effect and replace it.
  486. pChannel = FindExistingChannel( userID, effectIndex );
  487. }
  488. if( (rumbleFlags & RUMBLE_FLAG_ONLYONE) )
  489. {
  490. pChannel = FindExistingChannel( userID, effectIndex );
  491. if( pChannel )
  492. {
  493. // Bail out. An instance of this effect is already playing.
  494. return;
  495. }
  496. }
  497. if( (rumbleFlags & RUMBLE_FLAG_UPDATE_SCALE) )
  498. {
  499. pChannel = FindExistingChannel( userID, effectIndex );
  500. if( pChannel )
  501. {
  502. pChannel->scale = ((float)rumbleData) / 100.0f;
  503. }
  504. // It's possible to return without finding a rumble to update.
  505. // This means you tried to update a rumble you never started.
  506. return;
  507. }
  508. if( !pChannel )
  509. {
  510. pChannel = FindAvailableChannel( userID, priority );
  511. }
  512. if( pChannel )
  513. {
  514. pChannel->waveformIndex = effectIndex;
  515. pChannel->priority = 1;
  516. pChannel->starttime = gpGlobals->curtime;
  517. pChannel->in_use = true;
  518. pChannel->rumbleFlags = rumbleFlags;
  519. if( rumbleFlags & RUMBLE_FLAG_INITIAL_SCALE )
  520. {
  521. pChannel->scale = ((float)rumbleData) / 100.0f;
  522. }
  523. else
  524. {
  525. pChannel->scale = 1.0f;
  526. }
  527. }
  528. if( (rumbleFlags & RUMBLE_FLAG_RANDOM_AMPLITUDE) )
  529. {
  530. pChannel->scale = random->RandomFloat( 0.1f, 1.0f );
  531. }
  532. }
  533. //---------------------------------------------------------
  534. // Find all playing effects of this type and stop them.
  535. //---------------------------------------------------------
  536. void CRumbleEffects::StopEffect( int userID, int effectIndex )
  537. {
  538. for( int i = 0 ; i < MAX_RUMBLE_CHANNELS ; i++ )
  539. {
  540. if( m_Channels[userID][i].in_use && m_Channels[userID][i].waveformIndex == effectIndex )
  541. {
  542. m_Channels[userID][i].in_use = false;
  543. }
  544. }
  545. }
  546. //---------------------------------------------------------
  547. //---------------------------------------------------------
  548. void CRumbleEffects::StopAllEffects( int userID )
  549. {
  550. for( int i = 0 ; i < MAX_RUMBLE_CHANNELS ; i++ )
  551. {
  552. m_Channels[userID][i].in_use = false;
  553. }
  554. m_flScreenShake[ userID ] = 0.0f;
  555. }
  556. //---------------------------------------------------------
  557. //---------------------------------------------------------
  558. void CRumbleEffects::ComputeAmplitudes( RumbleChannel_t *pChannel, float curtime, float *pLeft, float *pRight )
  559. {
  560. // How long has this waveform been playing?
  561. float elapsed = curtime - pChannel->starttime;
  562. if( elapsed >= (NUM_WAVE_SAMPLES/10) )
  563. {
  564. if( (pChannel->rumbleFlags & RUMBLE_FLAG_LOOP) )
  565. {
  566. // This effect loops. Just fixup the start time and recompute elapsed.
  567. pChannel->starttime = curtime;
  568. elapsed = curtime - pChannel->starttime;
  569. }
  570. else
  571. {
  572. // This effect is done! Should it loop?
  573. *pLeft = 0;
  574. *pRight = 0;
  575. pChannel->in_use = false;
  576. return;
  577. }
  578. }
  579. // Figure out which sample we're playing FROM.
  580. int seconds = ((int) elapsed);
  581. int sample = (int)(elapsed*10.0f);
  582. // Get the fraction bit.
  583. float fraction, left, right;
  584. fraction = elapsed - seconds;
  585. if( sample == m_Waveforms[pChannel->waveformIndex].numSamples )
  586. {
  587. // This effect is done. Send zeroes to the mixer for this
  588. // final frame and then turn the channel off. (Unless it loops!)
  589. if( (pChannel->rumbleFlags & RUMBLE_FLAG_LOOP) )
  590. {
  591. // Loop this effect
  592. pChannel->starttime = gpGlobals->curtime;
  593. // Send the first sample.
  594. left = m_Waveforms[pChannel->waveformIndex].amplitude_left[0];
  595. right = m_Waveforms[pChannel->waveformIndex].amplitude_right[0];
  596. }
  597. else
  598. {
  599. left = 0.0f;
  600. right = 0.0f;
  601. pChannel->in_use = false;
  602. }
  603. }
  604. else
  605. {
  606. // Use values for the last sample that we have passed
  607. left = m_Waveforms[pChannel->waveformIndex].amplitude_left[sample];
  608. right = m_Waveforms[pChannel->waveformIndex].amplitude_right[sample];
  609. }
  610. left *= pChannel->scale;
  611. right *= pChannel->scale;
  612. if( cl_debugrumble.GetBool() )
  613. {
  614. Msg("Seconds:%d Fraction:%f Sample:%d L:%f R:%f\n", seconds, fraction, sample, left, right );
  615. }
  616. if( !m_bOutputEnabled )
  617. {
  618. // Send zeroes to stop any current rumbling, and to keep it silenced.
  619. left = 0;
  620. right = 0;
  621. }
  622. *pLeft = left;
  623. *pRight = right;
  624. }
  625. //---------------------------------------------------------
  626. //---------------------------------------------------------
  627. void CRumbleEffects::UpdateScreenShakeRumble( int userID, float shake, float balance )
  628. {
  629. if( m_bOutputEnabled )
  630. {
  631. m_flScreenShake[ userID ] = shake;
  632. }
  633. else
  634. {
  635. // Silence
  636. m_flScreenShake[ userID ] = 0.0f;
  637. }
  638. }
  639. //---------------------------------------------------------
  640. //---------------------------------------------------------
  641. void CRumbleEffects::UpdateEffects( int userID, float curtime )
  642. {
  643. float fLeftMotor = 0.0f;
  644. float fRightMotor = 0.0f;
  645. for( int i = 0 ; i < MAX_RUMBLE_CHANNELS ; i++ )
  646. {
  647. // Expire old channels
  648. RumbleChannel_t *pChannel = &m_Channels[userID][i];
  649. if( pChannel->in_use )
  650. {
  651. float left = 0, right = 0;
  652. ComputeAmplitudes( pChannel, curtime, &left, &right );
  653. fLeftMotor += left;
  654. fRightMotor += right;
  655. }
  656. }
  657. // Add in any screenshake
  658. float shakeLeft = 0.0f;
  659. float shakeRight = 0.0f;
  660. if( m_flScreenShake[ userID ] != 0.0f )
  661. {
  662. if( m_flScreenShake[ userID ] < 0.0f )
  663. {
  664. shakeLeft = fabs( m_flScreenShake[ userID ] );
  665. }
  666. else
  667. {
  668. shakeRight = m_flScreenShake[ userID ];
  669. }
  670. }
  671. fLeftMotor += shakeLeft;
  672. fRightMotor += shakeRight;
  673. fLeftMotor *= cl_rumblescale.GetFloat();
  674. fRightMotor *= cl_rumblescale.GetFloat();
  675. if ( engine->IsPaused() || !input->ControllerModeActive() )
  676. {
  677. // Send nothing when paused or vibration disabled or not using controller.
  678. fLeftMotor = 0.0f;
  679. fRightMotor = 0.0f;
  680. }
  681. inputsystem->SetRumble( fLeftMotor, fRightMotor, userID );
  682. }
  683. //---------------------------------------------------------
  684. //---------------------------------------------------------
  685. void StopAllRumbleEffects( int userID )
  686. {
  687. // Kill all rumble channels that have effects assigned to this userID,
  688. // and stop the motors.
  689. g_RumbleEffects.StopAllEffects( userID );
  690. inputsystem->StopRumble( userID );
  691. }
  692. //---------------------------------------------------------
  693. //---------------------------------------------------------
  694. void RumbleEffect( int userID, unsigned char effectIndex, unsigned char rumbleData, unsigned char rumbleFlags )
  695. {
  696. g_RumbleEffects.StartEffect( userID, effectIndex, rumbleData, rumbleFlags );
  697. }
  698. //---------------------------------------------------------
  699. //---------------------------------------------------------
  700. void UpdateRumbleEffects( int userID )
  701. {
  702. // dkorus: maybe only stop weapon driven rumble effects?
  703. // this was short circuiting the damage rumbles when being killed
  704. C_BasePlayer *player = C_BasePlayer::GetLocalPlayer( XBX_GetSlotByUserId( userID ) );
  705. if( !player )
  706. {
  707. StopAllRumbleEffects( userID );
  708. return;
  709. }
  710. g_RumbleEffects.UpdateEffects( userID, gpGlobals->curtime );
  711. }
  712. //---------------------------------------------------------
  713. //---------------------------------------------------------
  714. void UpdateScreenShakeRumble( int userID, float shake, float balance )
  715. {
  716. C_BasePlayer *player = C_BasePlayer::GetLocalPlayer( XBX_GetSlotByUserId( userID ) );
  717. if( !player || !player->IsAlive() )
  718. {
  719. return;
  720. }
  721. g_RumbleEffects.UpdateScreenShakeRumble( userID, shake, balance );
  722. }
  723. //---------------------------------------------------------
  724. //---------------------------------------------------------
  725. void EnableRumbleOutput( bool bEnable )
  726. {
  727. g_RumbleEffects.SetOutputEnabled( bEnable );
  728. }