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.

291 lines
9.2 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Data types used inside constraints for the purpose of playing sounds
  4. // during movement.
  5. //
  6. //=============================================================================//
  7. #ifndef PHYSCONSTRAINT_SOUNDS_H
  8. #define PHYSCONSTRAINT_SOUNDS_H
  9. #ifdef _WIN32
  10. #pragma once
  11. #endif
  12. #include <mathlib/ssemath.h>
  13. #include "soundenvelope.h"
  14. /** \brief Class to store a sampled history of velocity for an object -- used for certain sound calculations
  15. Although this contains only one sample for now, it exists as an interface
  16. so as to make simpler the possibility of moving to a ring buffer
  17. implementation in the future.
  18. The "sample rate" variable is not nominal: it should be used to specify
  19. the ClientThink() interval.
  20. Be sure to use the beginSampling() function for the first sample, and
  21. addSample() thereafter: this will be relevant and necessary for a ring
  22. buffer implementation (which will have to perform certain initialization).
  23. */
  24. class VelocitySampler
  25. {
  26. public:
  27. /*
  28. enum
  29. {
  30. HISTORY_DEPTH_LOG = 3, // < log-base-2 of the sampler's array depth
  31. HISTORY_DEPTH = (1 << VELOCITY_SAMPLER_HISTORY_DEPTH_LOG),
  32. };
  33. */
  34. /// Return the internally stored sample rate.
  35. inline float getSampleRate()
  36. {
  37. return m_fIdealSampleRate;
  38. }
  39. /// Store off the first recorded sample for the given object.
  40. inline void BeginSampling(const Vector &relativeVelocity);
  41. /// Record a sample. Do this LAST, after calling hasReversed() et al.
  42. inline void AddSample(const Vector &relativeVelocity);
  43. /// Using the sample history, determine if the object has reversed direction
  44. /// with at least the given acceleration (in units/sec^2).
  45. int HasReversed(const Vector &relativeVelocity, const float thresholdAcceleration[], const unsigned short numThresholds);
  46. /// Call this in spawn(). (Not a constructor because those are difficult to use in entities.)
  47. void Initialize(float samplerate);
  48. /// A convenience function for extracting the linear velocity of one object relative to another.
  49. inline static Vector GetRelativeVelocity(IPhysicsObject *pObj, IPhysicsObject *pReferenceFrame);
  50. /// A convenience function for extracting the angular velocity of one object relative to another.
  51. inline static Vector GetRelativeAngularVelocity(IPhysicsObject *pObj, IPhysicsObject *pReferenceFrame);
  52. protected:
  53. Vector m_prevSample;
  54. float m_fPrevSampleTime;
  55. float m_fIdealSampleRate;
  56. };
  57. struct SimpleConstraintSoundProfile
  58. {
  59. // define the indices of the sound points:
  60. enum
  61. {
  62. kMIN_THRESHOLD, ///< below this no sound is played
  63. kMIN_FULL, ///< at this velocity sound is at its loudest
  64. kHIGHWATER, ///< high water mark for this enum
  65. } eKeypoints;
  66. float m_keyPoints[kHIGHWATER];
  67. /// Number of entries in the reversal sound array
  68. enum { kREVERSAL_SOUND_ARRAY_SIZE = 3 };
  69. /// Acceleration threshold for playing the hard-reverse sound. Divided into sections.
  70. /// Below the 0th threshold no sound will play.
  71. float m_reversalSoundThresholds[kREVERSAL_SOUND_ARRAY_SIZE];
  72. /// Get volume for given velocity [0..1]
  73. float GetVolume(float inVel);
  74. };
  75. float SimpleConstraintSoundProfile::GetVolume(float inVel)
  76. {
  77. // clamped lerp on 0-1
  78. if (inVel <= m_keyPoints[kMIN_THRESHOLD])
  79. {
  80. return 0;
  81. }
  82. else if (inVel >= m_keyPoints[kMIN_FULL])
  83. {
  84. return 1;
  85. }
  86. else // lerp...
  87. {
  88. return (inVel - m_keyPoints[kMIN_THRESHOLD])/(m_keyPoints[kMIN_FULL] - m_keyPoints[kMIN_THRESHOLD]);
  89. }
  90. }
  91. class CPhysConstraint;
  92. /** This class encapsulates the data and behavior necessary for a constraint to play sounds.
  93. For the moment I have no easy means of populating this from an entity's datadesc.
  94. You should explicitly fill out the fields with eg
  95. DEFINE_KEYFIELD( m_soundInfo.m_soundProfile.m_keyPoints[SimpleConstraintSoundProfile::kMIN_THRESHOLD] , FIELD_FLOAT, "minSoundThreshold" ),
  96. DEFINE_KEYFIELD( m_soundInfo.m_soundProfile.m_keyPoints[SimpleConstraintSoundProfile::kMIN_FULL] , FIELD_FLOAT, "maxSoundThreshold" ),
  97. DEFINE_KEYFIELD( m_soundInfo.m_iszTravelSoundFwd, FIELD_SOUNDNAME, "slidesoundfwd" ),
  98. DEFINE_KEYFIELD( m_soundInfo.m_iszTravelSoundBack, FIELD_SOUNDNAME, "slidesoundback" ),
  99. DEFINE_KEYFIELD( m_soundInfo.m_iszReversalSound, FIELD_SOUNDNAME, "reversalsound" ),
  100. DEFINE_KEYFIELD( m_soundInfo.m_soundProfile.m_reversalSoundThreshold , FIELD_FLOAT, "reversalsoundthreshold" ),
  101. */
  102. class ConstraintSoundInfo
  103. {
  104. public:
  105. // no ctor.
  106. // dtor
  107. ~ConstraintSoundInfo();
  108. /// Call from the constraint's Activate()
  109. void OnActivate( CPhysConstraint *pOuter );
  110. /// Constraint should have a think function that calls this. It should pass in relative velocity
  111. /// between child and parent. (This need not be linear velocity; it may be angular.)
  112. void OnThink( CPhysConstraint *pOuter, const Vector &relativeVelocity );
  113. /// This is how often the think function should be run:
  114. inline float getThinkRate() const { return 0.09f; }
  115. /// Call this before the first call to OnThink()
  116. void StartThinking( CPhysConstraint *pOuter, const Vector &relativeVelocity, const Vector &forwardVector );
  117. /// Call this if you intend to stop calling OnThink():
  118. void StopThinking( CPhysConstraint *pOuter );
  119. /// Call from owner's Precache().
  120. void OnPrecache( CPhysConstraint *pOuter );
  121. VelocitySampler m_vSampler;
  122. SimpleConstraintSoundProfile m_soundProfile;
  123. Vector m_forwardAxis; ///< velocity in this direction is forward. The opposite direction is backward.
  124. string_t m_iszTravelSoundFwd,m_iszTravelSoundBack; // Path/filename of WAV file to play.
  125. CSoundPatch *m_pTravelSound;
  126. bool m_bPlayTravelSound;
  127. string_t m_iszReversalSounds[SimpleConstraintSoundProfile::kREVERSAL_SOUND_ARRAY_SIZE]; // Path/filename of WAV files to play -- one per entry in threshold.
  128. // CSoundPatch *m_pReversalSound;
  129. bool m_bPlayReversalSound;
  130. protected:
  131. /// Maintain consistency of internal datastructures on start
  132. void ValidateInternals( CPhysConstraint *pOuter );
  133. /// Stop playing any active sounds.
  134. void DeleteAllSounds();
  135. };
  136. /////////////// INLINE FUNCTIONS
  137. /// compute the relative velocity between an object and its parent. Just a convenience.
  138. Vector VelocitySampler::GetRelativeVelocity( IPhysicsObject *pObj, IPhysicsObject *pReferenceFrame )
  139. {
  140. Vector childVelocity, parentVelocity;
  141. pObj->GetImplicitVelocity( &childVelocity, NULL );
  142. pReferenceFrame->GetImplicitVelocity(&parentVelocity, NULL);
  143. return (childVelocity - parentVelocity);
  144. }
  145. Vector VelocitySampler::GetRelativeAngularVelocity( IPhysicsObject *pObj, IPhysicsObject *pReferenceFrame )
  146. {
  147. Assert(pObj);
  148. if ( pReferenceFrame )
  149. {
  150. Vector childVelocityLocal, parentVelocityLocal, childVelocityWorld, parentVelocityWorld;
  151. pObj->GetImplicitVelocity( NULL, &childVelocityLocal );
  152. pObj->LocalToWorldVector( &childVelocityWorld, childVelocityLocal );
  153. pReferenceFrame->GetImplicitVelocity( NULL, &parentVelocityLocal );
  154. pObj->LocalToWorldVector( &parentVelocityWorld, parentVelocityLocal );
  155. return (childVelocityWorld - parentVelocityWorld);
  156. }
  157. else
  158. {
  159. Vector childVelocityLocal, childVelocityWorld;
  160. pObj->GetImplicitVelocity( NULL, &childVelocityLocal );
  161. pObj->LocalToWorldVector( &childVelocityWorld, childVelocityLocal );
  162. return (childVelocityWorld);
  163. }
  164. }
  165. /************************************************************************/
  166. // This function is nominal -- it's here as an interface because in the
  167. // future there will need to be special initialization for the first entry
  168. // in a ring buffer. (I made a test implementation of this, then reverted it
  169. // later; this is not an arbitrary assumption.)
  170. /************************************************************************/
  171. /// Store off the first recorded sample for the given object.
  172. void VelocitySampler::BeginSampling(const Vector &relativeVelocity)
  173. {
  174. return AddSample(relativeVelocity);
  175. }
  176. // Record a sample for the given object
  177. void VelocitySampler::AddSample(const Vector &relativeVelocity)
  178. {
  179. m_prevSample = relativeVelocity;
  180. m_fPrevSampleTime = gpGlobals->curtime;
  181. }
  182. /* // abandoned -- too complicated, no way to set from keyfields
  183. #pragma warning(push)
  184. #pragma warning( disable:4201 ) // C4201: nonstandard extension used: nameless struct/union
  185. /// Stores information used for playing sounds based on
  186. /// constraint movement
  187. class ConstraintSoundProfile
  188. {
  189. public:
  190. /// Defines a point in the sound profile: volume and pitch for the sound to play.
  191. /// Implicit crossfading between two sounds. Used to map velocity to a sound profile.
  192. struct SoundInfoTuple
  193. {
  194. float minVelocity;
  195. union {
  196. struct{
  197. float volume1,pitch1; //< volume and pitch of sound 1
  198. float volume2,pitch2; //< volume and pitch of sound 2
  199. };
  200. fltx4 m_as4;
  201. };
  202. inline SoundInfoTuple(float _minVelocity, float _volume1, float _pitch1, float _volume2, float _pitch2) :
  203. minVelocity(_minVelocity), volume1(_volume1), pitch1(_pitch1), volume2(_volume2), pitch2(_pitch2)
  204. {}
  205. };
  206. ConstraintSoundProfile(const SoundInfoTuple *soundTable, unsigned int tableSize)
  207. : m_pSoundInfos(soundTable), m_numSoundInfos(tableSize)
  208. {}
  209. protected:
  210. /// A table of sound info structs
  211. const SoundInfoTuple * const m_pSoundInfos;
  212. /// Size of the table
  213. const unsigned int m_numSoundInfos;
  214. };
  215. static ConstraintSoundProfile::SoundInfoTuple CSDebugProfileTable[] =
  216. {
  217. ConstraintSoundProfile::SoundInfoTuple(12,0,0,0,0),
  218. ConstraintSoundProfile::SoundInfoTuple(24,0,0,0,0),
  219. };
  220. #pragma warning(pop)
  221. */
  222. #endif