From ec2590a25da79abf4b8e9f503d210d853dfdd68d Mon Sep 17 00:00:00 2001 From: danij Date: Fri, 16 Aug 2013 22:53:05 +0100 Subject: [PATCH] Sector|World|Client: Sector now manages environmental audio updates internally --- doomsday/client/include/audio/s_environ.h | 27 ---- doomsday/client/include/world/sector.h | 16 +- doomsday/client/include/world/surface.h | 18 +-- doomsday/client/src/audio/s_environ.cpp | 30 ---- doomsday/client/src/audio/s_main.cpp | 6 - doomsday/client/src/audio/s_sfx.cpp | 4 +- doomsday/client/src/dd_main.cpp | 2 +- doomsday/client/src/world/sector.cpp | 175 ++++++++++++---------- doomsday/client/src/world/world.cpp | 2 +- 9 files changed, 123 insertions(+), 157 deletions(-) diff --git a/doomsday/client/include/audio/s_environ.h b/doomsday/client/include/audio/s_environ.h index 0263c84869..2a4949f032 100644 --- a/doomsday/client/include/audio/s_environ.h +++ b/doomsday/client/include/audio/s_environ.h @@ -24,8 +24,6 @@ #include "api_uri.h" -class Sector; - enum AudioEnvironmentId { AE_NONE = -1, @@ -48,31 +46,6 @@ struct AudioEnvironment int dampingMul; }; -/** - * Requests re-calculation of the reverb properties of the given sector. Should - * be called whenever any of the properties governing reverb properties have - * changed (i.e., wall/plane material or plane height changes). - * - * Call S_UpdateReverbForSector() to do the actual calculation. - * - * @param sec Sector to calculate reverb properties of. - */ -void S_MarkSectorReverbDirty(Sector *sec); - -/** - * Recalculates reverb properties for a sector. One must first mark the sector - * as needing an update using S_MarkSectorReverbDirty() or this function will do - * nothing. - * - * @param sec Sector in which to update reverb properties. - */ -void S_UpdateReverbForSector(Sector *sec); - -/** - * Must be called when the map changes. - */ -void S_ResetReverb(); - /** * Lookup the symbolic name of the identified audio environment. */ diff --git a/doomsday/client/include/world/sector.h b/doomsday/client/include/world/sector.h index b6e3e83ec4..b3513e73cc 100644 --- a/doomsday/client/include/world/sector.h +++ b/doomsday/client/include/world/sector.h @@ -429,20 +429,26 @@ class Sector : public de::MapElement /** * Perform initialization for environmental audio (reverb). Duties include * determining the set of BSP leafs which will contribute to the final audio - * characteristics (reverb) of the sector. To be called when initializing - * the map after load. + * characteristics of the sector. To be called when initializing the map after + * loading. * * The BspLeaf Blockmap for the owning map must be prepared before calling. */ void initReverb(); /** - * Recalculate environmental audio (reverb) for the sector. + * Request re-calculation of the environmental audio (reverb) characteristics + * for the sector (update is deferred until next accessed). + * + * Should be called whenever any of the properties governing reverb properties + * have changed (i.e., wall/plane material changes). */ - void updateReverb(); + void markReverbDirty(bool yes = true); /** - * Returns the final environmental audio characteristics (reverb) of the sector. + * Provides access to the final environmental audio characteristics (reverb) + * of the sector. Note that if a reverb update is scheduled it will be done + * at this time (@ref markReverbDirty()). */ AudioEnvironmentFactors const &reverb() const; diff --git a/doomsday/client/include/world/surface.h b/doomsday/client/include/world/surface.h index 3231a54a97..db7374c716 100644 --- a/doomsday/client/include/world/surface.h +++ b/doomsday/client/include/world/surface.h @@ -50,25 +50,25 @@ class Surface : public de::MapElement DENG2_ERROR(MissingMaterialError); /* - * Observers to be notified when the normal vector changes. - */ - DENG2_DEFINE_AUDIENCE(NormalChange, - void normalChanged(Surface &surface, de::Vector3f oldNormal, - int changedAxes /*bit-field (0x1=X, 0x2=Y, 0x4=Z)*/)) - /* - * Observers to be notified when the @em sharp material origin changes. + * Notified when the @em sharp material origin changes. */ DENG2_DEFINE_AUDIENCE(MaterialOriginChange, void materialOriginChanged(Surface &surface, de::Vector2f oldMaterialOrigin, int changedAxes /*bit-field (0x1=X, 0x2=Y)*/)) /* - * Observers to be notified when the opacity changes. + * Notified when the normal vector changes. + */ + DENG2_DEFINE_AUDIENCE(NormalChange, + void normalChanged(Surface &surface, de::Vector3f oldNormal, + int changedAxes /*bit-field (0x1=X, 0x2=Y, 0x4=Z)*/)) + /* + * Notified when the opacity changes. */ DENG2_DEFINE_AUDIENCE(OpacityChange, void opacityChanged(Surface &surface, float oldOpacity)) /* - * Observers to be notified when the tint color changes. + * Notified when the tint color changes. */ DENG2_DEFINE_AUDIENCE(TintColorChange, void tintColorChanged(Surface §or, de::Vector3f const &oldTintColor, diff --git a/doomsday/client/src/audio/s_environ.cpp b/doomsday/client/src/audio/s_environ.cpp index 4876a0dbc4..b51b7397f9 100644 --- a/doomsday/client/src/audio/s_environ.cpp +++ b/doomsday/client/src/audio/s_environ.cpp @@ -21,14 +21,9 @@ * 02110-1301 USA */ -#include - #include "de_base.h" #include "de_audio.h" -#include "de_play.h" -#include "de_resource.h" -#include "BspLeaf" #include "Sector" #include "audio/s_environ.h" @@ -43,9 +38,6 @@ static AudioEnvironment envInfo[1 + NUM_AUDIO_ENVIRONMENTS] = { {"Cloth", 5, 5, 255} }; -typedef std::set ReverbUpdateRequested; -ReverbUpdateRequested reverbUpdateRequested; - char const *S_AudioEnvironmentName(AudioEnvironmentId id) { DENG_ASSERT(id >= AE_NONE && id < NUM_AUDIO_ENVIRONMENTS); @@ -83,25 +75,3 @@ AudioEnvironmentId S_AudioEnvironmentId(uri_s const *uri) } return AE_NONE; } - -void S_ResetReverb() -{ - reverbUpdateRequested.clear(); -} - -void S_UpdateReverbForSector(Sector *sec) -{ - if(reverbUpdateRequested.empty()) return; - - // If update has been requested for this sector, calculate it now. - if(reverbUpdateRequested.find(sec) != reverbUpdateRequested.end()) - { - sec->updateReverb(); - reverbUpdateRequested.erase(sec); - } -} - -void S_MarkSectorReverbDirty(Sector* sec) -{ - reverbUpdateRequested.insert(sec); -} diff --git a/doomsday/client/src/audio/s_main.cpp b/doomsday/client/src/audio/s_main.cpp index 344ba662ee..d85448f5e7 100644 --- a/doomsday/client/src/audio/s_main.cpp +++ b/doomsday/client/src/audio/s_main.cpp @@ -163,8 +163,6 @@ void S_MapChange(void) #ifdef __CLIENT__ Sfx_MapChange(); - - S_ResetReverb(); #endif } @@ -182,10 +180,6 @@ void S_Reset(void) Sfx_Reset(); #endif _api_S.StopMusic(); - -#ifdef __CLIENT__ - S_ResetReverb(); -#endif } void S_StartFrame(void) diff --git a/doomsday/client/src/audio/s_sfx.cpp b/doomsday/client/src/audio/s_sfx.cpp index 972042166f..41708fba1f 100644 --- a/doomsday/client/src/audio/s_sfx.cpp +++ b/doomsday/client/src/audio/s_sfx.cpp @@ -562,9 +562,7 @@ void Sfx_ListenerUpdate() { listenerSector = listener->bspLeaf->sectorPtr(); - // It may be necessary to recalculate the reverb properties. - S_UpdateReverbForSector(listenerSector); - + // It may be necessary to recalculate the reverb properties... AudioEnvironmentFactors const &envFactors = listenerSector->reverb(); for(int i = 0; i < NUM_REVERB_DATA; ++i) diff --git a/doomsday/client/src/dd_main.cpp b/doomsday/client/src/dd_main.cpp index 53019c1912..6f82cb893f 100644 --- a/doomsday/client/src/dd_main.cpp +++ b/doomsday/client/src/dd_main.cpp @@ -3028,7 +3028,7 @@ DENG_EXTERN_C void R_SetupMap(int mode, int flags) sector->updateSoundEmitterOrigin(); #ifdef __CLIENT__ map.updateMissingMaterialsForLinesOfSector(*sector); - S_MarkSectorReverbDirty(sector); + sector->markReverbDirty(); #endif } diff --git a/doomsday/client/src/world/sector.cpp b/doomsday/client/src/world/sector.cpp index 2465f4b03c..8ddf7efe99 100644 --- a/doomsday/client/src/world/sector.cpp +++ b/doomsday/client/src/world/sector.cpp @@ -84,6 +84,7 @@ DENG2_OBSERVES(Plane, HeightChange) /// Final environmental audio characteristics. AudioEnvironmentFactors reverb; + bool needReverbUpdate; ///< @true= marked for update. bool visible; ///< @c true= marked as visible for the current frame. #endif @@ -98,7 +99,8 @@ DENG2_OBSERVES(Plane, HeightChange) lightColor(lightColor), validCount(0) #ifdef __CLIENT__ - ,visible(false) + ,needReverbUpdate(true), + visible(false) #endif { zap(soundEmitter); @@ -157,6 +159,87 @@ DENG2_OBSERVES(Plane, HeightChange) static_cast(context)->addReverbBspLeaf(bspLeaf); return false; // Continue iteration. } + + /** + * Recalculate environmental audio (reverb) for the sector. + */ + void updateReverb() + { + needReverbUpdate = false; + + // Sectors with no referencing lines need no reverb. + if(!self.sideCount()) + return; + + uint spaceVolume = int((self.ceiling().height() - self.floor().height()) * self.roughArea()); + + reverb[SRD_SPACE] = reverb[SRD_VOLUME] = + reverb[SRD_DECAY] = reverb[SRD_DAMPING] = 0; + + foreach(BspLeaf *bspLeaf, reverbBspLeafs) + { + if(bspLeaf->updateReverb()) + { + BspLeaf::AudioEnvironmentFactors const &leafReverb = bspLeaf->reverb(); + + reverb[SRD_SPACE] += leafReverb[SRD_SPACE]; + + reverb[SRD_VOLUME] += leafReverb[SRD_VOLUME] / 255.0f * leafReverb[SRD_SPACE]; + reverb[SRD_DECAY] += leafReverb[SRD_DECAY] / 255.0f * leafReverb[SRD_SPACE]; + reverb[SRD_DAMPING] += leafReverb[SRD_DAMPING] / 255.0f * leafReverb[SRD_SPACE]; + } + } + + float spaceScatter; + if(reverb[SRD_SPACE]) + { + spaceScatter = spaceVolume / reverb[SRD_SPACE]; + // These three are weighted by the space. + reverb[SRD_VOLUME] /= reverb[SRD_SPACE]; + reverb[SRD_DECAY] /= reverb[SRD_SPACE]; + reverb[SRD_DAMPING] /= reverb[SRD_SPACE]; + } + else + { + spaceScatter = 0; + reverb[SRD_VOLUME] = .2f; + reverb[SRD_DECAY] = .4f; + reverb[SRD_DAMPING] = 1; + } + + // If the space is scattered, the reverb effect lessens. + reverb[SRD_SPACE] /= (spaceScatter > .8 ? 10 : spaceScatter > .6 ? 4 : 1); + + // Normalize the reverb space [0..1] + // 0= very small + // .99= very large + // 1.0= only for open areas (special case). + reverb[SRD_SPACE] /= 120e6; + if(reverb[SRD_SPACE] > .99) + reverb[SRD_SPACE] = .99f; + + if(self.ceilingSurface().hasSkyMaskedMaterial() || + self.floorSurface().hasSkyMaskedMaterial()) + { + // An "open" sector. + // It can still be small, in which case; reverb is diminished a bit. + if(reverb[SRD_SPACE] > .5) + reverb[SRD_VOLUME] = 1; // Full volume. + else + reverb[SRD_VOLUME] = .5f; // Small, but still open. + + reverb[SRD_SPACE] = 1; + } + else + { + // A "closed" sector. + // Large spaces have automatically a bit more audible reverb. + reverb[SRD_VOLUME] += reverb[SRD_SPACE] / 4; + } + + if(reverb[SRD_VOLUME] > 1) + reverb[SRD_VOLUME] = 1; + } #endif // Observes Plane HeightChange. @@ -173,7 +256,11 @@ DENG2_OBSERVES(Plane, HeightChange) #ifdef __CLIENT__ /// @todo Map should observe. self.map().updateMissingMaterialsForLinesOfSector(self); - S_MarkSectorReverbDirty(&self); +#endif + +#ifdef __CLIENT__ + // We'll need to recalculate environmental audio characteristics. + needReverbUpdate = true; #endif // Check if there are any camera players in this sector. If their @@ -308,7 +395,7 @@ void Sector::initReverb() { d->reverbBspLeafs.clear(); - // Sectors which no referencing line need no reverb. + // Sectors with no referencing lines need no reverb. if(!sideCount()) return; AABoxd affectionBounds = aaBox(); @@ -325,85 +412,23 @@ void Sector::initReverb() // Link all non-degenerate BspLeafs whose axis-aligned bounding box intersects // with the affection bounds to the reverb set. map().bspLeafsBoxIterator(affectionBounds, 0, Instance::addReverbBspLeafWorker, d); + + // We still need to update the final characteristics. + d->needReverbUpdate = true; } -void Sector::updateReverb() +void Sector::markReverbDirty(bool yes) { - // Sectors which no referencing line need no reverb. - if(!sideCount()) - return; - - uint spaceVolume = int((ceiling().height() - floor().height()) * roughArea()); - - d->reverb[SRD_SPACE] = d->reverb[SRD_VOLUME] = - d->reverb[SRD_DECAY] = d->reverb[SRD_DAMPING] = 0; - - foreach(BspLeaf *bspLeaf, d->reverbBspLeafs) - { - if(bspLeaf->updateReverb()) - { - BspLeaf::AudioEnvironmentFactors const &leafReverb = bspLeaf->reverb(); - - d->reverb[SRD_SPACE] += leafReverb[SRD_SPACE]; - - d->reverb[SRD_VOLUME] += leafReverb[SRD_VOLUME] / 255.0f * leafReverb[SRD_SPACE]; - d->reverb[SRD_DECAY] += leafReverb[SRD_DECAY] / 255.0f * leafReverb[SRD_SPACE]; - d->reverb[SRD_DAMPING] += leafReverb[SRD_DAMPING] / 255.0f * leafReverb[SRD_SPACE]; - } - } - - float spaceScatter; - if(d->reverb[SRD_SPACE]) - { - spaceScatter = spaceVolume / d->reverb[SRD_SPACE]; - // These three are weighted by the space. - d->reverb[SRD_VOLUME] /= d->reverb[SRD_SPACE]; - d->reverb[SRD_DECAY] /= d->reverb[SRD_SPACE]; - d->reverb[SRD_DAMPING] /= d->reverb[SRD_SPACE]; - } - else - { - spaceScatter = 0; - d->reverb[SRD_VOLUME] = .2f; - d->reverb[SRD_DECAY] = .4f; - d->reverb[SRD_DAMPING] = 1; - } - - // If the space is scattered, the reverb effect lessens. - d->reverb[SRD_SPACE] /= (spaceScatter > .8 ? 10 : spaceScatter > .6 ? 4 : 1); - - // Normalize the reverb space [0..1] - // 0= very small - // .99= very large - // 1.0= only for open areas (special case). - d->reverb[SRD_SPACE] /= 120e6; - if(d->reverb[SRD_SPACE] > .99) - d->reverb[SRD_SPACE] = .99f; - - if(ceilingSurface().hasSkyMaskedMaterial() || floorSurface().hasSkyMaskedMaterial()) - { - // An "open" sector. - // It can still be small, in which case; reverb is diminished a bit. - if(d->reverb[SRD_SPACE] > .5) - d->reverb[SRD_VOLUME] = 1; // Full volume. - else - d->reverb[SRD_VOLUME] = .5f; // Small, but still open. - - d->reverb[SRD_SPACE] = 1; - } - else - { - // A "closed" sector. - // Large spaces have automatically a bit more audible reverb. - d->reverb[SRD_VOLUME] += d->reverb[SRD_SPACE] / 4; - } - - if(d->reverb[SRD_VOLUME] > 1) - d->reverb[SRD_VOLUME] = 1; + d->needReverbUpdate = yes; } AudioEnvironmentFactors const &Sector::reverb() const { + // Perform any scheduled update now. + if(d->needReverbUpdate) + { + d->updateReverb(); + } return d->reverb; } diff --git a/doomsday/client/src/world/world.cpp b/doomsday/client/src/world/world.cpp index 2af578da79..2be348aa58 100644 --- a/doomsday/client/src/world/world.cpp +++ b/doomsday/client/src/world/world.cpp @@ -607,7 +607,7 @@ DENG2_PIMPL(World) sector->updateSoundEmitterOrigin(); #ifdef __CLIENT__ map->updateMissingMaterialsForLinesOfSector(*sector); - S_MarkSectorReverbDirty(sector); + sector->markReverbDirty(); #endif }