1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
|
#include "RenderableParticle.h"
namespace particles
{
RenderableParticle::RenderableParticle(const IParticleDef::Ptr& particleDef) :
_particleDef(), // don't initialise the ptr yet
_random(rand()), // use a random seed
_direction(0,0,1), // default direction
_entityColour(1,1,1) // default entity colour
{
// Use this method, for observer handling
setParticleDef(particleDef);
}
RenderableParticle::~RenderableParticle()
{
// Clear the particle def reference (remove this class as observer)
setParticleDef({});
}
// Time is in msecs
void RenderableParticle::update(const Matrix4& viewRotation, const Matrix4& localToWorld, IRenderEntity* entity)
{
auto renderSystem = _renderSystem.lock();
if (!renderSystem) return; // no rendersystem there yet
auto time = renderSystem->getTime();
// Invalidate our bounds information
_bounds = AABB();
// Make sure all shaders are constructed
ensureShaders(*renderSystem);
// greebo: Use the inverse matrix of the incoming matrix, this is enough to compensate
// the camera rotation.
auto invViewRotation = viewRotation.getInverse();
// Traverse the stages and call update
for (const auto& pair : _shaderMap)
{
for (const auto& stage : pair.second.stages)
{
if (!stage->getDef().isVisible())
{
stage->clear();
continue;
}
// Update the particle quads
stage->update(time, invViewRotation);
// Check if the stage is empty, otherwise remove any geometry
if (stage->getNumQuads() == 0)
{
stage->clear();
continue;
}
// Attach the geometry to the shader
stage->submitGeometry(pair.second.shader, localToWorld);
// Attach to the parent entity for lighting mode
stage->attachToEntity(entity);
}
}
}
void RenderableParticle::clearRenderables()
{
for (const auto& pair : _shaderMap)
{
for (const auto& stage : pair.second.stages)
{
stage->clear();
}
}
}
void RenderableParticle::onPreRender(const VolumeTest& volume)
{}
void RenderableParticle::renderHighlights(IRenderableCollector& collector, const VolumeTest& volume)
{
}
void RenderableParticle::setRenderSystem(const RenderSystemPtr& renderSystem)
{
_renderSystem = renderSystem;
}
const IParticleDef::Ptr& RenderableParticle::getParticleDef() const
{
return _particleDef;
}
void RenderableParticle::setParticleDef(const IParticleDef::Ptr& def)
{
if (_particleDef)
{
_defConnection.disconnect();
}
_particleDef = def;
if (_particleDef)
{
// Start monitoring this particle for reload events
_defConnection = _particleDef->signal_changed().connect(
sigc::mem_fun(this, &RenderableParticle::setupStages)
);
}
// Re-construct our stage information
setupStages();
}
void RenderableParticle::setMainDirection(const Vector3& direction)
{
_direction = direction;
// The particle stages hold a const-reference to _direction
// so no further update is needed
}
void RenderableParticle::setEntityColour(const Vector3& colour)
{
_entityColour = colour;
// The particle stages hold a const-reference to _entityColour
// so no further update is needed
}
// Updates bounds from stages and returns the value
const AABB& RenderableParticle::getBounds()
{
if (!_bounds.isValid())
{
calculateBounds();
}
return _bounds;
}
void RenderableParticle::calculateBounds()
{
for (const auto& pair : _shaderMap)
{
for (const auto& stage : pair.second.stages)
{
_bounds.includeAABB(stage->getBounds());
}
}
}
// Sort stages into groups sharing a material, without capturing the shader yet
void RenderableParticle::setupStages()
{
_shaderMap.clear();
if (!_particleDef) return; // nothing to do.
for (std::size_t i = 0; i < _particleDef->getNumStages(); ++i)
{
const auto& stage = _particleDef->getStage(i);
const auto& materialName = stage->getMaterialName();
if (_shaderMap.find(materialName) == _shaderMap.end())
{
_shaderMap.emplace(materialName, ParticleStageGroup());
}
// Create a new renderable stage and add it to the shader
auto renderableStage = std::make_shared<RenderableParticleStage>(*stage, _random, _direction, _entityColour);
_shaderMap[materialName].stages.emplace_back(std::move(renderableStage));
}
}
// Capture all shaders, if necessary
void RenderableParticle::ensureShaders(RenderSystem& renderSystem)
{
for (auto& pair : _shaderMap)
{
if (!pair.second.shader)
{
pair.second.shader = renderSystem.capture(pair.first);
}
}
}
} // namespace
|