From bfa8a2cd751afa3d9a344e6b9b9e1191657b0493 Mon Sep 17 00:00:00 2001 From: danij Date: Fri, 12 Apr 2013 04:07:01 +0100 Subject: [PATCH] Sector: Observe Plane HeightChange notification --- doomsday/client/include/map/plane.h | 8 +- doomsday/client/include/map/r_world.h | 5 +- doomsday/client/include/map/sector.h | 9 +- doomsday/client/src/edit_map.cpp | 2 + doomsday/client/src/map/p_dmu.cpp | 3 +- doomsday/client/src/map/plane.cpp | 21 +- doomsday/client/src/map/r_world.cpp | 464 ++++++++++---------------- doomsday/client/src/map/sector.cpp | 62 ++++ 8 files changed, 280 insertions(+), 294 deletions(-) diff --git a/doomsday/client/include/map/plane.h b/doomsday/client/include/map/plane.h index 60129eca7d..1a55876a39 100644 --- a/doomsday/client/include/map/plane.h +++ b/doomsday/client/include/map/plane.h @@ -56,7 +56,7 @@ class Plane : public de::MapElement /** * Observers to be notified whenever a @em sharp height change occurs. */ - DENG2_DEFINE_AUDIENCE(HeightChange, void planeHeightChanged(Plane const &plane, coord_t oldHeight)) + DENG2_DEFINE_AUDIENCE(HeightChange, void planeHeightChanged(Plane &plane, coord_t oldHeight)) static int const MAX_SMOOTH_MOVE; ///< 64, $smoothplane: Maximum speed for a smoothed plane. @@ -69,9 +69,9 @@ class Plane : public de::MapElement }; public: /// @todo Make private: - coord_t _oldHeight[2]; - coord_t _targetHeight; ///< Target height. - coord_t _visHeight; ///< Visual plane height (smoothed). + coord_t _oldHeight[2]; + coord_t _targetHeight; ///< Target height. + coord_t _visHeight; ///< Visual plane height (smoothed). public: /** diff --git a/doomsday/client/include/map/r_world.h b/doomsday/client/include/map/r_world.h index a6bf972180..d9394057db 100644 --- a/doomsday/client/include/map/r_world.h +++ b/doomsday/client/include/map/r_world.h @@ -67,6 +67,8 @@ boolean R_SectorContainsSkySurfaces(Sector const *sec); void R_ClearSectorFlags(); +void R_UpdateMissingMaterialsForLinesOfSector(Sector const &sec); + /** * Returns pointers to the line's vertices in such a fashion that @c verts[0] * is the leftmost vertex and @c verts[1] is the rightmost vertex, when the @@ -172,8 +174,7 @@ boolean R_MiddleMaterialCoversOpening(int lineFlags, Sector const *frontSec, boolean R_MiddleMaterialCoversLineOpening(LineDef const *line, int side, boolean ignoreOpacity); #endif // __CLIENT__ -bool R_UpdateSector(Sector §or, bool forceUpdate = false); -bool R_UpdatePlane(Plane &plane, bool forceUpdate = false); +void R_UpdateSector(Sector §or, bool forceUpdate = false); /// @return Current glow strength for the plane. float R_GlowStrength(Plane const *pln); diff --git a/doomsday/client/include/map/sector.h b/doomsday/client/include/map/sector.h index baffc086d6..ab19bbe8ea 100644 --- a/doomsday/client/include/map/sector.h +++ b/doomsday/client/include/map/sector.h @@ -49,11 +49,12 @@ class LineDef; ///@} /** - * Map sector. + * World map sector. * * @ingroup map */ -class Sector : public de::MapElement +class Sector : public de::MapElement, + DENG2_OBSERVES(Plane, HeightChange) { public: /// Required/referenced plane is missing. @ingroup errors @@ -480,6 +481,10 @@ class Sector : public de::MapElement */ int setProperty(setargs_t const &args); +protected: + // Observes Plane HeightChange. + void planeHeightChanged(Plane &plane, coord_t oldHeight); + private: DENG2_PRIVATE(d) }; diff --git a/doomsday/client/src/edit_map.cpp b/doomsday/client/src/edit_map.cpp index c15deb0b50..85d377624e 100644 --- a/doomsday/client/src/edit_map.cpp +++ b/doomsday/client/src/edit_map.cpp @@ -1251,6 +1251,8 @@ uint MPE_PlaneCreate(uint sectorIdx, coord_t height, ddstring_t const *materialU sector->_planes.append(plane); plane->setInSectorIndex(sector->planeCount() - 1); + plane->audienceForHeightChange += sector; + return plane->inSectorIndex() + 1; // 1-based index. } diff --git a/doomsday/client/src/map/p_dmu.cpp b/doomsday/client/src/map/p_dmu.cpp index 51f94b2bde..825704e75f 100644 --- a/doomsday/client/src/map/p_dmu.cpp +++ b/doomsday/client/src/map/p_dmu.cpp @@ -1036,8 +1036,7 @@ static int setProperty(void *ptr, void *context) if(updatePlane) { - if(R_UpdatePlane(*updatePlane)) - updateSector1 = &updatePlane->sector(); + updateSector1 = &updatePlane->sector(); } if(updateSector1) diff --git a/doomsday/client/src/map/plane.cpp b/doomsday/client/src/map/plane.cpp index 8262c4d094..7642ca5d36 100644 --- a/doomsday/client/src/map/plane.cpp +++ b/doomsday/client/src/map/plane.cpp @@ -1,4 +1,4 @@ -/** @file plane.h Map Plane. +/** @file plane.h World Map Plane. * * @authors Copyright © 2003-2013 Jaakko Keränen * @authors Copyright © 2006-2013 Daniel Swanson @@ -18,13 +18,13 @@ * 02110-1301 USA */ +#include + #include "de_base.h" -#include "de_console.h" -#include "de_play.h" +#include "audio/s_environ.h" #include "map/linedef.h" #include "map/gamemap.h" - #include "render/r_main.h" // frameTimePos #include "map/plane.h" @@ -108,6 +108,17 @@ DENG2_PIMPL(Plane) coord_t oldHeight = height; height = newHeight; + if(!ddMapSetup) + { +#ifdef __CLIENT__ + // Update the sound emitter origin for the plane. + surface.updateSoundEmitterOrigin(); +#endif + + // We need the decorations updated. + surface.markAsNeedingDecorationUpdate(); + } + // Notify interested parties of the change. notifyHeightChanged(oldHeight); @@ -129,6 +140,8 @@ DENG2_PIMPL(Plane) /** * To be called when the height changes to update the plotted decoration * origins for surfaces whose material offset is dependant upon this. + * + * @todo Sector should observe instead. */ void markDependantSurfacesForDecorationUpdate() { diff --git a/doomsday/client/src/map/r_world.cpp b/doomsday/client/src/map/r_world.cpp index dd147b7efc..a967b7518e 100644 --- a/doomsday/client/src/map/r_world.cpp +++ b/doomsday/client/src/map/r_world.cpp @@ -506,20 +506,6 @@ LineDef *R_FindLineAlignNeighbor(Sector const *sec, LineDef const *line, } #endif // __CLIENT__ -/** - * Set intial values of various tracked and interpolated properties - * (lighting, smoothed planes etc). - */ -static void updateAllMapSectors(GameMap &map, bool forceUpdate = false) -{ - if(novideo) return; - - foreach(Sector *sector, map.sectors()) - { - R_UpdateSector(*sector, forceUpdate); - } -} - static void resetAllMapPlaneVisHeights(GameMap &map) { foreach(Sector *sector, map.sectors()) @@ -550,202 +536,6 @@ static void resetAllMapSurfaceVisMaterialOrigins(GameMap &map) } } -#undef R_SetupMap -DENG_EXTERN_C void R_SetupMap(int mode, int flags) -{ - DENG_UNUSED(flags); - - switch(mode) - { - case DDSMM_INITIALIZE: - // A new map is about to be setup. - ddMapSetup = true; - -#ifdef __CLIENT__ - App_Materials().purgeCacheQueue(); -#endif - return; - - case DDSMM_AFTER_LOADING: - DENG_ASSERT(theMap); - - // Update everything again. Its possible that after loading we - // now have more HOMs to fix, etc.. - theMap->initSkyFix(); - - updateAllMapSectors(*theMap, true /*force*/); - resetAllMapPlaneVisHeights(*theMap); - resetAllMapSurfaceVisMaterialOrigins(*theMap); - theMap->initPolyobjs(); - DD_ResetTimer(); - return; - - case DDSMM_FINALIZE: { - DENG_ASSERT(theMap); - - if(gameTime > 20000000 / TICSPERSEC) - { - // In very long-running games, gameTime will become so large that it cannot be - // accurately converted to 35 Hz integer tics. Thus it needs to be reset back - // to zero. - gameTime = 0; - } - - // We are now finished with the map entity db. - EntityDatabase_Delete(theMap->entityDatabase); - -#ifdef __SERVER__ - // Init server data. - Sv_InitPools(); -#endif - - // Recalculate the light range mod matrix. - Rend_CalcLightModRange(); - - theMap->initPolyobjs(); - P_MapSpawnPlaneParticleGens(); - - updateAllMapSectors(*theMap, true /*force*/); - resetAllMapPlaneVisHeights(*theMap); - resetAllMapSurfaceVisMaterialOrigins(*theMap); - -#ifdef __CLIENT__ - theMap->buildSurfaceLists(); - - float startTime = Timer_Seconds(); - Rend_CacheForMap(); - App_Materials().processCacheQueue(); - VERBOSE( Con_Message("Precaching took %.2f seconds.", Timer_Seconds() - startTime) ) -#endif - - S_SetupForChangedMap(); - - // Map setup has been completed. - - // Run any commands specified in Map Info. - de::Uri mapUri = theMap->uri(); - ded_mapinfo_t *mapInfo = Def_GetMapInfo(reinterpret_cast(&mapUri)); - if(mapInfo && mapInfo->execute) - { - Con_Execute(CMDS_SCRIPT, mapInfo->execute, true, false); - } - - // Run the special map setup command, which the user may alias to do something useful. - String cmd = "init-" + mapUri.resolved(); - if(Con_IsValidCommand(cmd.toUtf8().constData())) - { - Con_Executef(CMDS_SCRIPT, false, "%s", cmd.toUtf8().constData()); - } - -#ifdef __CLIENT__ - // Clear any input events that might have accumulated during the - // setup period. - DD_ClearEvents(); -#endif - - // Now that the setup is done, let's reset the tictimer so it'll - // appear that no time has passed during the setup. - DD_ResetTimer(); - - // Kill all local commands and determine the invoid status of players. - for(int i = 0; i < DDMAXPLAYERS; ++i) - { - player_t *plr = &ddPlayers[i]; - ddplayer_t *ddpl = &plr->shared; - - //clients[i].numTics = 0; - - // Determine if the player is in the void. - ddpl->inVoid = true; - if(ddpl->mo) - { - BspLeaf *bspLeaf = P_BspLeafAtPoint(ddpl->mo->origin); - if(bspLeaf) - { - /// @todo $nplanes - if(ddpl->mo->origin[VZ] >= bspLeaf->sector().floor().visHeight() && - ddpl->mo->origin[VZ] < bspLeaf->sector().ceiling().visHeight() - 4) - { - ddpl->inVoid = false; - } - } - } - } - - // Reset the map tick timer. - ddMapTime = 0; - - // We've finished setting up the map. - ddMapSetup = false; - - // Inform the timing system to suspend the starting of the clock. - firstFrameAfterLoad = true; - - DENG2_FOR_AUDIENCE(MapChange, i) i->currentMapChanged(); - - Z_PrintStatus(); - return; } - - default: - Con_Error("R_SetupMap: Unknown setup mode %i", mode); - exit(1); // Unreachable. - } -} - -void R_ClearSectorFlags() -{ - if(!theMap) return; - - foreach(Sector *sector, theMap->sectors()) - { - // Clear all flags that can be cleared before each frame. - sector->_frameFlags &= ~SIF_FRAME_CLEAR; - } -} - -float R_GlowStrength(Plane const *plane) -{ -#ifdef __CLIENT__ - Surface const &surface = plane->surface(); - if(surface.hasMaterial() && glowFactor > .0001f) - { - if(surface.material().isDrawable() && !surface.hasSkyMaskedMaterial()) - { - MaterialSnapshot const &ms = surface.material().prepare(Rend_MapSurfaceMaterialSpec()); - - float glowStrength = ms.glowStrength() * glowFactor; // Global scale factor. - return glowStrength; - } - } -#else - DENG_UNUSED(plane); -#endif - return 0; -} - -/** - * Does the specified sector contain any sky surface planes? - * - * @return @c true, if one or more plane surfaces in the given sector use - * a sky-masked material. - */ -boolean R_SectorContainsSkySurfaces(Sector const *sec) -{ - DENG_ASSERT(sec); - - boolean sectorContainsSkySurfaces = false; - uint n = 0; - do - { - if(sec->planeSurface(n).hasSkyMaskedMaterial()) - sectorContainsSkySurfaces = true; - else - n++; - } while(!sectorContainsSkySurfaces && n < sec->planeCount()); - - return sectorContainsSkySurfaces; -} - #ifdef __CLIENT__ /** @@ -873,10 +663,8 @@ static void addMissingMaterial(SideDef *s, SideDefSection section) << path; } } -#endif // __CLIENT__ -#ifdef __CLIENT__ -static void updateMissingMaterialsForLinesOfSector(Sector const &sec) +void R_UpdateMissingMaterialsForLinesOfSector(Sector const &sec) { foreach(LineDef *line, sec.lines()) { @@ -926,78 +714,217 @@ static void updateMissingMaterialsForLinesOfSector(Sector const &sec) } #endif // __CLIENT__ -bool R_UpdatePlane(Plane &plane, bool forceUpdate) +static void updateAllMapSectors(GameMap &map) { - Sector *sec = &plane.sector(); - bool changed = false; + foreach(Sector *sector, map.sectors()) + { + sector->updateSoundEmitterOrigin(); +#ifdef __CLIENT__ + R_UpdateMissingMaterialsForLinesOfSector(*sector); +#endif + S_MarkSectorReverbDirty(sector); + } +} - // Geometry change? - if(forceUpdate || plane.height() != plane._oldHeight[1]) +#undef R_SetupMap +DENG_EXTERN_C void R_SetupMap(int mode, int flags) +{ + DENG_UNUSED(flags); + + switch(mode) { - // Check if there are any camera players in this sector. If their - // height is now above the ceiling/below the floor they are now in - // the void. - for(uint i = 0; i < DDMAXPLAYERS; ++i) + case DDSMM_INITIALIZE: + // A new map is about to be setup. + ddMapSetup = true; + +#ifdef __CLIENT__ + App_Materials().purgeCacheQueue(); +#endif + return; + + case DDSMM_AFTER_LOADING: + DENG_ASSERT(theMap); + + // Update everything again. Its possible that after loading we + // now have more HOMs to fix, etc.. + theMap->initSkyFix(); + + updateAllMapSectors(*theMap); + resetAllMapPlaneVisHeights(*theMap); + resetAllMapSurfaceVisMaterialOrigins(*theMap); + + theMap->initPolyobjs(); + DD_ResetTimer(); + return; + + case DDSMM_FINALIZE: { + DENG_ASSERT(theMap); + + if(gameTime > 20000000 / TICSPERSEC) { - player_t *plr = &ddPlayers[i]; - ddplayer_t *ddpl = &plr->shared; + // In very long-running games, gameTime will become so large that it cannot be + // accurately converted to 35 Hz integer tics. Thus it needs to be reset back + // to zero. + gameTime = 0; + } - if(!ddpl->inGame || !ddpl->mo || !ddpl->mo->bspLeaf) - continue; + // We are now finished with the map entity db. + EntityDatabase_Delete(theMap->entityDatabase); - /// @todo $nplanes - if((ddpl->flags & DDPF_CAMERA) && ddpl->mo->bspLeaf->sectorPtr() == sec && - (ddpl->mo->origin[VZ] > sec->ceiling().height() - 4 || ddpl->mo->origin[VZ] < sec->floor().height())) - { - ddpl->inVoid = true; - } +#ifdef __SERVER__ + // Init server data. + Sv_InitPools(); +#endif + + // Recalculate the light range mod matrix. + Rend_CalcLightModRange(); + + theMap->initPolyobjs(); + P_MapSpawnPlaneParticleGens(); + + updateAllMapSectors(*theMap); + resetAllMapPlaneVisHeights(*theMap); + resetAllMapSurfaceVisMaterialOrigins(*theMap); + +#ifdef __CLIENT__ + theMap->buildSurfaceLists(); + + float startTime = Timer_Seconds(); + Rend_CacheForMap(); + App_Materials().processCacheQueue(); + VERBOSE( Con_Message("Precaching took %.2f seconds.", Timer_Seconds() - startTime) ) +#endif + + S_SetupForChangedMap(); + + // Map setup has been completed. + + // Run any commands specified in Map Info. + de::Uri mapUri = theMap->uri(); + ded_mapinfo_t *mapInfo = Def_GetMapInfo(reinterpret_cast(&mapUri)); + if(mapInfo && mapInfo->execute) + { + Con_Execute(CMDS_SCRIPT, mapInfo->execute, true, false); } - // Update the sound emitter origins for this plane and all dependent wall surfaces. - plane.surface().updateSoundEmitterOrigin(); - foreach(LineDef *line, sec->lines()) + // Run the special map setup command, which the user may alias to do something useful. + String cmd = "init-" + mapUri.resolved(); + if(Con_IsValidCommand(cmd.toUtf8().constData())) { - line->front().updateSoundEmitterOrigins(); - line->back().updateSoundEmitterOrigins(); + Con_Executef(CMDS_SCRIPT, false, "%s", cmd.toUtf8().constData()); } #ifdef __CLIENT__ - // Inform the shadow bias of changed geometry. - foreach(BspLeaf *bspLeaf, sec->bspLeafs()) + // Clear any input events that might have accumulated during the + // setup period. + DD_ClearEvents(); +#endif + + // Now that the setup is done, let's reset the tictimer so it'll + // appear that no time has passed during the setup. + DD_ResetTimer(); + + // Kill all local commands and determine the invoid status of players. + for(int i = 0; i < DDMAXPLAYERS; ++i) { - if(HEdge *base = bspLeaf->firstHEdge()) + player_t *plr = &ddPlayers[i]; + ddplayer_t *ddpl = &plr->shared; + + //clients[i].numTics = 0; + + // Determine if the player is in the void. + ddpl->inVoid = true; + if(ddpl->mo) { - HEdge *hedge = base; - do + BspLeaf *bspLeaf = P_BspLeafAtPoint(ddpl->mo->origin); + if(bspLeaf) { - if(hedge->hasLine()) + /// @todo $nplanes + if(ddpl->mo->origin[VZ] >= bspLeaf->sector().floor().visHeight() && + ddpl->mo->origin[VZ] < bspLeaf->sector().ceiling().visHeight() - 4) { - for(uint i = 0; i < 3; ++i) - { - SB_SurfaceMoved(&hedge->biasSurfaceForGeometryGroup(i)); - } + ddpl->inVoid = false; } - } while((hedge = &hedge->next()) != base); + } } - - SB_SurfaceMoved(&bspLeaf->biasSurfaceForGeometryGroup(plane.inSectorIndex())); } - // We need the decorations updated. - plane.surface().markAsNeedingDecorationUpdate(); + // Reset the map tick timer. + ddMapTime = 0; -#endif // __CLIENT__ + // We've finished setting up the map. + ddMapSetup = false; + + // Inform the timing system to suspend the starting of the clock. + firstFrameAfterLoad = true; + + DENG2_FOR_AUDIENCE(MapChange, i) i->currentMapChanged(); + + Z_PrintStatus(); + return; } - changed = true; + default: + Con_Error("R_SetupMap: Unknown setup mode %i", mode); + exit(1); // Unreachable. } +} - return changed; +void R_ClearSectorFlags() +{ + if(!theMap) return; + + foreach(Sector *sector, theMap->sectors()) + { + // Clear all flags that can be cleared before each frame. + sector->_frameFlags &= ~SIF_FRAME_CLEAR; + } } -bool R_UpdateSector(Sector §or, bool forceUpdate) +float R_GlowStrength(Plane const *plane) { - bool changed = false, planeChanged = false; +#ifdef __CLIENT__ + Surface const &surface = plane->surface(); + if(surface.hasMaterial() && glowFactor > .0001f) + { + if(surface.material().isDrawable() && !surface.hasSkyMaskedMaterial()) + { + MaterialSnapshot const &ms = surface.material().prepare(Rend_MapSurfaceMaterialSpec()); + + float glowStrength = ms.glowStrength() * glowFactor; // Global scale factor. + return glowStrength; + } + } +#else + DENG_UNUSED(plane); +#endif + return 0; +} +/** + * Does the specified sector contain any sky surface planes? + * + * @return @c true, if one or more plane surfaces in the given sector use + * a sky-masked material. + */ +boolean R_SectorContainsSkySurfaces(Sector const *sec) +{ + DENG_ASSERT(sec); + + boolean sectorContainsSkySurfaces = false; + uint n = 0; + do + { + if(sec->planeSurface(n).hasSkyMaskedMaterial()) + sectorContainsSkySurfaces = true; + else + n++; + } while(!sectorContainsSkySurfaces && n < sec->planeCount()); + + return sectorContainsSkySurfaces; +} + +void R_UpdateSector(Sector §or, bool forceUpdate) +{ #ifdef __CLIENT__ // Check if there are any lightlevel or color changes. if(forceUpdate || @@ -1011,35 +938,12 @@ bool R_UpdateSector(Sector §or, bool forceUpdate) sector._oldLightColor = sector._lightColor; LG_SectorChanged(§or); - changed = true; } else { sector._frameFlags &= ~SIF_LIGHT_CHANGED; } #endif - - foreach(Plane *plane, sector.planes()) - { - if(R_UpdatePlane(*plane, forceUpdate)) - { - planeChanged = true; - } - } - - if(forceUpdate || planeChanged) - { - sector.updateSoundEmitterOrigin(); -#ifdef __CLIENT__ - updateMissingMaterialsForLinesOfSector(sector); -#endif - S_MarkSectorReverbDirty(§or); - changed = true; - } - - DENG_UNUSED(changed); /// @todo Should it be used? -jk - - return planeChanged; } /** diff --git a/doomsday/client/src/map/sector.cpp b/doomsday/client/src/map/sector.cpp index 68c1bb09e8..40963d3cd9 100644 --- a/doomsday/client/src/map/sector.cpp +++ b/doomsday/client/src/map/sector.cpp @@ -26,6 +26,7 @@ #include "map/bspleaf.h" #include "map/linedef.h" #include "map/gamemap.h" +#include "map/p_players.h" #ifdef __CLIENT__ # include "render/rend_bias.h" #endif @@ -362,6 +363,67 @@ void Sector::updateSoundEmitterOrigin() d->soundEmitter.origin[VZ] = (floor().height() + ceiling().height()) / 2; } +void Sector::planeHeightChanged(Plane &plane, coord_t oldHeight) +{ + updateSoundEmitterOrigin(); +#ifdef __CLIENT__ + R_UpdateMissingMaterialsForLinesOfSector(*this); +#endif + S_MarkSectorReverbDirty(this); + + // Check if there are any camera players in this sector. If their + // height is now above the ceiling/below the floor they are now in + // the void. + for(uint i = 0; i < DDMAXPLAYERS; ++i) + { + player_t *plr = &ddPlayers[i]; + ddplayer_t *ddpl = &plr->shared; + + if(!ddpl->inGame || !ddpl->mo || !ddpl->mo->bspLeaf) + continue; + + /// @todo $nplanes + if((ddpl->flags & DDPF_CAMERA) && ddpl->mo->bspLeaf->sectorPtr() == this && + (ddpl->mo->origin[VZ] > ceiling().height() - 4 || ddpl->mo->origin[VZ] < floor().height())) + { + ddpl->inVoid = true; + } + } + + // Update the sound emitter origins for all dependent wall surfaces. + foreach(LineDef *line, d->lines) + { + line->front().updateSoundEmitterOrigins(); + line->back().updateSoundEmitterOrigins(); + } + +#ifdef __CLIENT__ + // Inform the shadow bias of changed geometry. + foreach(BspLeaf *bspLeaf, d->bspLeafs) + { + if(HEdge *base = bspLeaf->firstHEdge()) + { + HEdge *hedge = base; + do + { + if(hedge->hasLine()) + { + for(uint i = 0; i < 3; ++i) + { + SB_SurfaceMoved(&hedge->biasSurfaceForGeometryGroup(i)); + } + } + } while((hedge = &hedge->next()) != base); + } + + SB_SurfaceMoved(&bspLeaf->biasSurfaceForGeometryGroup(plane.inSectorIndex())); + } + +#endif // __CLIENT__ + + DENG2_UNUSED2(plane, oldHeight); +} + int Sector::property(setargs_t &args) const { switch(args.prop)