source-engine/game/shared/vphysics_sound.h

178 lines
5.3 KiB
C
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef VPHYSICS_SOUND_H
#define VPHYSICS_SOUND_H
#ifdef _WIN32
#pragma once
#endif
#include "SoundEmitterSystem/isoundemittersystembase.h"
namespace physicssound
{
struct impactsound_t
{
void *pGameData;
int entityIndex;
int soundChannel;
float volume;
float impactSpeed;
unsigned short surfaceProps;
unsigned short surfacePropsHit;
Vector origin;
};
// UNDONE: Use a sorted container and sort by volume/distance?
struct soundlist_t
{
CUtlVector<impactsound_t> elements;
impactsound_t &GetElement(int index) { return elements[index]; }
impactsound_t &AddElement() { return elements[elements.AddToTail()]; }
int Count() { return elements.Count(); }
void RemoveAll() { elements.RemoveAll(); }
};
void PlayImpactSounds( soundlist_t &list )
{
for ( int i = list.Count()-1; i >= 0; --i )
{
impactsound_t &sound = list.GetElement(i);
const surfacedata_t *psurf = physprops->GetSurfaceData( sound.surfaceProps );
if ( psurf->sounds.impactHard )
{
const surfacedata_t *pHit = physprops->GetSurfaceData( sound.surfacePropsHit );
unsigned short soundName = psurf->sounds.impactHard;
if ( pHit && psurf->sounds.impactSoft )
{
if ( pHit->audio.hardnessFactor < psurf->audio.hardThreshold ||
(psurf->audio.hardVelocityThreshold > 0 && psurf->audio.hardVelocityThreshold > sound.impactSpeed) )
{
soundName = psurf->sounds.impactSoft;
}
}
const char *pSound = physprops->GetString( soundName );
CSoundParameters params;
if ( !CBaseEntity::GetParametersForSound( pSound, params, NULL ) )
break;
if ( sound.volume > 1 )
sound.volume = 1;
CPASAttenuationFilter filter( sound.origin, params.soundlevel );
// JAY: If this entity gets deleted, the sound comes out at the world origin
// this sounds bad! Play on ent 0 for now.
EmitSound_t ep;
ep.m_nChannel = sound.soundChannel;
ep.m_pSoundName = params.soundname;
ep.m_flVolume = params.volume * sound.volume;
ep.m_SoundLevel = params.soundlevel;
ep.m_nPitch = params.pitch;
ep.m_pOrigin = &sound.origin;
CBaseEntity::EmitSound( filter, 0 /*sound.entityIndex*/, ep );
}
}
list.RemoveAll();
}
void AddImpactSound( soundlist_t &list, void *pGameData, int entityIndex, int soundChannel, IPhysicsObject *pObject, int surfaceProps, int surfacePropsHit, float volume, float impactSpeed )
{
impactSpeed += 1e-4;
for ( int i = list.Count()-1; i >= 0; --i )
{
impactsound_t &sound = list.GetElement(i);
// UNDONE: Compare entity or channel somehow?
// UNDONE: Doing one slot per entity is too noisy. So now we use one slot per material
// heuristic - after 4 impacts sounds in one frame, start merging everything
if ( surfaceProps == sound.surfaceProps || list.Count() > 4 )
{
// UNDONE: Store instance volume separate from aggregate volume and compare that?
if ( volume > sound.volume )
{
pObject->GetPosition( &sound.origin, NULL );
sound.pGameData = pGameData;
sound.entityIndex = entityIndex;
sound.soundChannel = soundChannel;
sound.surfacePropsHit = surfacePropsHit;
}
sound.volume += volume;
sound.impactSpeed = MAX(impactSpeed,sound.impactSpeed);
return;
}
}
impactsound_t &sound = list.AddElement();
sound.pGameData = pGameData;
sound.entityIndex = entityIndex;
sound.soundChannel = soundChannel;
pObject->GetPosition( &sound.origin, NULL );
sound.surfaceProps = surfaceProps;
sound.surfacePropsHit = surfacePropsHit;
sound.volume = volume;
sound.impactSpeed = impactSpeed;
}
struct breaksound_t
{
Vector origin;
int surfacePropsBreak;
};
void AddBreakSound( CUtlVector<breaksound_t> &list, const Vector &origin, unsigned short surfaceProps )
{
const surfacedata_t *psurf = physprops->GetSurfaceData( surfaceProps );
if ( !psurf->sounds.breakSound )
return;
for ( int i = list.Count()-1; i >= 0; --i )
{
breaksound_t &sound = list.Element(i);
// Allow 3 break sounds before you start merging anything.
if ( list.Count() > 2 && surfaceProps == sound.surfacePropsBreak )
{
sound.origin = (sound.origin + origin) * 0.5f;
return;
}
}
breaksound_t sound;
sound.origin = origin;
sound.surfacePropsBreak = surfaceProps;
list.AddToTail(sound);
}
void PlayBreakSounds( CUtlVector<breaksound_t> &list )
{
for ( int i = list.Count()-1; i >= 0; --i )
{
breaksound_t &sound = list.Element(i);
const surfacedata_t *psurf = physprops->GetSurfaceData( sound.surfacePropsBreak );
const char *pSound = physprops->GetString( psurf->sounds.breakSound );
CSoundParameters params;
if ( !CBaseEntity::GetParametersForSound( pSound, params, NULL ) )
return;
// Play from the world, because the entity is breaking, so it'll be destroyed soon
CPASAttenuationFilter filter( sound.origin, params.soundlevel );
EmitSound_t ep;
ep.m_nChannel = CHAN_STATIC;
ep.m_pSoundName = params.soundname;
ep.m_flVolume = params.volume;
ep.m_SoundLevel = params.soundlevel;
ep.m_nPitch = params.pitch;
ep.m_pOrigin = &sound.origin;
CBaseEntity::EmitSound( filter, 0 /*sound.entityIndex*/, ep );
}
list.RemoveAll();
}
};
#endif // VPHYSICS_SOUND_H