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
291 lines
9.2 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Data types used inside constraints for the purpose of playing sounds |
|
// during movement. |
|
// |
|
//=============================================================================// |
|
|
|
#ifndef PHYSCONSTRAINT_SOUNDS_H |
|
#define PHYSCONSTRAINT_SOUNDS_H |
|
#ifdef _WIN32 |
|
#pragma once |
|
#endif |
|
|
|
|
|
#include <mathlib/ssemath.h> |
|
#include "soundenvelope.h" |
|
|
|
|
|
/** \brief Class to store a sampled history of velocity for an object -- used for certain sound calculations |
|
|
|
Although this contains only one sample for now, it exists as an interface |
|
so as to make simpler the possibility of moving to a ring buffer |
|
implementation in the future. |
|
|
|
The "sample rate" variable is not nominal: it should be used to specify |
|
the ClientThink() interval. |
|
|
|
Be sure to use the beginSampling() function for the first sample, and |
|
addSample() thereafter: this will be relevant and necessary for a ring |
|
buffer implementation (which will have to perform certain initialization). |
|
*/ |
|
class VelocitySampler |
|
{ |
|
public: |
|
/* |
|
enum |
|
{ |
|
HISTORY_DEPTH_LOG = 3, // < log-base-2 of the sampler's array depth |
|
HISTORY_DEPTH = (1 << VELOCITY_SAMPLER_HISTORY_DEPTH_LOG), |
|
}; |
|
*/ |
|
|
|
/// Return the internally stored sample rate. |
|
inline float getSampleRate() |
|
{ |
|
return m_fIdealSampleRate; |
|
} |
|
|
|
|
|
/// Store off the first recorded sample for the given object. |
|
inline void BeginSampling(const Vector &relativeVelocity); |
|
|
|
/// Record a sample. Do this LAST, after calling hasReversed() et al. |
|
inline void AddSample(const Vector &relativeVelocity); |
|
|
|
/// Using the sample history, determine if the object has reversed direction |
|
/// with at least the given acceleration (in units/sec^2). |
|
int HasReversed(const Vector &relativeVelocity, const float thresholdAcceleration[], const unsigned short numThresholds); |
|
|
|
/// Call this in spawn(). (Not a constructor because those are difficult to use in entities.) |
|
void Initialize(float samplerate); |
|
|
|
|
|
/// A convenience function for extracting the linear velocity of one object relative to another. |
|
inline static Vector GetRelativeVelocity(IPhysicsObject *pObj, IPhysicsObject *pReferenceFrame); |
|
|
|
/// A convenience function for extracting the angular velocity of one object relative to another. |
|
inline static Vector GetRelativeAngularVelocity(IPhysicsObject *pObj, IPhysicsObject *pReferenceFrame); |
|
|
|
|
|
protected: |
|
Vector m_prevSample; |
|
float m_fPrevSampleTime; |
|
|
|
float m_fIdealSampleRate; |
|
|
|
}; |
|
|
|
struct SimpleConstraintSoundProfile |
|
{ |
|
// define the indices of the sound points: |
|
enum |
|
{ |
|
kMIN_THRESHOLD, ///< below this no sound is played |
|
kMIN_FULL, ///< at this velocity sound is at its loudest |
|
|
|
kHIGHWATER, ///< high water mark for this enum |
|
} eKeypoints; |
|
|
|
float m_keyPoints[kHIGHWATER]; |
|
|
|
/// Number of entries in the reversal sound array |
|
enum { kREVERSAL_SOUND_ARRAY_SIZE = 3 }; |
|
|
|
/// Acceleration threshold for playing the hard-reverse sound. Divided into sections. |
|
/// Below the 0th threshold no sound will play. |
|
float m_reversalSoundThresholds[kREVERSAL_SOUND_ARRAY_SIZE]; |
|
|
|
/// Get volume for given velocity [0..1] |
|
float GetVolume(float inVel); |
|
}; |
|
|
|
float SimpleConstraintSoundProfile::GetVolume(float inVel) |
|
{ |
|
// clamped lerp on 0-1 |
|
if (inVel <= m_keyPoints[kMIN_THRESHOLD]) |
|
{ |
|
return 0; |
|
} |
|
else if (inVel >= m_keyPoints[kMIN_FULL]) |
|
{ |
|
return 1; |
|
} |
|
else // lerp... |
|
{ |
|
return (inVel - m_keyPoints[kMIN_THRESHOLD])/(m_keyPoints[kMIN_FULL] - m_keyPoints[kMIN_THRESHOLD]); |
|
} |
|
} |
|
|
|
class CPhysConstraint; |
|
/** This class encapsulates the data and behavior necessary for a constraint to play sounds. |
|
|
|
For the moment I have no easy means of populating this from an entity's datadesc. |
|
You should explicitly fill out the fields with eg |
|
|
|
DEFINE_KEYFIELD( m_soundInfo.m_soundProfile.m_keyPoints[SimpleConstraintSoundProfile::kMIN_THRESHOLD] , FIELD_FLOAT, "minSoundThreshold" ), |
|
DEFINE_KEYFIELD( m_soundInfo.m_soundProfile.m_keyPoints[SimpleConstraintSoundProfile::kMIN_FULL] , FIELD_FLOAT, "maxSoundThreshold" ), |
|
DEFINE_KEYFIELD( m_soundInfo.m_iszTravelSoundFwd, FIELD_SOUNDNAME, "slidesoundfwd" ), |
|
DEFINE_KEYFIELD( m_soundInfo.m_iszTravelSoundBack, FIELD_SOUNDNAME, "slidesoundback" ), |
|
DEFINE_KEYFIELD( m_soundInfo.m_iszReversalSound, FIELD_SOUNDNAME, "reversalsound" ), |
|
DEFINE_KEYFIELD( m_soundInfo.m_soundProfile.m_reversalSoundThreshold , FIELD_FLOAT, "reversalsoundthreshold" ), |
|
|
|
*/ |
|
class ConstraintSoundInfo |
|
{ |
|
public: |
|
// no ctor. |
|
// dtor |
|
~ConstraintSoundInfo(); |
|
|
|
/// Call from the constraint's Activate() |
|
void OnActivate( CPhysConstraint *pOuter ); |
|
|
|
/// Constraint should have a think function that calls this. It should pass in relative velocity |
|
/// between child and parent. (This need not be linear velocity; it may be angular.) |
|
void OnThink( CPhysConstraint *pOuter, const Vector &relativeVelocity ); |
|
|
|
/// This is how often the think function should be run: |
|
inline float getThinkRate() const { return 0.09f; } |
|
|
|
/// Call this before the first call to OnThink() |
|
void StartThinking( CPhysConstraint *pOuter, const Vector &relativeVelocity, const Vector &forwardVector ); |
|
|
|
/// Call this if you intend to stop calling OnThink(): |
|
void StopThinking( CPhysConstraint *pOuter ); |
|
|
|
/// Call from owner's Precache(). |
|
void OnPrecache( CPhysConstraint *pOuter ); |
|
|
|
|
|
VelocitySampler m_vSampler; |
|
SimpleConstraintSoundProfile m_soundProfile; |
|
|
|
Vector m_forwardAxis; ///< velocity in this direction is forward. The opposite direction is backward. |
|
|
|
string_t m_iszTravelSoundFwd,m_iszTravelSoundBack; // Path/filename of WAV file to play. |
|
CSoundPatch *m_pTravelSound; |
|
bool m_bPlayTravelSound; |
|
|
|
string_t m_iszReversalSounds[SimpleConstraintSoundProfile::kREVERSAL_SOUND_ARRAY_SIZE]; // Path/filename of WAV files to play -- one per entry in threshold. |
|
// CSoundPatch *m_pReversalSound; |
|
bool m_bPlayReversalSound; |
|
|
|
protected: |
|
/// Maintain consistency of internal datastructures on start |
|
void ValidateInternals( CPhysConstraint *pOuter ); |
|
|
|
/// Stop playing any active sounds. |
|
void DeleteAllSounds(); |
|
}; |
|
|
|
|
|
/////////////// INLINE FUNCTIONS |
|
|
|
|
|
/// compute the relative velocity between an object and its parent. Just a convenience. |
|
Vector VelocitySampler::GetRelativeVelocity( IPhysicsObject *pObj, IPhysicsObject *pReferenceFrame ) |
|
{ |
|
Vector childVelocity, parentVelocity; |
|
pObj->GetImplicitVelocity( &childVelocity, NULL ); |
|
pReferenceFrame->GetImplicitVelocity(&parentVelocity, NULL); |
|
|
|
return (childVelocity - parentVelocity); |
|
} |
|
|
|
|
|
Vector VelocitySampler::GetRelativeAngularVelocity( IPhysicsObject *pObj, IPhysicsObject *pReferenceFrame ) |
|
{ |
|
Assert(pObj); |
|
|
|
if ( pReferenceFrame ) |
|
{ |
|
Vector childVelocityLocal, parentVelocityLocal, childVelocityWorld, parentVelocityWorld; |
|
pObj->GetImplicitVelocity( NULL, &childVelocityLocal ); |
|
pObj->LocalToWorldVector( &childVelocityWorld, childVelocityLocal ); |
|
pReferenceFrame->GetImplicitVelocity( NULL, &parentVelocityLocal ); |
|
pObj->LocalToWorldVector( &parentVelocityWorld, parentVelocityLocal ); |
|
|
|
return (childVelocityWorld - parentVelocityWorld); |
|
} |
|
else |
|
{ |
|
Vector childVelocityLocal, childVelocityWorld; |
|
pObj->GetImplicitVelocity( NULL, &childVelocityLocal ); |
|
pObj->LocalToWorldVector( &childVelocityWorld, childVelocityLocal ); |
|
|
|
return (childVelocityWorld); |
|
} |
|
} |
|
|
|
/************************************************************************/ |
|
// This function is nominal -- it's here as an interface because in the |
|
// future there will need to be special initialization for the first entry |
|
// in a ring buffer. (I made a test implementation of this, then reverted it |
|
// later; this is not an arbitrary assumption.) |
|
/************************************************************************/ |
|
/// Store off the first recorded sample for the given object. |
|
void VelocitySampler::BeginSampling(const Vector &relativeVelocity) |
|
{ |
|
return AddSample(relativeVelocity); |
|
} |
|
|
|
// Record a sample for the given object |
|
void VelocitySampler::AddSample(const Vector &relativeVelocity) |
|
{ |
|
m_prevSample = relativeVelocity; |
|
m_fPrevSampleTime = gpGlobals->curtime; |
|
} |
|
|
|
|
|
|
|
/* // abandoned -- too complicated, no way to set from keyfields |
|
#pragma warning(push) |
|
#pragma warning( disable:4201 ) // C4201: nonstandard extension used: nameless struct/union |
|
/// Stores information used for playing sounds based on |
|
/// constraint movement |
|
class ConstraintSoundProfile |
|
{ |
|
public: |
|
/// Defines a point in the sound profile: volume and pitch for the sound to play. |
|
/// Implicit crossfading between two sounds. Used to map velocity to a sound profile. |
|
struct SoundInfoTuple |
|
{ |
|
float minVelocity; |
|
union { |
|
struct{ |
|
float volume1,pitch1; //< volume and pitch of sound 1 |
|
float volume2,pitch2; //< volume and pitch of sound 2 |
|
}; |
|
fltx4 m_as4; |
|
}; |
|
|
|
inline SoundInfoTuple(float _minVelocity, float _volume1, float _pitch1, float _volume2, float _pitch2) : |
|
minVelocity(_minVelocity), volume1(_volume1), pitch1(_pitch1), volume2(_volume2), pitch2(_pitch2) |
|
{} |
|
}; |
|
|
|
ConstraintSoundProfile(const SoundInfoTuple *soundTable, unsigned int tableSize) |
|
: m_pSoundInfos(soundTable), m_numSoundInfos(tableSize) |
|
{} |
|
|
|
|
|
protected: |
|
|
|
/// A table of sound info structs |
|
const SoundInfoTuple * const m_pSoundInfos; |
|
/// Size of the table |
|
const unsigned int m_numSoundInfos; |
|
}; |
|
|
|
static ConstraintSoundProfile::SoundInfoTuple CSDebugProfileTable[] = |
|
{ |
|
ConstraintSoundProfile::SoundInfoTuple(12,0,0,0,0), |
|
ConstraintSoundProfile::SoundInfoTuple(24,0,0,0,0), |
|
|
|
}; |
|
#pragma warning(pop) |
|
*/ |
|
|
|
|
|
#endif
|
|
|