Navigation Menu

Skip to content

Commit

Permalink
#5893: Introduce a new interface which allows a more general kind of …
Browse files Browse the repository at this point in the history
…renderables to be attached to IRenderEntities.

The common RenderableGeometry type now supports attaching itself to a render entity to be considered during lighting mode rendering.
  • Loading branch information
codereader committed Jan 29, 2022
1 parent 4e9c0f3 commit 50020cd
Show file tree
Hide file tree
Showing 21 changed files with 286 additions and 127 deletions.
14 changes: 7 additions & 7 deletions include/irender.h
Expand Up @@ -171,23 +171,23 @@ class IRenderEntity
virtual Vector4 getEntityColour() const = 0;

/**
* Associates the given surface with this entity and the given shader.
* Associates the given object with this entity and the given shader.
* It will be processed during the following lighting mode rendering passes.
*/
virtual void addSurface(const render::IRenderableSurface::Ptr& surface, const ShaderPtr& shader) = 0;
virtual void addRenderable(const render::IRenderableObject::Ptr& object, const ShaderPtr& shader) = 0;

/**
* Removes the surface from this entity.
* Removes the object from this entity.
*/
virtual void removeSurface(const render::IRenderableSurface::Ptr& surface) = 0;
virtual void removeRenderable(const render::IRenderableObject::Ptr& object) = 0;

using SurfaceVisitFunction = std::function<void(const render::IRenderableSurface::Ptr&, const ShaderPtr&)>;
using ObjectVisitFunction = std::function<void(const render::IRenderableObject::Ptr&, const ShaderPtr&)>;

/**
* Enumerate all entity surfaces (partially) intersecting with the given bounds.
* Enumerate all entity object (partially) intersecting with the given bounds.
* The bounds are specified in world coordinates.
*/
virtual void foreachSurfaceTouchingBounds(const AABB& bounds, const SurfaceVisitFunction& functor) = 0;
virtual void foreachRenderableTouchingBounds(const AABB& bounds, const ObjectVisitFunction& functor) = 0;
};
typedef std::shared_ptr<IRenderEntity> IRenderEntityPtr;
typedef std::weak_ptr<IRenderEntity> IRenderEntityWeakPtr;
Expand Down
32 changes: 32 additions & 0 deletions include/irenderableobject.h
@@ -0,0 +1,32 @@
#pragma once

#include <memory>
#include <sigc++/signal.h>
#include "math/AABB.h"
#include "math/Matrix4.h"

namespace render
{

class IRenderableObject
{
public:
using Ptr = std::shared_ptr<IRenderableObject>;

virtual ~IRenderableObject() {}

// Returns true if this object is not empty and should be rendered
virtual bool isVisible() = 0;

// The model view matrix used to render this object
virtual const Matrix4& getObjectTransform() = 0;

// The object bounds in local coordinates
virtual const AABB& getObjectBounds() = 0;

// Emitted when the object bounds have changed,
// because it has been either moved or resized.
virtual sigc::signal<void>& signal_boundsChanged() = 0;
};

}
16 changes: 4 additions & 12 deletions include/isurfacerenderer.h
@@ -1,6 +1,7 @@
#pragma once

#include <sigc++/signal.h>
#include "irenderableobject.h"

#include <vector>
#include <limits>
#include <cstdint>
Expand All @@ -16,7 +17,8 @@ namespace render
* The ISurfaceRenderer will reacquire the transformation matrix each frame,
* whereas the vertices and indices won't be requested every time.
*/
class IRenderableSurface
class IRenderableSurface :
public IRenderableObject
{
public:
using Ptr = std::shared_ptr<IRenderableSurface>;
Expand All @@ -28,16 +30,6 @@ class IRenderableSurface

// Returns the indices to render the triangle primitives
virtual const std::vector<unsigned int>& getIndices() = 0;

// The model view matrix used to render this surface
virtual const Matrix4& getSurfaceTransform() = 0;

// The surface bounds in local coordinates
virtual const AABB& getSurfaceBounds() = 0;

// Emitted when the surface bounds have changed,
// because it has been either moved or resized.
virtual sigc::signal<void>& signal_boundsChanged() = 0;
};

/**
Expand Down
9 changes: 7 additions & 2 deletions libs/render/RenderableBox.h
Expand Up @@ -225,6 +225,11 @@ class RenderableBoxSurface final :
_indices = detail::generateTriangleBoxIndices();
}

bool isVisible() override
{
return !_indices.empty();
}

const std::vector<ArbitraryMeshVertex>& getVertices() override
{
return _vertices;
Expand All @@ -235,12 +240,12 @@ class RenderableBoxSurface final :
return _indices;
}

const Matrix4& getSurfaceTransform() override
const Matrix4& getObjectTransform() override
{
return _orientation;
}

const AABB& getSurfaceBounds() override
const AABB& getObjectBounds() override
{
return _bounds;
}
Expand Down
114 changes: 113 additions & 1 deletion libs/render/RenderableGeometry.h
Expand Up @@ -2,6 +2,8 @@

#include <vector>
#include "igeometryrenderer.h"
#include "isurfacerenderer.h"
#include "irenderableobject.h"
#include "irender.h"

namespace render
Expand All @@ -25,11 +27,59 @@ class RenderableGeometry :
std::size_t _lastVertexSize; // To detect size changes when updating geometry
std::size_t _lastIndexSize; // To detect size changes when updating geometry

class RenderAdapter final :
public IRenderableObject
{
private:
RenderableGeometry& _owner;
AABB _bounds;
sigc::signal<void> _sigBoundsChanged;

public:
RenderAdapter(RenderableGeometry& owner) :
_owner(owner)
{}

bool isVisible() override
{
return _owner._surfaceSlot != IGeometryRenderer::InvalidSlot;
}

const Matrix4& getObjectTransform() override
{
static Matrix4 _identity = Matrix4::getIdentity();
return _identity;
}

const AABB& getObjectBounds() override
{
return _bounds;
}

sigc::signal<void>& signal_boundsChanged() override
{
return _sigBoundsChanged;
}

void setBounds(const AABB& bounds)
{
_bounds = bounds;
signal_boundsChanged().emit();
}
};

// Adapater suitable to be attached to an IRenderEntity
std::shared_ptr<RenderAdapter> _renderAdapter;

// The render entity the adapter is attached to
IRenderEntity* _renderEntity;

protected:
RenderableGeometry() :
_surfaceSlot(IGeometryRenderer::InvalidSlot),
_lastVertexSize(0),
_lastIndexSize(0)
_lastIndexSize(0),
_renderEntity(nullptr)
{}

public:
Expand Down Expand Up @@ -67,6 +117,9 @@ class RenderableGeometry :
// Removes the geometry and clears the shader reference
void clear()
{
// Detach from the render entity when being cleared
detachFromEntity();

removeGeometry();

_shader.reset();
Expand All @@ -81,6 +134,52 @@ class RenderableGeometry :
}
}

// Attach this geometry to the given render entity.
// This call is only valid if this Geometry instance has been attached to a shader
// Does nothing if already attached to the given render entity.
void attachToEntity(IRenderEntity* entity)
{
if (_renderEntity == entity) return; // nothing to do

if (!_shader)
{
throw std::logic_error("Cannot attach geometry without any shader");
}

if (_renderEntity && entity != _renderEntity)
{
detachFromEntity();
}

_renderEntity = entity;
_renderEntity->addRenderable(getRenderAdapter(), _shader);
}

void detachFromEntity()
{
if (_renderEntity)
{
_renderEntity->removeRenderable(_renderAdapter);
_renderEntity = nullptr;
}
}

/**
* Returns the adapter class suitable to attach this geometry as surface to a render entity
* The surface will have an identity transform (all vertices specified in world coords).
* This adapter will be valid as long as this geometry is attached to the IGeometryRenderer,
* otherwise no access to the stored vertices/indices is possible.
*/
const IRenderableObject::Ptr& getRenderAdapter()
{
if (!_renderAdapter)
{
_renderAdapter = std::make_shared<RenderAdapter>(*this);
}

return _renderAdapter;
}

protected:
// Removes the geometry from the attached shader. Does nothing if no geometry has been added.
void removeGeometry()
Expand Down Expand Up @@ -122,6 +221,19 @@ class RenderableGeometry :
{
_shader->updateGeometry(_surfaceSlot, vertices, indices);
}

// Fire the bounds changed signal (after submitting the changed vertices)
if (_renderAdapter)
{
AABB bounds;

for (const auto& vertex : vertices)
{
bounds.includePoint(vertex.vertex);
}

_renderAdapter->setBounds(bounds);
}
}
};

Expand Down
14 changes: 7 additions & 7 deletions radiantcore/entity/EntityNode.cpp
Expand Up @@ -200,20 +200,20 @@ const Vector3& EntityNode::getDirection() const
return _direction;
}

void EntityNode::addSurface(const render::IRenderableSurface::Ptr& surface, const ShaderPtr& shader)
void EntityNode::addRenderable(const render::IRenderableObject::Ptr& object, const ShaderPtr& shader)
{
_renderSurfaces.addSurface(surface, shader);
_renderObjects.addRenderable(object, shader);
}

void EntityNode::removeSurface(const render::IRenderableSurface::Ptr& surface)
void EntityNode::removeRenderable(const render::IRenderableObject::Ptr& object)
{
_renderSurfaces.removeSurface(surface);
_renderObjects.removeRenderable(object);
}

void EntityNode::foreachSurfaceTouchingBounds(const AABB& bounds,
const IRenderEntity::SurfaceVisitFunction& functor)
void EntityNode::foreachRenderableTouchingBounds(const AABB& bounds,
const IRenderEntity::ObjectVisitFunction& functor)
{
_renderSurfaces.foreachSurfaceTouchingBounds(bounds, functor);
_renderObjects.foreachRenderableTouchingBounds(bounds, functor);
}

std::string EntityNode::getFingerprint()
Expand Down
14 changes: 7 additions & 7 deletions radiantcore/entity/EntityNode.h
Expand Up @@ -19,7 +19,7 @@

#include "KeyObserverMap.h"
#include "RenderableEntityName.h"
#include "RenderableSurfaceCollection.h"
#include "RenderableObjectCollection.h"

namespace entity
{
Expand Down Expand Up @@ -106,9 +106,9 @@ class EntityNode :
// Whether this entity has registered itself to a render system
bool _isAttachedToRenderSystem;

// The list of surfaces attached to this IRenderEntity
// The list of renderable objects attached to this IRenderEntity
// Used in lighting render mode to enumerate surfaces by entity
RenderableSurfaceCollection _renderSurfaces;
RenderableObjectCollection _renderObjects;

protected:
// The Constructor needs the eclass
Expand All @@ -129,10 +129,10 @@ class EntityNode :
virtual float getShaderParm(int parmNum) const override;
virtual const Vector3& getDirection() const override;

virtual void addSurface(const render::IRenderableSurface::Ptr& surface, const ShaderPtr& shader) override;
virtual void removeSurface(const render::IRenderableSurface::Ptr& surface) override;
virtual void foreachSurfaceTouchingBounds(const AABB& bounds,
const SurfaceVisitFunction& functor) override;
virtual void addRenderable(const render::IRenderableObject::Ptr& object, const ShaderPtr& shader) override;
virtual void removeRenderable(const render::IRenderableObject::Ptr& object) override;
virtual void foreachRenderableTouchingBounds(const AABB& bounds,
const ObjectVisitFunction& functor) override;

// IMatrixTransform implementation
Matrix4 localToParent() const override { return _localToParent; }
Expand Down

0 comments on commit 50020cd

Please sign in to comment.