Team Fortress 2 Source Code as on 22/4/2020
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.

826 lines
22 KiB

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