diff --git a/doomsday/apps/client/include/client/clientsubsector.h b/doomsday/apps/client/include/client/clientsubsector.h index 7648601583..a2717a7104 100644 --- a/doomsday/apps/client/include/client/clientsubsector.h +++ b/doomsday/apps/client/include/client/clientsubsector.h @@ -92,8 +92,8 @@ class ClientSubsector : public Subsector, public ILightSource * * @param callback Function to call for each edge loop. */ - de::LoopResult forAllEdgeLoops(std::function func); - de::LoopResult forAllEdgeLoops(std::function func) const; + de::LoopResult forAllEdgeLoops(const std::function &func); + de::LoopResult forAllEdgeLoops(const std::function &func) const; //- Audio environment ------------------------------------------------------------------- diff --git a/doomsday/apps/client/include/clientapp.h b/doomsday/apps/client/include/clientapp.h index 2aac04ea38..9bb8fb781e 100644 --- a/doomsday/apps/client/include/clientapp.h +++ b/doomsday/apps/client/include/clientapp.h @@ -79,7 +79,7 @@ class ClientApp : public de::BaseGuiApp, public DoomsdayApp static void alert(de::String const &msg, de::LogEntry::Level level = de::LogEntry::Message); static ClientPlayer &player(int console); - static de::LoopResult forLocalPlayers(std::function func); + static de::LoopResult forLocalPlayers(const std::function &func); static ClientApp & app(); static ConfigProfiles & logSettings(); diff --git a/doomsday/apps/client/include/resource/clientmaterial.h b/doomsday/apps/client/include/resource/clientmaterial.h index 788c7d2426..1b82208c2f 100644 --- a/doomsday/apps/client/include/resource/clientmaterial.h +++ b/doomsday/apps/client/include/resource/clientmaterial.h @@ -45,7 +45,9 @@ class ClientMaterial : public world::Material */ ClientMaterial(world::MaterialManifest &manifest); - ~ClientMaterial(); + ~ClientMaterial() override; + + bool isAnimated() const override; /** * Returns a human-friendly, textual description of the full material configuration. @@ -200,7 +202,7 @@ class ClientMaterial : public world::Material * * @param func Callback to make for each Decoration. */ - de::LoopResult forAllDecorations(std::function func) const; + de::LoopResult forAllDecorations(const std::function &func) const; /** * Add a new (light) decoration to the material. @@ -242,7 +244,7 @@ class ClientMaterial : public world::Material * * @param func Callback to make for each Animator. */ - de::LoopResult forAllAnimators(std::function func) const; + de::LoopResult forAllAnimators(const std::function &func) const; /** * Destroy all the MaterialAnimators for the material. diff --git a/doomsday/apps/client/include/world/sector.h b/doomsday/apps/client/include/world/sector.h index 367487fa29..af56d6a48e 100644 --- a/doomsday/apps/client/include/world/sector.h +++ b/doomsday/apps/client/include/world/sector.h @@ -238,7 +238,7 @@ class Sector : public world::MapElement * * @param callback Function to call for each Subsector. */ - de::LoopResult forAllSubsectors(std::function callback) const; + de::LoopResult forAllSubsectors(const std::function &callback) const; /** * Generate a new Subsector from the given set of map @a subspaces. diff --git a/doomsday/apps/client/src/client/clientsubsector.cpp b/doomsday/apps/client/src/client/clientsubsector.cpp index 0a5beaf3c1..0c829d31f9 100644 --- a/doomsday/apps/client/src/client/clientsubsector.cpp +++ b/doomsday/apps/client/src/client/clientsubsector.cpp @@ -1027,10 +1027,10 @@ DENG2_PIMPL(ClientSubsector) ds.markForUpdate(false); - // Clear any existing decorations. qDeleteAll(ds.decorations); ds.decorations.clear(); + // Clear any existing decorations. if (surface.hasMaterial()) { Vector2f materialOrigin; @@ -1471,7 +1471,7 @@ dint ClientSubsector::edgeLoopCount() const return (bool(d->boundaryData->outerLoop) ? 1 : 0) + d->boundaryData->innerLoops.count(); } -LoopResult ClientSubsector::forAllEdgeLoops(std::function func) +LoopResult ClientSubsector::forAllEdgeLoops(const std::function &func) { d->initBoundaryDataIfNeeded(); DENG2_ASSERT(bool(d->boundaryData->outerLoop)); @@ -1487,7 +1487,7 @@ LoopResult ClientSubsector::forAllEdgeLoops(std::function func) const +LoopResult ClientSubsector::forAllEdgeLoops(const std::function &func) const { d->initBoundaryDataIfNeeded(); DENG2_ASSERT(bool(d->boundaryData->outerLoop)); @@ -1848,14 +1848,16 @@ void ClientSubsector::decorate() { LOG_AS("ClientSubsector::decorate"); - auto decorateFunc = [this] (Surface &surface) - { - d->decorate(surface); - return LoopContinue; - }; + if (!hasDecorations()) return; + +// auto decorateFunc = [this] (Surface &surface) +// { +// d->decorate(surface); +// return LoopContinue; +// }; // Surfaces of the edge loops. - forAllEdgeLoops([this, &decorateFunc] (ClEdgeLoop const &loop) + forAllEdgeLoops([this/*, &decorateFunc*/] (ClEdgeLoop const &loop) { SubsectorCirculator it(&loop.first()); do diff --git a/doomsday/apps/client/src/clientapp.cpp b/doomsday/apps/client/src/clientapp.cpp index 269223d173..bde4c86902 100644 --- a/doomsday/apps/client/src/clientapp.cpp +++ b/doomsday/apps/client/src/clientapp.cpp @@ -817,7 +817,7 @@ ClientPlayer &ClientApp::player(int console) // static return DoomsdayApp::players().at(console).as(); } -LoopResult ClientApp::forLocalPlayers(std::function func) // static +LoopResult ClientApp::forLocalPlayers(const std::function &func) // static { auto const &players = DoomsdayApp::players(); for (int i = 0; i < players.count(); ++i) diff --git a/doomsday/apps/client/src/gl/dgl_draw.cpp b/doomsday/apps/client/src/gl/dgl_draw.cpp index 7c582b25a0..2d1ecb9e2a 100644 --- a/doomsday/apps/client/src/gl/dgl_draw.cpp +++ b/doomsday/apps/client/src/gl/dgl_draw.cpp @@ -39,6 +39,8 @@ using namespace de; uint constexpr MAX_TEX_COORDS = 2; +static unsigned s_drawCallCount = 0; + struct DGLDrawState { struct Vertex @@ -335,7 +337,7 @@ struct DGLDrawState // Upload the vertex data. GLData::DrawBuffer &buf = nextBuffer(); - buf.arrayData.setData(&vertices[0], sizeof(Vertex) * vertices.size(), gl::Stream); + buf.arrayData.setData(&vertices[0], sizeof(Vertex) * vertices.size(), gl::Dynamic); #if defined (DENG_HAVE_VAOS) GL.glBindVertexArray(buf.vertexArray); @@ -428,7 +430,7 @@ struct DGLDrawState gl->shader.beginUse(); { glBindArrays(); - LIBGUI_GL.glDrawArrays(glPrimitive(), 0, numVertices()); + LIBGUI_GL.glDrawArrays(glPrimitive(), 0, numVertices()); ++s_drawCallCount; LIBGUI_ASSERT_GL_OK(); glUnbindArrays(); } @@ -445,6 +447,9 @@ void DGL_Shutdown() void DGL_BeginFrame() { + qDebug() << "draw calls:" << s_drawCallCount; + s_drawCallCount = 0; + if (dglDraw.gl) { // Reuse buffers every frame. diff --git a/doomsday/apps/client/src/resource/clientmaterial.cpp b/doomsday/apps/client/src/resource/clientmaterial.cpp index 72d897d51b..127fd644ac 100644 --- a/doomsday/apps/client/src/resource/clientmaterial.cpp +++ b/doomsday/apps/client/src/resource/clientmaterial.cpp @@ -153,6 +153,22 @@ ClientMaterial::ClientMaterial(world::MaterialManifest &manifest) ClientMaterial::~ClientMaterial() {} +bool ClientMaterial::isAnimated() const +{ + if (Material::isAnimated()) + { + return true; + } + for (const auto &decor : d->decorations) + { + if (decor->isAnimated()) + { + return true; + } + } + return false; +} + AudioEnvironmentId ClientMaterial::audioEnvironment() const { return (isDrawable()? d->audioEnvironment : AE_NONE); @@ -168,7 +184,7 @@ int ClientMaterial::decorationCount() const return d->decorations.count(); } -LoopResult ClientMaterial::forAllDecorations(std::function func) const +LoopResult ClientMaterial::forAllDecorations(const std::function &func) const { for (Decoration *decor : d.getConst()->decorations) { @@ -214,7 +230,7 @@ MaterialAnimator &ClientMaterial::getAnimator(MaterialVariantSpec const &spec) return *d->findAnimator(spec, true/*create*/); } -LoopResult ClientMaterial::forAllAnimators(std::function func) const +LoopResult ClientMaterial::forAllAnimators(const std::function &func) const { for (MaterialAnimator *animator : d.getConst()->animators) { diff --git a/doomsday/apps/client/src/world/base/clientserverworld.cpp b/doomsday/apps/client/src/world/base/clientserverworld.cpp index a179e31e46..3b2935f425 100644 --- a/doomsday/apps/client/src/world/base/clientserverworld.cpp +++ b/doomsday/apps/client/src/world/base/clientserverworld.cpp @@ -644,7 +644,8 @@ DENG2_PIMPL(ClientServerWorld) // Rewind/restart material animators. /// @todo Only rewind animators responsible for map-surface contexts. - world::Materials::get().forAllMaterials([] (world::Material &material) + world::Materials::get().updateLookup(); + world::Materials::get().forAnimatedMaterials([] (world::Material &material) { return material.as().forAllAnimators([] (MaterialAnimator &animator) { diff --git a/doomsday/apps/client/src/world/base/p_ticker.cpp b/doomsday/apps/client/src/world/base/p_ticker.cpp index fba5f58685..fff29a1c11 100644 --- a/doomsday/apps/client/src/world/base/p_ticker.cpp +++ b/doomsday/apps/client/src/world/base/p_ticker.cpp @@ -34,7 +34,7 @@ void P_Ticker(timespan_t elapsed) /// @todo Each context animator should be driven by a more relevant ticker, rather /// than using the playsim's ticker for all contexts. (e.g., animators for the UI /// context should be driven separately). - world::Materials::get().forAllMaterials([&elapsed] (world::Material &material) + world::Materials::get().forAnimatedMaterials([&elapsed] (world::Material &material) { auto &mat = material.as(); for (int i = mat.animatorCount() - 1; i >= 0; --i) diff --git a/doomsday/apps/client/src/world/base/sector.cpp b/doomsday/apps/client/src/world/base/sector.cpp index 8564e33fb7..85369d2673 100644 --- a/doomsday/apps/client/src/world/base/sector.cpp +++ b/doomsday/apps/client/src/world/base/sector.cpp @@ -349,7 +349,7 @@ dint Sector::subsectorCount() const return d->subsectors.count(); } -LoopResult Sector::forAllSubsectors(std::function callback) const +LoopResult Sector::forAllSubsectors(const std::function &callback) const { for (Subsector *subsec : d->subsectors) { diff --git a/doomsday/apps/libdoomsday/include/doomsday/world/material.h b/doomsday/apps/libdoomsday/include/doomsday/world/material.h index efcd67325e..07e08d7f49 100644 --- a/doomsday/apps/libdoomsday/include/doomsday/world/material.h +++ b/doomsday/apps/libdoomsday/include/doomsday/world/material.h @@ -111,6 +111,8 @@ class LIBDOOMSDAY_PUBLIC Material : public MapElement return (_flags & Valid) != 0; } + virtual bool isAnimated() const; + /** * Change the do-not-draw property of the material according to @a yes. */ diff --git a/doomsday/apps/libdoomsday/include/doomsday/world/materials.h b/doomsday/apps/libdoomsday/include/doomsday/world/materials.h index 0f9d124fdb..329d2d232c 100644 --- a/doomsday/apps/libdoomsday/include/doomsday/world/materials.h +++ b/doomsday/apps/libdoomsday/include/doomsday/world/materials.h @@ -193,7 +193,11 @@ class LIBDOOMSDAY_PUBLIC Materials * * @param func Callback to make for each Material. */ - de::LoopResult forAllMaterials(std::function func) const; + de::LoopResult forAllMaterials(const std::function &func) const; + + de::LoopResult forAnimatedMaterials(const std::function &func) const; + + void updateLookup(); private: DENG2_PRIVATE(d) diff --git a/doomsday/apps/libdoomsday/src/world/material.cpp b/doomsday/apps/libdoomsday/src/world/material.cpp index bd8f8f07b9..948addbf3d 100644 --- a/doomsday/apps/libdoomsday/src/world/material.cpp +++ b/doomsday/apps/libdoomsday/src/world/material.cpp @@ -222,6 +222,11 @@ void Material::setHeight(int newHeight) setDimensions(Vector2ui(width(), newHeight)); } +bool Material::isAnimated() const +{ + return hasAnimatedTextureLayers(); +} + void Material::setWidth(int newWidth) { setDimensions(Vector2ui(newWidth, height())); diff --git a/doomsday/apps/libdoomsday/src/world/materials.cpp b/doomsday/apps/libdoomsday/src/world/materials.cpp index 2fa2dd3b8c..d620cd3d99 100644 --- a/doomsday/apps/libdoomsday/src/world/materials.cpp +++ b/doomsday/apps/libdoomsday/src/world/materials.cpp @@ -23,6 +23,7 @@ #include "doomsday/resource/resources.h" #include +#include using namespace de; @@ -56,6 +57,8 @@ DENG2_PIMPL(Materials) QList materials; ///< From all schemes. int materialManifestCount = 0; ///< Total number of material manifests (in all schemes). + std::unordered_set animatedMaterialsSubset; ///< Subset of materials (not owned) that need to animate. + MaterialManifestGroups materialGroups; uint materialManifestIdMapSize = 0; @@ -158,7 +161,9 @@ DENG2_PIMPL(Materials) /// Observes Material Deletion. void materialBeingDeleted(Material const &material) { - materials.removeOne(const_cast(&material)); + Material *pMat = const_cast(&material); + materials.removeOne(pMat); + animatedMaterialsSubset.erase(pMat); } }; @@ -269,7 +274,7 @@ dint Materials::materialCount() const return d->materials.count(); } -LoopResult Materials::forAllMaterials(std::function func) const +LoopResult Materials::forAllMaterials(const std::function &func) const { for (Material *mat : d.getConst()->materials) { @@ -281,6 +286,30 @@ LoopResult Materials::forAllMaterials(std::function fun return LoopContinue; } +LoopResult Materials::forAnimatedMaterials(const std::function &func) const +{ + for (Material *mat : d.getConst()->animatedMaterialsSubset) + { + if (auto result = func(*mat)) + { + return result; + } + } + return LoopContinue; +} + +void Materials::updateLookup() +{ + d->animatedMaterialsSubset.clear(); + for (auto *mat : d->materials) + { + if (mat->isAnimated()) + { + d->animatedMaterialsSubset.insert(mat); + } + } +} + Materials::MaterialManifestGroup &Materials::newMaterialGroup() { // Allocating one by one is inefficient, but it doesn't really matter.