Skip to content

Commit

Permalink
Refactor|BspLeaf|Client: Moved BSP leaf audio environment calculation…
Browse files Browse the repository at this point in the history
…s into BspLeaf

Each BSP leaf may contribute to the audio characteristics of several
sectors. Currently the audio environment properties of a BSP leaf are
repeatedly calculated each time an affected sector is updated.

Moving this logic into BspLeaf will potentially allow for efficiently
updating these values only when necessary.
  • Loading branch information
danij-deng committed Aug 16, 2013
1 parent 8fe6525 commit 1bc26ff
Show file tree
Hide file tree
Showing 10 changed files with 184 additions and 209 deletions.
53 changes: 32 additions & 21 deletions doomsday/client/include/audio/s_environ.h
@@ -1,4 +1,4 @@
/** @file s_environ.h Sound environment.
/** @file s_environ.h Audio environment management.
* @ingroup audio
*
* @authors Copyright © 2003-2013 Jaakko Keränen <jaakko.keranen@iki.fi>
Expand All @@ -24,24 +24,29 @@

#include "api_uri.h"

namespace de {
class Map;
}

class Sector;

typedef enum audioenvironmentclass_e {
AEC_UNKNOWN = -1,
AEC_FIRST = 0,
AEC_METAL = AEC_FIRST,
AEC_ROCK,
AEC_WOOD,
AEC_CLOTH,
NUM_AUDIO_ENVIRONMENT_CLASSES
} AudioEnvironmentClass;
enum AudioEnvironmentId
{
AE_NONE = -1,
AE_FIRST = 0,
AE_METAL = AE_FIRST,
AE_ROCK,
AE_WOOD,
AE_CLOTH,
NUM_AUDIO_ENVIRONMENTS
};

#define VALID_AUDIO_ENVIRONMENT_CLASS(val) (\
(int)(val) >= AEC_FIRST && (int)(val) < NUM_AUDIO_ENVIRONMENT_CLASSES)
/**
* Defines the properties of an audio environment.
*/
struct AudioEnvironment
{
char const name[9]; ///< Environment type name.
int volumeMul;
int decayMul;
int dampingMul;
};

/**
* Requests re-calculation of the reverb properties of the given sector. Should
Expand All @@ -68,16 +73,22 @@ void S_UpdateReverbForSector(Sector *sec);
/**
* Must be called when the map changes.
*/
void S_ResetReverb(void);
void S_ResetReverb();

/**
* Lookup the symbolic name of the identified audio environment.
*/
char const *S_AudioEnvironmentName(AudioEnvironmentId id);

/**
* @return Environment class name for identifier @a mclass.
* Lookup the identified audio environment.
*/
char const *S_AudioEnvironmentName(AudioEnvironmentClass environment);
AudioEnvironment const &S_AudioEnvironment(AudioEnvironmentId id);

/**
* @return Environment class associated with material @a uri else @c AEC_UNKNOWN.
* Lookup the audio environment associated with material @a uri. If no environment
* is defined then @c AE_NONE is returned.
*/
AudioEnvironmentClass S_AudioEnvironmentForMaterial(Uri const *uri);
AudioEnvironmentId S_AudioEnvironmentId(Uri const *uri);

#endif // DENG_SOUND_ENVIRON
24 changes: 11 additions & 13 deletions doomsday/client/include/resource/material.h
Expand Up @@ -788,19 +788,6 @@ class Material : public de::MapElement,
*/
void setFlags(Flags flagsToChange, de::FlagOp operation = de::SetFlags);

/**
* Returns the environment audio class for the material.
*/
audioenvironmentclass_e audioEnvironment() const;

/**
* Change the material's environment audio class.
* @param newEnvironment New environment to apply.
*
* @todo If attached to a map Surface update accordingly!
*/
void setAudioEnvironment(audioenvironmentclass_e newEnvironment);

/**
* Add a new layer to the end of the material's layer stack. Ownership of the
* layer is @em not transferred to the caller.
Expand Down Expand Up @@ -876,6 +863,17 @@ class Material : public de::MapElement,
ShineLayer const &shineLayer() const;

#ifdef __CLIENT__
/**
* Returns the identifier of the audio environment for the material.
*/
AudioEnvironmentId audioEnvironment() const;

/**
* Change the audio environment for the material.
*
* @param newEnvironment New audio environment to apply.
*/
void setAudioEnvironment(AudioEnvironmentId newEnvironment);

/**
* Returns the number of material (light) decorations.
Expand Down
5 changes: 5 additions & 0 deletions doomsday/client/include/world/bspleaf.h
Expand Up @@ -287,6 +287,11 @@ class BspLeaf : public de::MapElement
*/
void applyBiasDigest(BiasDigest &changes);

/**
* Recalculate the environmental audio characteristics for the BSP leaf.
*/
bool updateReverb();

/**
* Clear the list of fake radio shadow line sides for the BSP leaf.
*/
Expand Down
3 changes: 0 additions & 3 deletions doomsday/client/include/world/sector.h
Expand Up @@ -108,9 +108,6 @@ class Sector : public de::MapElement
struct mobj_s *_mobjList;

#ifdef __CLIENT__
/// @ref sectorFrameFlags
int _frameFlags;

/// Final environmental audio characteristics.
AudioEnvironmentFactors _reverb;
#endif
Expand Down
153 changes: 21 additions & 132 deletions doomsday/client/src/audio/s_environ.cpp
Expand Up @@ -21,34 +21,22 @@
* 02110-1301 USA</small>
*/

#include <cctype>
#include <cstring>
#include <set>

#include <de/Log>

#include "de_base.h"
#include "de_audio.h"
#include "de_play.h"
#include "de_resource.h"
#include "de_system.h"

#include "Face"

#include "BspLeaf"
#include "Sector"

#include "audio/s_environ.h"

using namespace de;

typedef struct {
char const name[9]; ///< Environment type name.
int volumeMul;
int decayMul;
int dampingMul;
} audioenvinfo_t;

static audioenvinfo_t envInfo[NUM_AUDIO_ENVIRONMENT_CLASSES] = {
static AudioEnvironment envInfo[1 + NUM_AUDIO_ENVIRONMENTS] = {
{"", 0, 0, 0},
{"Metal", 255, 255, 25},
{"Rock", 200, 160, 100},
{"Wood", 80, 50, 200},
Expand All @@ -58,14 +46,19 @@ static audioenvinfo_t envInfo[NUM_AUDIO_ENVIRONMENT_CLASSES] = {
typedef std::set<Sector *> ReverbUpdateRequested;
ReverbUpdateRequested reverbUpdateRequested;

char const *S_AudioEnvironmentName(AudioEnvironmentClass env)
char const *S_AudioEnvironmentName(AudioEnvironmentId id)
{
DENG_ASSERT(id >= AE_NONE && id < NUM_AUDIO_ENVIRONMENTS);
return envInfo[1 + int(id)].name;
}

AudioEnvironment const &S_AudioEnvironment(AudioEnvironmentId id)
{
if(VALID_AUDIO_ENVIRONMENT_CLASS(env))
return envInfo[env - AEC_FIRST].name;
return "";
DENG_ASSERT(id >= AE_NONE && id < NUM_AUDIO_ENVIRONMENTS);
return envInfo[1 + int(id)];
}

AudioEnvironmentClass S_AudioEnvironmentForMaterial(uri_s const *uri)
AudioEnvironmentId S_AudioEnvironmentId(uri_s const *uri)
{
if(uri)
{
Expand All @@ -77,122 +70,18 @@ AudioEnvironmentClass S_AudioEnvironmentForMaterial(uri_s const *uri)
uri_s *ref = env->materials[k];
if(!ref || !Uri_Equality(ref, uri)) continue;

// See if we recognise the material name.
for(int l = 0; l < NUM_AUDIO_ENVIRONMENT_CLASSES; ++l)
// Is this a known environment?
for(int m = 0; m < NUM_AUDIO_ENVIRONMENTS; ++m)
{
if(!stricmp(env->id, envInfo[l].name))
return AudioEnvironmentClass(AEC_FIRST + l);
AudioEnvironment const &envInfo = S_AudioEnvironment(AudioEnvironmentId(m));
if(!stricmp(env->id, envInfo.name))
return AudioEnvironmentId(m);
}
return AEC_UNKNOWN;
return AE_NONE;
}
}
}
return AEC_UNKNOWN;
}

static void accumReverbForWallSections(HEdge const *hedge,
float envSpaceAccum[NUM_AUDIO_ENVIRONMENT_CLASSES], float &total)
{
// Edges with no map line segment implicitly have no surfaces.
if(!hedge || !hedge->mapElement())
return;

Line::Side::Segment *seg = hedge->mapElement()->as<Line::Side::Segment>();
if(!seg->lineSide().hasSections() || !seg->lineSide().middle().hasMaterial())
return;

Material &material = seg->lineSide().middle().material();
AudioEnvironmentClass env = material.audioEnvironment();
if(!(env >= 0 && env < NUM_AUDIO_ENVIRONMENT_CLASSES))
env = AEC_WOOD; // Assume it's wood if unknown.

total += seg->length();

envSpaceAccum[env] += seg->length();
}

static boolean calcBspLeafReverb(BspLeaf *bspLeaf)
{
DENG2_ASSERT(bspLeaf);

if(!bspLeaf->hasSector() || bspLeaf->isDegenerate() || isDedicated)
{
bspLeaf->_reverb[SRD_SPACE] = bspLeaf->_reverb[SRD_VOLUME] =
bspLeaf->_reverb[SRD_DECAY] = bspLeaf->_reverb[SRD_DAMPING] = 0;
return false;
}

float envSpaceAccum[NUM_AUDIO_ENVIRONMENT_CLASSES];
std::memset(&envSpaceAccum, 0, sizeof(envSpaceAccum));

// Space is the rough volume of the BSP leaf (bounding box).
bspLeaf->_reverb[SRD_SPACE] =
(int) (bspLeaf->sector().ceiling().height() - bspLeaf->sector().floor().height()) *
(bspLeaf->poly().aaBox().maxX - bspLeaf->poly().aaBox().minX) *
(bspLeaf->poly().aaBox().maxY - bspLeaf->poly().aaBox().minY);

float total = 0;

// The other reverb properties can be found out by taking a look at the
// materials of all surfaces in the BSP leaf.
HEdge *base = bspLeaf->poly().hedge();
HEdge *hedge = base;
do
{
accumReverbForWallSections(hedge, envSpaceAccum, total);
} while((hedge = &hedge->next()) != base);

foreach(Mesh *mesh, bspLeaf->extraMeshes())
foreach(HEdge *hedge, mesh->hedges())
{
accumReverbForWallSections(hedge, envSpaceAccum, total);
}

if(!total)
{
// Huh?
bspLeaf->_reverb[SRD_VOLUME] = bspLeaf->_reverb[SRD_DECAY] =
bspLeaf->_reverb[SRD_DAMPING] = 0;
return false;
}

// Average the results.
uint i, v;
for(i = 0; i < NUM_AUDIO_ENVIRONMENT_CLASSES; ++i)
{
envSpaceAccum[i] /= total;
}

// Volume.
for(i = 0, v = 0; i < NUM_AUDIO_ENVIRONMENT_CLASSES; ++i)
{
v += envSpaceAccum[i] * envInfo[i].volumeMul;
}
if(v > 255) v = 255;
bspLeaf->_reverb[SRD_VOLUME] = v;

// Decay time.
for(i = 0, v = 0; i < NUM_AUDIO_ENVIRONMENT_CLASSES; ++i)
{
v += envSpaceAccum[i] * envInfo[i].decayMul;
}
if(v > 255) v = 255;
bspLeaf->_reverb[SRD_DECAY] = v;

// High frequency damping.
for(i = 0, v = 0; i < NUM_AUDIO_ENVIRONMENT_CLASSES; ++i)
{
v += envSpaceAccum[i] * envInfo[i].dampingMul;
}
if(v > 255) v = 255;
bspLeaf->_reverb[SRD_DAMPING] = v;

/* DEBUG_Message(("bspLeaf %04i: vol:%3i sp:%3i dec:%3i dam:%3i\n",
bspLeaf->indexInMap(), bspLeaf->reverb[SRD_VOLUME],
bspLeaf->reverb[SRD_SPACE], bspLeaf->reverb[SRD_DECAY],
bspLeaf->reverb[SRD_DAMPING])); */

return true;
return AE_NONE;
}

static void calculateSectorReverb(Sector *sec)
Expand All @@ -206,7 +95,7 @@ static void calculateSectorReverb(Sector *sec)

foreach(BspLeaf *bspLeaf, sec->reverbBspLeafs())
{
if(calcBspLeafReverb(bspLeaf))
if(bspLeaf->updateReverb())
{
sec->_reverb[SRD_SPACE] += bspLeaf->_reverb[SRD_SPACE];

Expand Down
4 changes: 3 additions & 1 deletion doomsday/client/src/def_main.cpp
Expand Up @@ -1390,7 +1390,9 @@ static void interpretMaterialDef(ded_material_t const &def)

material.setFlags(translateMaterialDefFlags(def.flags));
material.setDimensions(Vector2i(def.width, def.height));
material.setAudioEnvironment(S_AudioEnvironmentForMaterial(def.uri));
#ifdef __CLIENT__
material.setAudioEnvironment(S_AudioEnvironmentId(def.uri));
#endif

rebuildMaterialLayers(material, def);
#ifdef __CLIENT__
Expand Down

0 comments on commit 1bc26ff

Please sign in to comment.