Skip to content

Commit

Permalink
Materials|World: More efficient animating of materials
Browse files Browse the repository at this point in the history
Only animate materials that are known to have something to animate.
  • Loading branch information
skyjake committed Nov 25, 2018
1 parent e949139 commit 3a6b398
Show file tree
Hide file tree
Showing 15 changed files with 93 additions and 27 deletions.
4 changes: 2 additions & 2 deletions doomsday/apps/client/include/client/clientsubsector.h
Expand Up @@ -92,8 +92,8 @@ class ClientSubsector : public Subsector, public ILightSource
*
* @param callback Function to call for each edge loop.
*/
de::LoopResult forAllEdgeLoops(std::function<de::LoopResult (ClEdgeLoop &)> func);
de::LoopResult forAllEdgeLoops(std::function<de::LoopResult (ClEdgeLoop const &)> func) const;
de::LoopResult forAllEdgeLoops(const std::function<de::LoopResult (ClEdgeLoop &)> &func);
de::LoopResult forAllEdgeLoops(const std::function<de::LoopResult (ClEdgeLoop const &)> &func) const;

//- Audio environment -------------------------------------------------------------------

Expand Down
2 changes: 1 addition & 1 deletion doomsday/apps/client/include/clientapp.h
Expand Up @@ -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<de::LoopResult (ClientPlayer &)> func);
static de::LoopResult forLocalPlayers(const std::function<de::LoopResult (ClientPlayer &)> &func);

static ClientApp & app();
static ConfigProfiles & logSettings();
Expand Down
8 changes: 5 additions & 3 deletions doomsday/apps/client/include/resource/clientmaterial.h
Expand Up @@ -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.
Expand Down Expand Up @@ -200,7 +202,7 @@ class ClientMaterial : public world::Material
*
* @param func Callback to make for each Decoration.
*/
de::LoopResult forAllDecorations(std::function<de::LoopResult (Decoration &)> func) const;
de::LoopResult forAllDecorations(const std::function<de::LoopResult (Decoration &)> &func) const;

/**
* Add a new (light) decoration to the material.
Expand Down Expand Up @@ -242,7 +244,7 @@ class ClientMaterial : public world::Material
*
* @param func Callback to make for each Animator.
*/
de::LoopResult forAllAnimators(std::function<de::LoopResult (MaterialAnimator &)> func) const;
de::LoopResult forAllAnimators(const std::function<de::LoopResult (MaterialAnimator &)> &func) const;

/**
* Destroy all the MaterialAnimators for the material.
Expand Down
2 changes: 1 addition & 1 deletion doomsday/apps/client/include/world/sector.h
Expand Up @@ -238,7 +238,7 @@ class Sector : public world::MapElement
*
* @param callback Function to call for each Subsector.
*/
de::LoopResult forAllSubsectors(std::function<de::LoopResult (world::Subsector &)> callback) const;
de::LoopResult forAllSubsectors(const std::function<de::LoopResult (world::Subsector &)> &callback) const;

/**
* Generate a new Subsector from the given set of map @a subspaces.
Expand Down
20 changes: 11 additions & 9 deletions doomsday/apps/client/src/client/clientsubsector.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -1471,7 +1471,7 @@ dint ClientSubsector::edgeLoopCount() const
return (bool(d->boundaryData->outerLoop) ? 1 : 0) + d->boundaryData->innerLoops.count();
}

LoopResult ClientSubsector::forAllEdgeLoops(std::function<LoopResult (ClEdgeLoop &)> func)
LoopResult ClientSubsector::forAllEdgeLoops(const std::function<LoopResult (ClEdgeLoop &)> &func)
{
d->initBoundaryDataIfNeeded();
DENG2_ASSERT(bool(d->boundaryData->outerLoop));
Expand All @@ -1487,7 +1487,7 @@ LoopResult ClientSubsector::forAllEdgeLoops(std::function<LoopResult (ClEdgeLoop
return LoopContinue;
}

LoopResult ClientSubsector::forAllEdgeLoops(std::function<LoopResult (ClEdgeLoop const &)> func) const
LoopResult ClientSubsector::forAllEdgeLoops(const std::function<LoopResult (ClEdgeLoop const &)> &func) const
{
d->initBoundaryDataIfNeeded();
DENG2_ASSERT(bool(d->boundaryData->outerLoop));
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion doomsday/apps/client/src/clientapp.cpp
Expand Up @@ -817,7 +817,7 @@ ClientPlayer &ClientApp::player(int console) // static
return DoomsdayApp::players().at(console).as<ClientPlayer>();
}

LoopResult ClientApp::forLocalPlayers(std::function<LoopResult (ClientPlayer &)> func) // static
LoopResult ClientApp::forLocalPlayers(const std::function<LoopResult (ClientPlayer &)> &func) // static
{
auto const &players = DoomsdayApp::players();
for (int i = 0; i < players.count(); ++i)
Expand Down
9 changes: 7 additions & 2 deletions doomsday/apps/client/src/gl/dgl_draw.cpp
Expand Up @@ -39,6 +39,8 @@ using namespace de;

uint constexpr MAX_TEX_COORDS = 2;

static unsigned s_drawCallCount = 0;

struct DGLDrawState
{
struct Vertex
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
}
Expand All @@ -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.
Expand Down
20 changes: 18 additions & 2 deletions doomsday/apps/client/src/resource/clientmaterial.cpp
Expand Up @@ -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);
Expand All @@ -168,7 +184,7 @@ int ClientMaterial::decorationCount() const
return d->decorations.count();
}

LoopResult ClientMaterial::forAllDecorations(std::function<LoopResult (Decoration &)> func) const
LoopResult ClientMaterial::forAllDecorations(const std::function<LoopResult (Decoration &)> &func) const
{
for (Decoration *decor : d.getConst()->decorations)
{
Expand Down Expand Up @@ -214,7 +230,7 @@ MaterialAnimator &ClientMaterial::getAnimator(MaterialVariantSpec const &spec)
return *d->findAnimator(spec, true/*create*/);
}

LoopResult ClientMaterial::forAllAnimators(std::function<LoopResult (MaterialAnimator &)> func) const
LoopResult ClientMaterial::forAllAnimators(const std::function<LoopResult (MaterialAnimator &)> &func) const
{
for (MaterialAnimator *animator : d.getConst()->animators)
{
Expand Down
3 changes: 2 additions & 1 deletion doomsday/apps/client/src/world/base/clientserverworld.cpp
Expand Up @@ -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<ClientMaterial>().forAllAnimators([] (MaterialAnimator &animator)
{
Expand Down
2 changes: 1 addition & 1 deletion doomsday/apps/client/src/world/base/p_ticker.cpp
Expand Up @@ -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<ClientMaterial>();
for (int i = mat.animatorCount() - 1; i >= 0; --i)
Expand Down
2 changes: 1 addition & 1 deletion doomsday/apps/client/src/world/base/sector.cpp
Expand Up @@ -349,7 +349,7 @@ dint Sector::subsectorCount() const
return d->subsectors.count();
}

LoopResult Sector::forAllSubsectors(std::function<LoopResult(Subsector &)> callback) const
LoopResult Sector::forAllSubsectors(const std::function<LoopResult(Subsector &)> &callback) const
{
for (Subsector *subsec : d->subsectors)
{
Expand Down
2 changes: 2 additions & 0 deletions doomsday/apps/libdoomsday/include/doomsday/world/material.h
Expand Up @@ -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.
*/
Expand Down
6 changes: 5 additions & 1 deletion doomsday/apps/libdoomsday/include/doomsday/world/materials.h
Expand Up @@ -193,7 +193,11 @@ class LIBDOOMSDAY_PUBLIC Materials
*
* @param func Callback to make for each Material.
*/
de::LoopResult forAllMaterials(std::function<de::LoopResult (Material &)> func) const;
de::LoopResult forAllMaterials(const std::function<de::LoopResult (Material &)> &func) const;

de::LoopResult forAnimatedMaterials(const std::function<de::LoopResult (Material &)> &func) const;

void updateLookup();

private:
DENG2_PRIVATE(d)
Expand Down
5 changes: 5 additions & 0 deletions doomsday/apps/libdoomsday/src/world/material.cpp
Expand Up @@ -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()));
Expand Down
33 changes: 31 additions & 2 deletions doomsday/apps/libdoomsday/src/world/materials.cpp
Expand Up @@ -23,6 +23,7 @@
#include "doomsday/resource/resources.h"

#include <de/memory.h>
#include <unordered_set>

using namespace de;

Expand Down Expand Up @@ -56,6 +57,8 @@ DENG2_PIMPL(Materials)
QList<Material *> materials; ///< From all schemes.
int materialManifestCount = 0; ///< Total number of material manifests (in all schemes).

std::unordered_set<Material *> animatedMaterialsSubset; ///< Subset of materials (not owned) that need to animate.

MaterialManifestGroups materialGroups;

uint materialManifestIdMapSize = 0;
Expand Down Expand Up @@ -158,7 +161,9 @@ DENG2_PIMPL(Materials)
/// Observes Material Deletion.
void materialBeingDeleted(Material const &material)
{
materials.removeOne(const_cast<Material *>(&material));
Material *pMat = const_cast<Material *>(&material);
materials.removeOne(pMat);
animatedMaterialsSubset.erase(pMat);
}
};

Expand Down Expand Up @@ -269,7 +274,7 @@ dint Materials::materialCount() const
return d->materials.count();
}

LoopResult Materials::forAllMaterials(std::function<LoopResult (Material &)> func) const
LoopResult Materials::forAllMaterials(const std::function<LoopResult (Material &)> &func) const
{
for (Material *mat : d.getConst()->materials)
{
Expand All @@ -281,6 +286,30 @@ LoopResult Materials::forAllMaterials(std::function<LoopResult (Material &)> fun
return LoopContinue;
}

LoopResult Materials::forAnimatedMaterials(const std::function<LoopResult (Material &)> &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.
Expand Down

0 comments on commit 3a6b398

Please sign in to comment.