Skip to content

Commit

Permalink
#5893: The RenderableSurfaceCollection is now notified when any of th…
Browse files Browse the repository at this point in the history
…e contained surfaces are changing their bounds.
  • Loading branch information
codereader committed Jan 27, 2022
1 parent 6bc219f commit 2e61d96
Show file tree
Hide file tree
Showing 10 changed files with 92 additions and 10 deletions.
5 changes: 5 additions & 0 deletions include/isurfacerenderer.h
@@ -1,5 +1,6 @@
#pragma once

#include <sigc++/signal.h>
#include <vector>
#include <limits>
#include <cstdint>
Expand Down Expand Up @@ -33,6 +34,10 @@ class IRenderableSurface

// 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
15 changes: 15 additions & 0 deletions libs/render/RenderableSurface.h
Expand Up @@ -24,6 +24,8 @@ class RenderableSurface :
using ShaderMapping = std::map<ShaderPtr, ISurfaceRenderer::Slot>;
ShaderMapping _shaders;

sigc::signal<void> _sigBoundsChanged;

protected:
RenderableSurface()
{}
Expand Down Expand Up @@ -52,12 +54,20 @@ class RenderableSurface :
}

// Notifies all the attached shaders that the surface geometry changed
// Also fires the bounds changed signal
void queueUpdate()
{
for (auto& [shader, slot] : _shaders)
{
shader->updateSurface(slot);
}

boundsChanged();
}

void boundsChanged()
{
_sigBoundsChanged.emit();
}

// Removes the surface from all shaders
Expand All @@ -78,6 +88,11 @@ class RenderableSurface :
shader->renderSurface(slot);
}

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

private:
void detachFromShader(const ShaderMapping::iterator& iter)
{
Expand Down
2 changes: 1 addition & 1 deletion libs/scene/Node.h
Expand Up @@ -150,7 +150,7 @@ class Node: public LitObject, public virtual INode, public std::enable_shared_fr

const Matrix4& localToWorld() const override;

void transformChangedLocal() override;
virtual void transformChangedLocal() override;

void transformChanged() override;

Expand Down
48 changes: 39 additions & 9 deletions radiantcore/entity/RenderableSurfaceCollection.h
@@ -1,18 +1,23 @@
#pragma once

#include <set>
#include <map>
#include <sigc++/connection.h>
#include <sigc++/trackable.h>
#include <sigc++/functors/mem_fun.h>
#include "irender.h"
#include "itextstream.h"

namespace entity
{

class RenderableSurfaceCollection
class RenderableSurfaceCollection :
public sigc::trackable
{
private:
AABB _collectionBounds;
bool _collectionBoundsNeedUpdate;

std::set<render::IRenderableSurface::Ptr> _surfaces;
std::map<render::IRenderableSurface::Ptr, sigc::connection> _surfaces;

public:
RenderableSurfaceCollection() :
Expand All @@ -21,13 +26,34 @@ class RenderableSurfaceCollection

void addSurface(const render::IRenderableSurface::Ptr& surface)
{
_surfaces.insert(surface);
sigc::connection subscription = surface->signal_boundsChanged().connect(
sigc::mem_fun(*this, &RenderableSurfaceCollection::onSurfaceBoundsChanged));

if (!_surfaces.try_emplace(surface, subscription).second)
{
// We've already been subscribed to this one
subscription.disconnect();
rWarning() << "Renderable surface has already been attached to entity" << std::endl;
return;
}

_collectionBoundsNeedUpdate = true;
}

void removeSurface(const render::IRenderableSurface::Ptr& surface)
{
_surfaces.erase(surface);
auto mapping = _surfaces.find(surface);

if (mapping != _surfaces.end())
{
mapping->second.disconnect();
_surfaces.erase(mapping);
}
else
{
rWarning() << "Renderable surface has not been attached to entity" << std::endl;
}

_collectionBoundsNeedUpdate = true;
}

Expand All @@ -39,10 +65,9 @@ class RenderableSurfaceCollection
ensureBoundsUpToDate();

// If the whole collection doesn't intersect, quit early
// TODO: bounds not updated when surface changes
//if (!_collectionBounds.intersects(bounds)) return;
if (!_collectionBounds.intersects(bounds)) return;

for (const auto& surface : _surfaces)
for (const auto& [surface, _] : _surfaces)
{
auto orientedBounds = AABB::createFromOrientedAABBSafe(
surface->getSurfaceBounds(), surface->getSurfaceTransform());
Expand All @@ -55,6 +80,11 @@ class RenderableSurfaceCollection
}

private:
void onSurfaceBoundsChanged()
{
_collectionBoundsNeedUpdate = true;
}

void ensureBoundsUpToDate()
{
if (!_collectionBoundsNeedUpdate) return;
Expand All @@ -63,7 +93,7 @@ class RenderableSurfaceCollection

_collectionBounds = AABB();

for (const auto& surface : _surfaces)
for (const auto& [surface, _] : _surfaces)
{
_collectionBounds.includeAABB(AABB::createFromOrientedAABBSafe(
surface->getSurfaceBounds(), surface->getSurfaceTransform()));
Expand Down
7 changes: 7 additions & 0 deletions radiantcore/model/NullModelNode.cpp
Expand Up @@ -125,6 +125,13 @@ void NullModelNode::onRemoveFromScene(scene::IMapRootNode& root)
_renderableBox.detach();
}

void NullModelNode::transformChangedLocal()
{
Node::transformChangedLocal();

_renderableBox.boundsChanged();
}

void NullModelNode::onVisibilityChanged(bool isVisibleNow)
{
Node::onVisibilityChanged(isVisibleNow);
Expand Down
1 change: 1 addition & 0 deletions radiantcore/model/NullModelNode.h
Expand Up @@ -57,6 +57,7 @@ class NullModelNode final :
const AABB& localAABB() const override;

void onRemoveFromScene(scene::IMapRootNode& root) override;
void transformChangedLocal() override;

protected:
void onVisibilityChanged(bool isVisibleNow) override;
Expand Down
10 changes: 10 additions & 0 deletions radiantcore/model/StaticModelNode.cpp
Expand Up @@ -186,6 +186,16 @@ bool StaticModelNode::getIntersection(const Ray& ray, Vector3& intersection)
return _model->getIntersection(ray, intersection, localToWorld());
}

void StaticModelNode::transformChangedLocal()
{
Node::transformChangedLocal();

for (auto& surface : _renderableSurfaces)
{
surface->boundsChanged();
}
}

// Skin changed notify
void StaticModelNode::skinChanged(const std::string& newSkinName)
{
Expand Down
2 changes: 2 additions & 0 deletions radiantcore/model/StaticModelNode.h
Expand Up @@ -95,6 +95,8 @@ class StaticModelNode final :
// Traceable implementation
bool getIntersection(const Ray& ray, Vector3& intersection) override;

void transformChangedLocal() override;

protected:
void _onTransformationChanged() override;
void _applyTransformation() override;
Expand Down
10 changes: 10 additions & 0 deletions radiantcore/model/md5/MD5ModelNode.cpp
Expand Up @@ -212,4 +212,14 @@ void MD5ModelNode::onModelAnimationUpdated()
}
}

void MD5ModelNode::transformChangedLocal()
{
Node::transformChangedLocal();

for (auto& surface : _renderableSurfaces)
{
surface->boundsChanged();
}
}

} // namespace md5
2 changes: 2 additions & 0 deletions radiantcore/model/md5/MD5ModelNode.h
Expand Up @@ -81,6 +81,8 @@ class MD5ModelNode :
virtual std::string getSkin() const override;
void skinChanged(const std::string& newSkinName) override;

void transformChangedLocal() override;

protected:
void onVisibilityChanged(bool isVisibleNow) override;

Expand Down

0 comments on commit 2e61d96

Please sign in to comment.