Skip to content

Commit

Permalink
#219: Add interface to IRenderableObject to be able to skip models wi…
Browse files Browse the repository at this point in the history
…th "noshadows" set on them.
  • Loading branch information
codereader committed Mar 26, 2022
1 parent 02f23ea commit b3e3ba8
Show file tree
Hide file tree
Showing 14 changed files with 70 additions and 30 deletions.
3 changes: 3 additions & 0 deletions include/irender.h
Expand Up @@ -195,6 +195,9 @@ class IRenderEntity
* The bounds are specified in world coordinates.
*/
virtual void foreachRenderableTouchingBounds(const AABB& bounds, const ObjectVisitFunction& functor) = 0;

// Returns true if this entity produces shadows when lit (i.e.returns false when the entity has "noshadows" set to 1)
virtual bool isShadowCasting() const = 0;
};
typedef std::shared_ptr<IRenderEntity> IRenderEntityPtr;
typedef std::weak_ptr<IRenderEntity> IRenderEntityWeakPtr;
Expand Down
3 changes: 3 additions & 0 deletions include/irenderableobject.h
Expand Up @@ -34,6 +34,9 @@ class IRenderableObject

// Returns the key to access the vertex data in the renderer's geometry store
virtual IGeometryStore::Slot getStorageLocation() = 0;

// Returns true if this surface produces shadows when lit
virtual bool isShadowCasting() = 0;
};

}
6 changes: 6 additions & 0 deletions libs/render/RenderableBox.h
Expand Up @@ -269,6 +269,12 @@ class RenderableBoxSurface final :
{
return _bounds;
}

bool isShadowCasting() override
{
return false;
}

private:
inline Vector3 toVector3(const Vector3f& vector)
{
Expand Down
5 changes: 5 additions & 0 deletions libs/render/RenderableGeometry.h
Expand Up @@ -91,6 +91,11 @@ class RenderableGeometry :

return _owner._shader->getGeometryStorageLocation(_owner._surfaceSlot);
}

bool isShadowCasting() override
{
return _owner._renderEntity->isShadowCasting();
}
};

// Adapater suitable to be attached to an IRenderEntity
Expand Down
20 changes: 17 additions & 3 deletions radiantcore/entity/EntityNode.cpp
Expand Up @@ -26,7 +26,8 @@ EntityNode::EntityNode(const IEntityClassPtr& eclass) :
_keyObservers(_spawnArgs),
_shaderParms(_keyObservers, _colourKey),
_direction(1,0,0),
_isAttachedToRenderSystem(false)
_isAttachedToRenderSystem(false),
_isShadowCasting(false)
{
}

Expand All @@ -48,7 +49,8 @@ EntityNode::EntityNode(const EntityNode& other) :
_keyObservers(_spawnArgs),
_shaderParms(_keyObservers, _colourKey),
_direction(1,0,0),
_isAttachedToRenderSystem(false)
_isAttachedToRenderSystem(false),
_isShadowCasting(false)
{
}

Expand Down Expand Up @@ -80,6 +82,8 @@ void EntityNode::construct()
observeKey("model", sigc::mem_fun(this, &EntityNode::_modelKeyChanged));
observeKey("skin", sigc::mem_fun(_modelKey, &ModelKey::skinChanged));

observeKey("noshadows", sigc::mem_fun(this, &EntityNode::_onNoShadowsSettingsChanged));

_shaderParms.addKeyObservers();

// Construct all attached entities
Expand Down Expand Up @@ -230,11 +234,16 @@ void EntityNode::foreachRenderable(const IRenderEntity::ObjectVisitFunction& fun
}

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

bool EntityNode::isShadowCasting() const
{
return _isShadowCasting;
}

std::string EntityNode::getFingerprint()
{
std::map<std::string, std::string> sortedKeyValues;
Expand Down Expand Up @@ -521,6 +530,11 @@ void EntityNode::_originKeyChanged()
// TODO: add virtual callout for subclasses
}

void EntityNode::_onNoShadowsSettingsChanged(const std::string& noShadowsValue)
{
_isShadowCasting = noShadowsValue != "1";
}

const ShaderPtr& EntityNode::getWireShader() const
{
return _wireShader;
Expand Down
6 changes: 5 additions & 1 deletion radiantcore/entity/EntityNode.h
Expand Up @@ -111,7 +111,9 @@ class EntityNode :
// Used in lighting render mode to enumerate surfaces by entity
RenderableObjectCollection _renderObjects;

protected:
bool _isShadowCasting;

protected:
// The Constructor needs the eclass
EntityNode(const IEntityClassPtr& eclass);

Expand All @@ -136,6 +138,7 @@ class EntityNode :
virtual void foreachRenderable(const ObjectVisitFunction& functor) override;
virtual void foreachRenderableTouchingBounds(const AABB& bounds,
const ObjectVisitFunction& functor) override;
virtual bool isShadowCasting() const;

// IMatrixTransform implementation
Matrix4 localToParent() const override { return _localToParent; }
Expand Down Expand Up @@ -228,6 +231,7 @@ class EntityNode :
// Private function target - wraps to virtual protected signal
void _modelKeyChanged(const std::string& value);
void _originKeyChanged();
void _onNoShadowsSettingsChanged(const std::string& value);

void acquireShaders();
void acquireShaders(const RenderSystemPtr& renderSystem);
Expand Down
14 changes: 3 additions & 11 deletions radiantcore/entity/light/LightNode.cpp
Expand Up @@ -28,8 +28,7 @@ LightNode::LightNode(const IEntityClassPtr& eclass)
_renderableLightVolume(*this),
_renderableVertices(*this, _instances, _projUseFlags),
_showLightVolumeWhenUnselected(EntitySettings::InstancePtr()->getShowAllLightRadii()),
_overrideColKey(colours::RKEY_OVERRIDE_LIGHTCOL),
_isShadowCasting(false)
_overrideColKey(colours::RKEY_OVERRIDE_LIGHTCOL)
{
m_doom3Radius.m_changed = std::bind(&LightNode::onLightRadiusChanged, this);
}
Expand All @@ -48,8 +47,7 @@ LightNode::LightNode(const LightNode& other)
_renderableLightVolume(*this),
_renderableVertices(*this, _instances, _projUseFlags),
_showLightVolumeWhenUnselected(other._showLightVolumeWhenUnselected),
_overrideColKey(colours::RKEY_OVERRIDE_LIGHTCOL),
_isShadowCasting(false)
_overrideColKey(colours::RKEY_OVERRIDE_LIGHTCOL)
{
m_doom3Radius.m_changed = std::bind(&LightNode::onLightRadiusChanged, this);
}
Expand Down Expand Up @@ -93,7 +91,6 @@ void LightNode::construct()
observeKey("light_start", sigc::mem_fun(this, &LightNode::lightStartChanged));
observeKey("light_end", sigc::mem_fun(this, &LightNode::lightEndChanged));
observeKey("texture", sigc::mem_fun(m_shader, &LightShader::valueChanged));
observeKey("noshadows", sigc::mem_fun(this, &LightNode::onNoShadowsChanged));

_projectionChanged = true;

Expand Down Expand Up @@ -136,11 +133,6 @@ void LightNode::onLightRadiusChanged()
boundsChanged();
}

void LightNode::onNoShadowsChanged(const std::string& noShadowsValue)
{
_isShadowCasting = noShadowsValue != "1";
}

void LightNode::transformChanged()
{
EntityNode::transformChanged();
Expand Down Expand Up @@ -1018,7 +1010,7 @@ Vector3 LightNode::getLightOrigin() const

bool LightNode::isShadowCasting() const
{
return _isShadowCasting;
return EntityNode::isShadowCasting();
}

/* greebo: A light is projected, if the entity keys light_target/light_up/light_right are not empty.
Expand Down
8 changes: 2 additions & 6 deletions radiantcore/entity/light/LightNode.h
Expand Up @@ -94,8 +94,6 @@ class LightNode :

mutable Matrix4 m_projectionOrientation;

bool _isShadowCasting;

public:
LightNode(const IEntityClassPtr& eclass);

Expand Down Expand Up @@ -223,7 +221,6 @@ class LightNode :
void rotationChanged();
void lightRotationChanged(const std::string& value);
void onLightRadiusChanged();
void onNoShadowsChanged(const std::string& value);

// Returns a reference to the member class Doom3LightRadius (used to set colours)
Doom3LightRadius& getDoom3Radius();
Expand Down Expand Up @@ -252,17 +249,16 @@ class LightNode :

// Update the projected light frustum
void updateProjection() const;
bool useStartEnd() const;

public:
// RendererLight implementation
const IRenderEntity& getLightEntity() const override;
Matrix4 getLightTextureTransformation() const override;
Vector3 getLightOrigin() const override;
bool isShadowCasting() const override;
const ShaderPtr& getShader() const override;
AABB lightAABB() const override;

bool useStartEnd() const;

};

} // namespace entity
9 changes: 8 additions & 1 deletion radiantcore/model/RenderableModelSurface.h
Expand Up @@ -13,15 +13,17 @@ class RenderableModelSurface final :
{
private:
const IIndexedModelSurface& _surface;
const IRenderEntity* _entity;
const Matrix4& _localToWorld;

public:
using Ptr = std::shared_ptr<RenderableModelSurface>;

// Construct this renderable around the existing surface.
// The reference to the orientation matrix is stored and needs to remain valid
RenderableModelSurface(const IIndexedModelSurface& surface, const Matrix4& localToWorld) :
RenderableModelSurface(const IIndexedModelSurface& surface, const IRenderEntity* entity, const Matrix4& localToWorld) :
_surface(surface),
_entity(entity),
_localToWorld(localToWorld)
{}

Expand Down Expand Up @@ -62,6 +64,11 @@ class RenderableModelSurface final :
{
return _surface.getSurfaceBounds();
}

bool isShadowCasting() override
{
return _entity != nullptr && _entity->isShadowCasting();
}
};

}
2 changes: 1 addition & 1 deletion radiantcore/model/StaticModelNode.cpp
Expand Up @@ -35,7 +35,7 @@ void StaticModelNode::onInsertIntoScene(scene::IMapRootNode& root)
return; // don't handle empty surfaces
}

_renderableSurfaces.emplace_back(std::make_shared<RenderableModelSurface>(surface, localToWorld()));
_renderableSurfaces.emplace_back(std::make_shared<RenderableModelSurface>(surface, _renderEntity, localToWorld()));
});

Node::onInsertIntoScene(root);
Expand Down
2 changes: 1 addition & 1 deletion radiantcore/model/md5/MD5ModelNode.cpp
Expand Up @@ -82,7 +82,7 @@ void MD5ModelNode::onInsertIntoScene(scene::IMapRootNode& root)
}

_renderableSurfaces.emplace_back(
std::make_shared<model::RenderableModelSurface>(surface, localToWorld())
std::make_shared<model::RenderableModelSurface>(surface, _renderEntity, localToWorld())
);
});

Expand Down
8 changes: 4 additions & 4 deletions radiantcore/rendersystem/OpenGLRenderSystem.cpp
Expand Up @@ -218,6 +218,10 @@ void OpenGLRenderSystem::realise()
{
shader->realise();
}

_orthoRenderer = std::make_unique<FullBrightRenderer>(RenderViewType::OrthoView, _state_sorted, _geometryStore);
_editorPreviewRenderer = std::make_unique<FullBrightRenderer>(RenderViewType::Camera, _state_sorted, _geometryStore);
_lightingModeRenderer = std::make_unique<LightingModeRenderer>(*_glProgramFactory, _geometryStore, _lights, _entities);
}

void OpenGLRenderSystem::unrealise()
Expand Down Expand Up @@ -409,10 +413,6 @@ void OpenGLRenderSystem::initialiseModule(const IApplicationContext& ctx)

_sharedContextDestroyed = GlobalOpenGLContext().signal_sharedContextDestroyed()
.connect(sigc::mem_fun(this, &OpenGLRenderSystem::unrealise));

_orthoRenderer = std::make_unique<FullBrightRenderer>(RenderViewType::OrthoView, _state_sorted, _geometryStore);
_editorPreviewRenderer = std::make_unique<FullBrightRenderer>(RenderViewType::Camera, _state_sorted, _geometryStore);
_lightingModeRenderer = std::make_unique<LightingModeRenderer>(*_glProgramFactory, _geometryStore, _lights, _entities);
}

void OpenGLRenderSystem::shutdownModule()
Expand Down
3 changes: 3 additions & 0 deletions radiantcore/rendersystem/backend/LightInteractions.cpp
Expand Up @@ -177,6 +177,9 @@ void LightInteractions::drawShadowMap(OpenGLState& state, const Rectangle& recta

for (const auto& object : objects)
{
// Skip models with "noshadows" set
if (!object.get().isShadowCasting()) continue;

// We submit all objects with an identity matrix in a single multi draw call
if (!object.get().isOriented())
{
Expand Down
11 changes: 9 additions & 2 deletions radiantcore/rendersystem/backend/WindingRenderer.h
Expand Up @@ -121,6 +121,7 @@ class WindingRenderer final :
{
private:
WindingRenderer& _owner;
const IRenderEntity* _entity;
BucketIndex _bucketIndex;

// The winding slot mapping indices, an index into
Expand All @@ -137,8 +138,9 @@ class WindingRenderer final :

sigc::signal<void> _sigBoundsChanged;
public:
WindingGroup(WindingRenderer& owner, BucketIndex bucketIndex) :
WindingGroup(WindingRenderer& owner, const IRenderEntity* entity, BucketIndex bucketIndex) :
_owner(owner),
_entity(entity),
_bucketIndex(bucketIndex),
_surfaceNeedsRebuild(true),
_boundsNeedUpdate(true),
Expand Down Expand Up @@ -217,6 +219,11 @@ class WindingRenderer final :
return _indexSlot;
}

bool isShadowCasting() override
{
return _entity->isShadowCasting();
}

private:
void boundsChanged()
{
Expand Down Expand Up @@ -311,7 +318,7 @@ class WindingRenderer final :
if (existing == _windingMap.end())
{
existing = _windingMap.emplace(key,
std::make_shared<WindingGroup>(_owner, slot.bucketIndex)).first;
std::make_shared<WindingGroup>(_owner, slot.renderEntity, slot.bucketIndex)).first;

// New surface, register this with the entity
slot.renderEntity->addRenderable(existing->second, _owner._owningShader);
Expand Down

0 comments on commit b3e3ba8

Please sign in to comment.