mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-25 03:42:48 +01:00
Merge pull request #573 from ShFil119/raii_effects
Refactor VisualFX and fix memory leaks
This commit is contained in:
commit
2670de509f
@ -497,15 +497,30 @@ void GameWorld::destroyQueuedObjects() {
|
||||
}
|
||||
}
|
||||
|
||||
VisualFX* GameWorld::createEffect(VisualFX::EffectType type) {
|
||||
auto effect = new VisualFX(type);
|
||||
effects.push_back(effect);
|
||||
return effect;
|
||||
LightFX& GameWorld::createLightEffect() {
|
||||
auto effect = std::make_unique<LightFX>();
|
||||
auto& ref = *effect;
|
||||
effects.push_back(std::move(effect));
|
||||
return ref;
|
||||
}
|
||||
|
||||
void GameWorld::destroyEffect(VisualFX* effect) {
|
||||
ParticleFX& GameWorld::createParticleEffect() {
|
||||
auto effect = std::make_unique<ParticleFX>();
|
||||
auto& ref = *effect;
|
||||
effects.push_back(std::move(effect));
|
||||
return ref;
|
||||
}
|
||||
|
||||
TrailFX& GameWorld::createTrailEffect() {
|
||||
auto effect = std::make_unique<TrailFX>();
|
||||
auto& ref = *effect;
|
||||
effects.push_back(std::move(effect));
|
||||
return ref;
|
||||
}
|
||||
|
||||
void GameWorld::destroyEffect(VisualFX& effect) {
|
||||
for (auto it = effects.begin(); it != effects.end();) {
|
||||
if (*it == effect) {
|
||||
if (it->get() == &effect) {
|
||||
it = effects.erase(it);
|
||||
} else {
|
||||
it++;
|
||||
@ -833,6 +848,20 @@ bool GameWorld::isPaused() const {
|
||||
return paused;
|
||||
}
|
||||
|
||||
void GameWorld::updateEffects() {
|
||||
for (int i = 0; i < static_cast<int>(effects.size()); ++i) {
|
||||
auto& effect = effects[i];
|
||||
if (effect->getType() == Particle) {
|
||||
auto particle = static_cast<ParticleFX*>(effect.get());
|
||||
if (particle->lifetime < 0.f) continue;
|
||||
if (getGameTime() >= particle->starttime + particle->lifetime) {
|
||||
destroyEffect(*particle);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VehicleObject* GameWorld::tryToSpawnVehicle(VehicleGenerator& gen) {
|
||||
constexpr float kMinClearRadius = 10.f;
|
||||
|
||||
|
@ -179,14 +179,24 @@ public:
|
||||
void doWeaponScan(const WeaponScan& scan);
|
||||
|
||||
/**
|
||||
* Allocates a new VisualFX of the given type
|
||||
* Allocates a new Light Effect
|
||||
*/
|
||||
VisualFX* createEffect(VisualFX::EffectType type);
|
||||
LightFX& createLightEffect();
|
||||
|
||||
/**
|
||||
* Allocates a new Particle Effect
|
||||
*/
|
||||
ParticleFX& createParticleEffect();
|
||||
|
||||
/**
|
||||
* Allocates a new Trail Effect
|
||||
*/
|
||||
TrailFX& createTrailEffect();
|
||||
|
||||
/**
|
||||
* Immediately destoys the given effect
|
||||
*/
|
||||
void destroyEffect(VisualFX* effect);
|
||||
void destroyEffect(VisualFX& effect);
|
||||
|
||||
/**
|
||||
* Returns the current hour
|
||||
@ -296,7 +306,7 @@ public:
|
||||
* Visual Effects
|
||||
* @todo Consider using lighter handing mechanism
|
||||
*/
|
||||
std::vector<VisualFX*> effects;
|
||||
std::vector<std::unique_ptr<VisualFX>> effects;
|
||||
|
||||
/**
|
||||
* Randomness Engine
|
||||
@ -364,6 +374,11 @@ public:
|
||||
void setPaused(bool pause);
|
||||
bool isPaused() const;
|
||||
|
||||
/**
|
||||
* Clean up old VisualFX
|
||||
*/
|
||||
void updateEffects();
|
||||
|
||||
/**
|
||||
* Attempt to spawn a vehicle at a vehicle generator
|
||||
*/
|
||||
|
@ -92,6 +92,7 @@ PickupObject::BehaviourFlags PickupObject::defaultBehaviourFlags(
|
||||
PickupObject::PickupObject(GameWorld* world, const glm::vec3& position,
|
||||
BaseModelInfo* modelinfo, PickupType type)
|
||||
: GameObject(world, position, glm::quat{1.0f, 0.0f, 0.0f, 0.0f}, modelinfo)
|
||||
, m_corona(world->createParticleEffect())
|
||||
, m_type(type) {
|
||||
btTransform tf;
|
||||
tf.setIdentity();
|
||||
@ -134,19 +135,18 @@ PickupObject::PickupObject(GameWorld* world, const glm::vec3& position,
|
||||
else if (modelinfo->name == "health" || modelinfo->name == "bonus")
|
||||
m_colourId = 13;
|
||||
|
||||
m_corona = world->createEffect(VisualFX::Particle);
|
||||
m_corona->particle.position = getPosition();
|
||||
m_corona->particle.direction = glm::vec3(0.f, 0.f, 1.f);
|
||||
m_corona->particle.orientation = VisualFX::ParticleData::Camera;
|
||||
m_corona.position = getPosition();
|
||||
m_corona.direction = glm::vec3(0.f, 0.f, 1.f);
|
||||
m_corona.orientation = ParticleFX::Camera;
|
||||
|
||||
// @todo float package should float on the water
|
||||
if (m_type == FloatingPackage) {
|
||||
// verify offset and texture?
|
||||
m_corona->particle.position += glm::vec3(0.f, 0.f, 0.7f);
|
||||
m_corona->particle.texture =
|
||||
m_corona.position += glm::vec3(0.f, 0.f, 0.7f);
|
||||
m_corona.texture =
|
||||
engine->data->findSlotTexture("particle", "coronastar");
|
||||
} else {
|
||||
m_corona->particle.texture =
|
||||
m_corona.texture =
|
||||
engine->data->findSlotTexture("particle", "coronaringa");
|
||||
}
|
||||
|
||||
@ -162,7 +162,6 @@ PickupObject::~PickupObject() {
|
||||
if (m_ghost) {
|
||||
setEnabled(false);
|
||||
engine->destroyEffect(m_corona);
|
||||
delete m_corona;
|
||||
delete m_ghost;
|
||||
delete m_shape;
|
||||
}
|
||||
@ -197,7 +196,7 @@ void PickupObject::tick(float dt) {
|
||||
float red = (*colour >> 16) & 0xFF;
|
||||
float green = (*colour >> 8) & 0xFF;
|
||||
float blue = *colour & 0xFF;
|
||||
m_corona->particle.colour =
|
||||
m_corona.colour =
|
||||
glm::vec4(red / 255.f, green / 255.f, blue / 255.f, 1.f) * colourValue;
|
||||
|
||||
if (m_enabled) {
|
||||
@ -258,10 +257,10 @@ void PickupObject::setEnabled(bool enabled) {
|
||||
if (!m_enabled && enabled) {
|
||||
engine->dynamicsWorld->addCollisionObject(
|
||||
m_ghost, btBroadphaseProxy::SensorTrigger);
|
||||
m_corona->particle.size = glm::vec2(1.5f, 1.5f);
|
||||
m_corona.size = glm::vec2(1.5f, 1.5f);
|
||||
} else if (m_enabled && !enabled) {
|
||||
engine->dynamicsWorld->removeCollisionObject(m_ghost);
|
||||
m_corona->particle.size = glm::vec2(0.f, 0.f);
|
||||
m_corona.size = glm::vec2(0.f, 0.f);
|
||||
}
|
||||
|
||||
m_enabled = enabled;
|
||||
|
@ -6,8 +6,10 @@
|
||||
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
#include <render/VisualFX.hpp>
|
||||
#include <objects/GameObject.hpp>
|
||||
|
||||
|
||||
class btPairCachingGhostObject;
|
||||
class btSphereShape;
|
||||
|
||||
@ -119,7 +121,7 @@ private:
|
||||
bool m_enabled = false;
|
||||
float m_enableTimer = 0.f;
|
||||
bool m_collected = false;
|
||||
VisualFX* m_corona = nullptr;
|
||||
ParticleFX& m_corona;
|
||||
short m_colourId = 0;
|
||||
bool respawn = false;
|
||||
float respawnTime{};
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "data/WeaponData.hpp"
|
||||
#include "engine/GameData.hpp"
|
||||
#include "engine/GameWorld.hpp"
|
||||
#include "render/VisualFX.hpp"
|
||||
|
||||
void ProjectileObject::checkPhysicsContact() {
|
||||
btManifoldArray manifoldArray;
|
||||
@ -77,17 +76,17 @@ void ProjectileObject::explode() {
|
||||
0.f});
|
||||
}
|
||||
|
||||
auto tex = engine->data->findSlotTexture("particle", "explo02");
|
||||
auto& explosion = engine->createParticleEffect();
|
||||
|
||||
auto explosion = engine->createEffect(VisualFX::Particle);
|
||||
explosion->particle.size = glm::vec2(exp_size);
|
||||
explosion->particle.texture = tex;
|
||||
explosion->particle.starttime = engine->getGameTime();
|
||||
explosion->particle.lifetime = 0.5f;
|
||||
explosion->particle.orientation = VisualFX::ParticleData::Camera;
|
||||
explosion->particle.colour = glm::vec4(1.0f);
|
||||
explosion->particle.position = getPosition();
|
||||
explosion->particle.direction = glm::vec3(0.f, 0.f, 1.f);
|
||||
auto tex = engine->data->findSlotTexture("particle", "explo02");
|
||||
explosion.texture = tex;
|
||||
explosion.size = glm::vec2(exp_size);
|
||||
explosion.starttime = engine->getGameTime();
|
||||
explosion.lifetime = 0.5f;
|
||||
explosion.orientation = ParticleFX::Camera;
|
||||
explosion.colour = glm::vec4(1.0f);
|
||||
explosion.position = getPosition();
|
||||
explosion.direction = glm::vec3(0.f, 0.f, 1.f);
|
||||
|
||||
_exploded = true;
|
||||
engine->destroyObjectQueued(this);
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <objects/GameObject.hpp>
|
||||
#include "render/VisualFX.hpp"
|
||||
|
||||
|
||||
class GameWorld;
|
||||
class btPairCachingGhostObject;
|
||||
|
@ -452,26 +452,25 @@ void GameRenderer::renderEffects(GameWorld* world) {
|
||||
auto& effects = world->effects;
|
||||
|
||||
std::sort(effects.begin(), effects.end(),
|
||||
[&](const VisualFX* a, const VisualFX* b) {
|
||||
return glm::distance(a->getPosition(), cpos) >
|
||||
glm::distance(b->getPosition(), cpos);
|
||||
[&](const auto& a, const auto& b) {
|
||||
return glm::distance(a->position, cpos) >
|
||||
glm::distance(b->position, cpos);
|
||||
});
|
||||
|
||||
for (VisualFX* fx : effects) {
|
||||
for (auto& fx : effects) {
|
||||
// Other effects not implemented yet
|
||||
if (fx->getType() != VisualFX::Particle) continue;
|
||||
if (fx->getType() != Particle) continue;
|
||||
auto particle = static_cast<ParticleFX*>(fx.get());
|
||||
|
||||
auto& particle = fx->particle;
|
||||
|
||||
auto& p = particle.position;
|
||||
auto& p = particle->position;
|
||||
|
||||
// Figure the direction to the camera center.
|
||||
auto amp = cpos - p;
|
||||
glm::vec3 ptc = particle.up;
|
||||
glm::vec3 ptc = particle->up;
|
||||
|
||||
if (particle.orientation == VisualFX::ParticleData::UpCamera) {
|
||||
if (particle->orientation == ParticleFX::UpCamera) {
|
||||
ptc = glm::normalize(amp - (glm::dot(amp, cfwd)) * cfwd);
|
||||
} else if (particle.orientation == VisualFX::ParticleData::Camera) {
|
||||
} else if (particle->orientation == ParticleFX::Camera) {
|
||||
ptc = amp;
|
||||
}
|
||||
|
||||
@ -485,12 +484,12 @@ void GameRenderer::renderEffects(GameWorld* world) {
|
||||
glm::vec3(0.0f,0.0f,1.0f));
|
||||
|
||||
transformMat = glm::scale(glm::translate(transformMat,p),
|
||||
glm::vec3(particle.size,1.0f)) * glm::inverse(lookMat);
|
||||
glm::vec3(particle->size,1.0f)) * glm::inverse(lookMat);
|
||||
|
||||
Renderer::DrawParameters dp;
|
||||
dp.textures = {particle.texture->getName()};
|
||||
dp.textures = {particle->texture->getName()};
|
||||
dp.ambient = 1.f;
|
||||
dp.colour = glm::u8vec4(particle.colour * 255.f);
|
||||
dp.colour = glm::u8vec4(particle->colour * 255.f);
|
||||
dp.start = 0;
|
||||
dp.count = 4;
|
||||
dp.blendMode = BlendMode::BLEND_ADDITIVE;
|
||||
|
@ -1,47 +1 @@
|
||||
#include "render/VisualFX.hpp"
|
||||
|
||||
#include <new>
|
||||
|
||||
VisualFX::LightData::~LightData() = default;
|
||||
|
||||
VisualFX::ParticleData::~ParticleData() = default;
|
||||
|
||||
VisualFX::TrailData::~TrailData() = default;
|
||||
|
||||
VisualFX::VisualFX(VisualFX::EffectType type) : type(type) {
|
||||
switch (type) {
|
||||
case VisualFX::Light:
|
||||
new (&light) LightData;
|
||||
break;
|
||||
case VisualFX::Particle:
|
||||
new (&particle) ParticleData;
|
||||
break;
|
||||
case VisualFX::Trail:
|
||||
new (&trail) TrailData;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VisualFX::~VisualFX() {
|
||||
switch (type) {
|
||||
case VisualFX::Light:
|
||||
light.~LightData();
|
||||
break;
|
||||
case VisualFX::Particle:
|
||||
particle.~ParticleData();
|
||||
break;
|
||||
case VisualFX::Trail:
|
||||
trail.~TrailData();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const glm::vec3& VisualFX::getPosition() const {
|
||||
static glm::vec3 errorRef{};
|
||||
switch (type) {
|
||||
case VisualFX::Particle:
|
||||
return particle.position;
|
||||
default:
|
||||
return errorRef;
|
||||
}
|
||||
}
|
||||
|
@ -5,20 +5,31 @@
|
||||
|
||||
#include <gl/TextureData.hpp>
|
||||
|
||||
enum EffectType { Light, Particle, Trail };
|
||||
|
||||
/**
|
||||
* Represents a scene effect: lighting, particles etc.
|
||||
*/
|
||||
class VisualFX {
|
||||
public:
|
||||
enum EffectType { Light, Particle, Trail };
|
||||
struct VisualFX {
|
||||
VisualFX() = default;
|
||||
virtual ~VisualFX() = default;
|
||||
|
||||
virtual EffectType getType() const = 0;
|
||||
|
||||
struct LightData {
|
||||
~LightData();
|
||||
};
|
||||
struct ParticleData {
|
||||
/** Initial world position */
|
||||
glm::vec3 position{};
|
||||
};
|
||||
|
||||
struct LightFX final : public VisualFX {
|
||||
LightFX() = default;
|
||||
~LightFX() = default;
|
||||
|
||||
EffectType getType() const override {
|
||||
return Light;
|
||||
}
|
||||
};
|
||||
|
||||
struct ParticleFX final : public VisualFX {
|
||||
/** Direction of particle */
|
||||
glm::vec3 direction{};
|
||||
|
||||
@ -28,59 +39,42 @@ public:
|
||||
Camera, /** Faces towards the camera @todo implement */
|
||||
UpCamera /** Face closes point in camera's look direction */
|
||||
};
|
||||
Orientation orientation;
|
||||
Orientation orientation{Free};
|
||||
|
||||
/** Game time at particle instantiation */
|
||||
float starttime;
|
||||
float starttime{0.f};
|
||||
/** Number of seconds particle should exist for, negative values =
|
||||
* forever */
|
||||
float lifetime;
|
||||
float lifetime{-1.f};
|
||||
|
||||
/** Texture name */
|
||||
TextureData::Handle texture;
|
||||
|
||||
/** Size of particle */
|
||||
glm::vec2 size;
|
||||
glm::vec2 size{1.f, 1.f};
|
||||
|
||||
/** Up direction (only used in Free mode) */
|
||||
glm::vec3 up;
|
||||
glm::vec3 up{0.f, 0.f, 1.f};
|
||||
|
||||
/** Render tint colour */
|
||||
glm::vec4 colour;
|
||||
glm::vec4 colour{1.f, 1.f, 1.f, 1.f};
|
||||
|
||||
/** Constructs a particle */
|
||||
ParticleData()
|
||||
: orientation(Free)
|
||||
, starttime(0.f)
|
||||
, lifetime(-1.f)
|
||||
, size(1.f, 1.f)
|
||||
, up(0.f, 0.f, 1.f)
|
||||
, colour(1.f, 1.f, 1.f, 1.f) {
|
||||
ParticleFX() = default;
|
||||
~ParticleFX() = default;
|
||||
|
||||
EffectType getType() const override {
|
||||
return Particle;
|
||||
}
|
||||
~ParticleData();
|
||||
};
|
||||
struct TrailData {
|
||||
~TrailData();
|
||||
};
|
||||
};
|
||||
|
||||
/// @todo stop abusing unions
|
||||
union {
|
||||
LightData light;
|
||||
ParticleData particle;
|
||||
TrailData trail;
|
||||
};
|
||||
struct TrailFX final : public VisualFX {
|
||||
TrailFX() = default;
|
||||
~TrailFX() = default;
|
||||
|
||||
VisualFX(EffectType type);
|
||||
~VisualFX();
|
||||
|
||||
EffectType getType() const {
|
||||
return type;
|
||||
EffectType getType() const override {
|
||||
return Trail;
|
||||
}
|
||||
|
||||
const glm::vec3& getPosition() const;
|
||||
|
||||
private:
|
||||
EffectType type;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -528,18 +528,7 @@ void RWGame::tick(float dt) {
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up old VisualFX
|
||||
for (int i = 0; i < static_cast<int>(world->effects.size()); ++i) {
|
||||
VisualFX* effect = world->effects[i];
|
||||
if (effect->getType() == VisualFX::Particle) {
|
||||
auto& part = effect->particle;
|
||||
if (part.lifetime < 0.f) continue;
|
||||
if (world->getGameTime() >= part.starttime + part.lifetime) {
|
||||
world->destroyEffect(effect);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
world->updateEffects();
|
||||
|
||||
for (auto& object : world->allObjects) {
|
||||
object->_updateLastTransform();
|
||||
|
@ -4,9 +4,9 @@
|
||||
BOOST_AUTO_TEST_SUITE(VisualFXTests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_light_data) {
|
||||
VisualFX fx(VisualFX::Light);
|
||||
auto fx = std::make_unique<LightFX>();
|
||||
|
||||
BOOST_CHECK_EQUAL(fx.getType(), VisualFX::Light);
|
||||
BOOST_CHECK_EQUAL(fx->getType(), Light);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
Loading…
Reference in New Issue
Block a user