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.

177 lines
5.3 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #ifndef VPHYSICS_SOUND_H
  8. #define VPHYSICS_SOUND_H
  9. #ifdef _WIN32
  10. #pragma once
  11. #endif
  12. #include "SoundEmitterSystem/isoundemittersystembase.h"
  13. namespace physicssound
  14. {
  15. struct impactsound_t
  16. {
  17. void *pGameData;
  18. int entityIndex;
  19. int soundChannel;
  20. float volume;
  21. float impactSpeed;
  22. unsigned short surfaceProps;
  23. unsigned short surfacePropsHit;
  24. Vector origin;
  25. };
  26. // UNDONE: Use a sorted container and sort by volume/distance?
  27. struct soundlist_t
  28. {
  29. CUtlVector<impactsound_t> elements;
  30. impactsound_t &GetElement(int index) { return elements[index]; }
  31. impactsound_t &AddElement() { return elements[elements.AddToTail()]; }
  32. int Count() { return elements.Count(); }
  33. void RemoveAll() { elements.RemoveAll(); }
  34. };
  35. void PlayImpactSounds( soundlist_t &list )
  36. {
  37. for ( int i = list.Count()-1; i >= 0; --i )
  38. {
  39. impactsound_t &sound = list.GetElement(i);
  40. const surfacedata_t *psurf = physprops->GetSurfaceData( sound.surfaceProps );
  41. if ( psurf->sounds.impactHard )
  42. {
  43. const surfacedata_t *pHit = physprops->GetSurfaceData( sound.surfacePropsHit );
  44. unsigned short soundName = psurf->sounds.impactHard;
  45. if ( pHit && psurf->sounds.impactSoft )
  46. {
  47. if ( pHit->audio.hardnessFactor < psurf->audio.hardThreshold ||
  48. (psurf->audio.hardVelocityThreshold > 0 && psurf->audio.hardVelocityThreshold > sound.impactSpeed) )
  49. {
  50. soundName = psurf->sounds.impactSoft;
  51. }
  52. }
  53. const char *pSound = physprops->GetString( soundName );
  54. CSoundParameters params;
  55. if ( !CBaseEntity::GetParametersForSound( pSound, params, NULL ) )
  56. break;
  57. if ( sound.volume > 1 )
  58. sound.volume = 1;
  59. CPASAttenuationFilter filter( sound.origin, params.soundlevel );
  60. // JAY: If this entity gets deleted, the sound comes out at the world origin
  61. // this sounds bad! Play on ent 0 for now.
  62. EmitSound_t ep;
  63. ep.m_nChannel = sound.soundChannel;
  64. ep.m_pSoundName = params.soundname;
  65. ep.m_flVolume = params.volume * sound.volume;
  66. ep.m_SoundLevel = params.soundlevel;
  67. ep.m_nPitch = params.pitch;
  68. ep.m_pOrigin = &sound.origin;
  69. CBaseEntity::EmitSound( filter, 0 /*sound.entityIndex*/, ep );
  70. }
  71. }
  72. list.RemoveAll();
  73. }
  74. void AddImpactSound( soundlist_t &list, void *pGameData, int entityIndex, int soundChannel, IPhysicsObject *pObject, int surfaceProps, int surfacePropsHit, float volume, float impactSpeed )
  75. {
  76. impactSpeed += 1e-4;
  77. for ( int i = list.Count()-1; i >= 0; --i )
  78. {
  79. impactsound_t &sound = list.GetElement(i);
  80. // UNDONE: Compare entity or channel somehow?
  81. // UNDONE: Doing one slot per entity is too noisy. So now we use one slot per material
  82. // heuristic - after 4 impacts sounds in one frame, start merging everything
  83. if ( surfaceProps == sound.surfaceProps || list.Count() > 4 )
  84. {
  85. // UNDONE: Store instance volume separate from aggregate volume and compare that?
  86. if ( volume > sound.volume )
  87. {
  88. pObject->GetPosition( &sound.origin, NULL );
  89. sound.pGameData = pGameData;
  90. sound.entityIndex = entityIndex;
  91. sound.soundChannel = soundChannel;
  92. sound.surfacePropsHit = surfacePropsHit;
  93. }
  94. sound.volume += volume;
  95. sound.impactSpeed = MAX(impactSpeed,sound.impactSpeed);
  96. return;
  97. }
  98. }
  99. impactsound_t &sound = list.AddElement();
  100. sound.pGameData = pGameData;
  101. sound.entityIndex = entityIndex;
  102. sound.soundChannel = soundChannel;
  103. pObject->GetPosition( &sound.origin, NULL );
  104. sound.surfaceProps = surfaceProps;
  105. sound.surfacePropsHit = surfacePropsHit;
  106. sound.volume = volume;
  107. sound.impactSpeed = impactSpeed;
  108. }
  109. struct breaksound_t
  110. {
  111. Vector origin;
  112. int surfacePropsBreak;
  113. };
  114. void AddBreakSound( CUtlVector<breaksound_t> &list, const Vector &origin, unsigned short surfaceProps )
  115. {
  116. const surfacedata_t *psurf = physprops->GetSurfaceData( surfaceProps );
  117. if ( !psurf->sounds.breakSound )
  118. return;
  119. for ( int i = list.Count()-1; i >= 0; --i )
  120. {
  121. breaksound_t &sound = list.Element(i);
  122. // Allow 3 break sounds before you start merging anything.
  123. if ( list.Count() > 2 && surfaceProps == sound.surfacePropsBreak )
  124. {
  125. sound.origin = (sound.origin + origin) * 0.5f;
  126. return;
  127. }
  128. }
  129. breaksound_t sound;
  130. sound.origin = origin;
  131. sound.surfacePropsBreak = surfaceProps;
  132. list.AddToTail(sound);
  133. }
  134. void PlayBreakSounds( CUtlVector<breaksound_t> &list )
  135. {
  136. for ( int i = list.Count()-1; i >= 0; --i )
  137. {
  138. breaksound_t &sound = list.Element(i);
  139. const surfacedata_t *psurf = physprops->GetSurfaceData( sound.surfacePropsBreak );
  140. const char *pSound = physprops->GetString( psurf->sounds.breakSound );
  141. CSoundParameters params;
  142. if ( !CBaseEntity::GetParametersForSound( pSound, params, NULL ) )
  143. return;
  144. // Play from the world, because the entity is breaking, so it'll be destroyed soon
  145. CPASAttenuationFilter filter( sound.origin, params.soundlevel );
  146. EmitSound_t ep;
  147. ep.m_nChannel = CHAN_STATIC;
  148. ep.m_pSoundName = params.soundname;
  149. ep.m_flVolume = params.volume;
  150. ep.m_SoundLevel = params.soundlevel;
  151. ep.m_nPitch = params.pitch;
  152. ep.m_pOrigin = &sound.origin;
  153. CBaseEntity::EmitSound( filter, 0 /*sound.entityIndex*/, ep );
  154. }
  155. list.RemoveAll();
  156. }
  157. };
  158. #endif // VPHYSICS_SOUND_H