Skip to content

Commit

Permalink
#5893: Extend the rendersystem interface to support entity registrati…
Browse files Browse the repository at this point in the history
…on, deregistration and enumeration. Add a couple of unit tests.
  • Loading branch information
codereader committed Jan 26, 2022
1 parent a320e51 commit c69690b
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 0 deletions.
18 changes: 18 additions & 0 deletions include/irender.h
Expand Up @@ -658,6 +658,24 @@ class RenderSystem
*/
virtual ShaderPtr capture(ColourShaderType type, const Colour4& colour) = 0;

/**
* Register the given entity to be considered during rendering.
* This returns an ID which can be used to deregister this entity later.
*/
virtual std::size_t addEntity(const IRenderEntityPtr& renderEntity) = 0;

/**
* Detaches this entity from this rendersystem, it won't be
* affected by any rendering after this call.
*/
virtual void removeEntity(std::size_t renderEntityId) = 0;

/**
* Enumerates all known render entities in this system, invoking
* the functor for each of them.
*/
virtual void foreachEntity(const std::function<void(const IRenderEntityPtr&)>& functor) = 0;

/**
* \brief
* Main render method.
Expand Down
15 changes: 15 additions & 0 deletions radiantcore/rendersystem/OpenGLRenderSystem.cpp
Expand Up @@ -501,6 +501,21 @@ void OpenGLRenderSystem::shutdownModule()
_materialDefsUnloaded.disconnect();
}

std::size_t OpenGLRenderSystem::addEntity(const IRenderEntityPtr& renderEntity)
{
return 0;
}

void OpenGLRenderSystem::removeEntity(std::size_t renderEntityId)
{

}

void OpenGLRenderSystem::foreachEntity(const std::function<void(const IRenderEntityPtr&)>& functor)
{

}

// Define the static OpenGLRenderSystem module
module::StaticModule<OpenGLRenderSystem> openGLRenderSystemModule;

Expand Down
4 changes: 4 additions & 0 deletions radiantcore/rendersystem/OpenGLRenderSystem.h
Expand Up @@ -91,6 +91,10 @@ class OpenGLRenderSystem final
Renderables m_renderables;
mutable bool m_traverseRenderablesMutex;

std::size_t addEntity(const IRenderEntityPtr& renderEntity) override;
void removeEntity(std::size_t renderEntityId) override;
void foreachEntity(const std::function<void(const IRenderEntityPtr&)>& functor) override;

/* OpenGLStateManager implementation */
void insertSortedState(const OpenGLStates::value_type& val) override;
void eraseSortedState(const OpenGLStates::key_type& key) override;
Expand Down
87 changes: 87 additions & 0 deletions test/Renderer.cpp
Expand Up @@ -2,13 +2,16 @@

#include "ieclass.h"
#include "ientity.h"
#include "irender.h"
#include "ilightnode.h"
#include "math/Matrix4.h"
#include "scenelib.h"

namespace test
{

using RendererTest = RadiantTest;
using RenderSystemTest = RadiantTest;

IEntityNodePtr createByClassName(const std::string& className)
{
Expand Down Expand Up @@ -257,4 +260,88 @@ TEST_F(RendererTest, RotatedProjectedLight)
EXPECT_EQ(mat * V4(16, 0, 0, 1), V4(0.5, 0.5, 1, 1));
}

namespace
{

std::size_t getEntityCount(RenderSystemPtr& renderSystem)
{
std::size_t count = 0;

renderSystem->foreachEntity([&](const IRenderEntityPtr&)
{
++count;
});

return count;
}

}

// Ensure that any entity in the scene is connected to the rendersystem
TEST_F(RenderSystemTest, EntityRegistration)
{
auto rootNode = GlobalMapModule().getRoot();
auto renderSystem = rootNode->getRenderSystem();

EXPECT_TRUE(renderSystem);
EXPECT_EQ(getEntityCount(renderSystem), 0) << "Rendersystem should be pristine";

auto entity = createByClassName("func_static");
scene::addNodeToContainer(entity, rootNode);

EXPECT_EQ(getEntityCount(renderSystem), 1) << "Rendersystem should contain one entity now";

scene::removeNodeFromParent(entity);
EXPECT_EQ(getEntityCount(renderSystem), 0) << "Rendersystem should be empty again";
}

TEST_F(RenderSystemTest, DuplicateEntityRegistration)
{
auto rootNode = GlobalMapModule().getRoot();
auto renderSystem = rootNode->getRenderSystem();

auto entity = createByClassName("func_static");
scene::addNodeToContainer(entity, rootNode);
EXPECT_EQ(getEntityCount(renderSystem), 1) << "Rendersystem should contain one entity now";

// Manually try to register the same entity twice
EXPECT_THROW(renderSystem->addEntity(entity), std::logic_error);
}

TEST_F(RenderSystemTest, DuplicateEntityDeregistration)
{
auto rootNode = GlobalMapModule().getRoot();
auto renderSystem = rootNode->getRenderSystem();

auto entity = createByClassName("func_static");

auto handle = renderSystem->addEntity(entity);
EXPECT_EQ(getEntityCount(renderSystem), 1) << "Rendersystem should contain one entity now";

// Manually try to remove the entity by this handle
renderSystem->removeEntity(handle);
EXPECT_EQ(getEntityCount(renderSystem), 0) << "Rendersystem should be empty now";

// Same call again should trigger an exception
EXPECT_THROW(renderSystem->removeEntity(handle), std::logic_error);
}

TEST_F(RenderSystemTest, EntityEnumeration)
{
auto rootNode = GlobalMapModule().getRoot();
auto renderSystem = rootNode->getRenderSystem();

auto entity = createByClassName("func_static");
scene::addNodeToContainer(entity, rootNode);

std::vector<IRenderEntityPtr> visitedEntities;
renderSystem->foreachEntity([&](const IRenderEntityPtr& entity)
{
visitedEntities.push_back(entity);
});

EXPECT_EQ(visitedEntities.size(), 1) << "We should've hit one entity";
EXPECT_EQ(visitedEntities.front(), entity) << "We should've hit our known entity";
}

}

0 comments on commit c69690b

Please sign in to comment.