mirror of
https://github.com/luanti-org/luanti.git
synced 2025-08-11 17:51:04 +00:00
Batched rendering of particles (#14489)
Co-authored-by: x2048 <codeforsmile@gmail.com> Co-authored-by: Desour <ds.desour@proton.me>
This commit is contained in:
parent
ff88ed7c75
commit
f8bff346f4
3 changed files with 395 additions and 213 deletions
|
@ -19,9 +19,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "localplayer.h"
|
||||
#include "irr_ptr.h"
|
||||
#include "../particles.h"
|
||||
|
||||
struct ClientEvent;
|
||||
|
@ -29,6 +30,10 @@ class ParticleManager;
|
|||
class ClientEnvironment;
|
||||
struct MapNode;
|
||||
struct ContentFeatures;
|
||||
class LocalPlayer;
|
||||
class ITextureSource;
|
||||
class IGameDef;
|
||||
class Client;
|
||||
|
||||
struct ClientParticleTexture
|
||||
{
|
||||
|
@ -38,9 +43,7 @@ struct ClientParticleTexture
|
|||
video::ITexture *ref = nullptr;
|
||||
|
||||
ClientParticleTexture() = default;
|
||||
ClientParticleTexture(const ServerParticleTexture& p, ITextureSource *t):
|
||||
tex(p),
|
||||
ref(t->getTextureForMesh(p.string)) {};
|
||||
ClientParticleTexture(const ServerParticleTexture& p, ITextureSource *tsrc);
|
||||
};
|
||||
|
||||
struct ClientParticleTexRef
|
||||
|
@ -61,14 +64,12 @@ struct ClientParticleTexRef
|
|||
};
|
||||
|
||||
class ParticleSpawner;
|
||||
class ParticleBuffer;
|
||||
|
||||
class Particle : public scene::ISceneNode
|
||||
class Particle
|
||||
{
|
||||
public:
|
||||
Particle(
|
||||
IGameDef *gamedef,
|
||||
LocalPlayer *player,
|
||||
ClientEnvironment *env,
|
||||
const ParticleParameters &p,
|
||||
const ClientParticleTexRef &texture,
|
||||
v2f texpos,
|
||||
|
@ -78,61 +79,46 @@ public:
|
|||
std::unique_ptr<ClientParticleTexture> owned_texture = nullptr
|
||||
);
|
||||
|
||||
virtual const aabb3f &getBoundingBox() const
|
||||
{
|
||||
return m_box;
|
||||
}
|
||||
~Particle();
|
||||
|
||||
virtual u32 getMaterialCount() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
DISABLE_CLASS_COPY(Particle)
|
||||
|
||||
virtual video::SMaterial& getMaterial(u32 i)
|
||||
{
|
||||
return m_material;
|
||||
}
|
||||
void step(float dtime, ClientEnvironment *env);
|
||||
|
||||
virtual void OnRegisterSceneNode();
|
||||
virtual void render();
|
||||
|
||||
void step(float dtime);
|
||||
|
||||
bool isExpired ()
|
||||
bool isExpired () const
|
||||
{ return m_expiration < m_time; }
|
||||
|
||||
ParticleSpawner *getParent() { return m_parent; }
|
||||
ParticleSpawner *getParent() const { return m_parent; }
|
||||
|
||||
const ClientParticleTexRef &getTextureRef() const { return m_texture; }
|
||||
|
||||
ParticleBuffer *getBuffer() const { return m_buffer; }
|
||||
bool attachToBuffer(ParticleBuffer *buffer);
|
||||
|
||||
private:
|
||||
void updateLight();
|
||||
void updateVertices();
|
||||
void setVertexAlpha(float a);
|
||||
video::SColor updateLight(ClientEnvironment *env);
|
||||
void updateVertices(ClientEnvironment *env, video::SColor color);
|
||||
|
||||
ParticleBuffer *m_buffer = nullptr;
|
||||
u16 m_index; // index in m_buffer
|
||||
|
||||
video::S3DVertex m_vertices[4];
|
||||
float m_time = 0.0f;
|
||||
float m_expiration;
|
||||
|
||||
ClientEnvironment *m_env;
|
||||
IGameDef *m_gamedef;
|
||||
aabb3f m_box;
|
||||
aabb3f m_collisionbox;
|
||||
// Color without lighting
|
||||
video::SColor m_base_color;
|
||||
|
||||
ClientParticleTexRef m_texture;
|
||||
video::SMaterial m_material;
|
||||
v2f m_texpos;
|
||||
v2f m_texsize;
|
||||
v3f m_pos;
|
||||
v3f m_velocity;
|
||||
v3f m_acceleration;
|
||||
const ParticleParameters m_p;
|
||||
LocalPlayer *m_player;
|
||||
|
||||
//! Color without lighting
|
||||
video::SColor m_base_color;
|
||||
//! Final rendered color
|
||||
video::SColor m_color;
|
||||
const ParticleParameters m_p;
|
||||
|
||||
float m_animation_time = 0.0f;
|
||||
int m_animation_frame = 0;
|
||||
float m_alpha = 0.0f;
|
||||
|
||||
ParticleSpawner *m_parent = nullptr;
|
||||
// Used if not spawned from a particlespawner
|
||||
|
@ -142,8 +128,7 @@ private:
|
|||
class ParticleSpawner
|
||||
{
|
||||
public:
|
||||
ParticleSpawner(IGameDef *gamedef,
|
||||
LocalPlayer *player,
|
||||
ParticleSpawner(LocalPlayer *player,
|
||||
const ParticleSpawnerParameters ¶ms,
|
||||
u16 attached_id,
|
||||
std::vector<ClientParticleTexture> &&texpool,
|
||||
|
@ -164,7 +149,6 @@ private:
|
|||
size_t m_active;
|
||||
ParticleManager *m_particlemanager;
|
||||
float m_time;
|
||||
IGameDef *m_gamedef;
|
||||
LocalPlayer *m_player;
|
||||
ParticleSpawnerParameters p;
|
||||
std::vector<ClientParticleTexture> m_texpool;
|
||||
|
@ -172,12 +156,61 @@ private:
|
|||
u16 m_attached_id;
|
||||
};
|
||||
|
||||
class ParticleBuffer : public scene::ISceneNode
|
||||
{
|
||||
friend class ParticleManager;
|
||||
public:
|
||||
ParticleBuffer(ClientEnvironment *env, const video::SMaterial &material);
|
||||
|
||||
// for pointer stability
|
||||
DISABLE_CLASS_COPY(ParticleBuffer)
|
||||
|
||||
/// Reserves one more slot for a particle (4 vertices, 6 indices)
|
||||
/// @return particle index within buffer
|
||||
std::optional<u16> allocate();
|
||||
/// Frees the particle at `index`
|
||||
void release(u16 index);
|
||||
|
||||
/// @return video::S3DVertex[4]
|
||||
video::S3DVertex *getVertices(u16 index);
|
||||
|
||||
inline bool isEmpty() const {
|
||||
return m_free_list.size() == m_count;
|
||||
}
|
||||
|
||||
virtual video::SMaterial &getMaterial(u32 num) override {
|
||||
return m_mesh_buffer->getMaterial();
|
||||
}
|
||||
virtual u32 getMaterialCount() const override {
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual const core::aabbox3df &getBoundingBox() const override;
|
||||
|
||||
virtual void render() override;
|
||||
|
||||
virtual void OnRegisterSceneNode() override;
|
||||
|
||||
// we have 16-bit indices
|
||||
static constexpr u16 MAX_PARTICLES_PER_BUFFER = 16000;
|
||||
|
||||
private:
|
||||
irr_ptr<scene::SMeshBuffer> m_mesh_buffer;
|
||||
// unused (e.g. expired) particle indices for re-use
|
||||
std::vector<u16> m_free_list;
|
||||
// for automatic deletion when unused for a while. is reset on allocate().
|
||||
float m_usage_timer = 0;
|
||||
// total count of contained particles
|
||||
u16 m_count = 0;
|
||||
mutable bool m_bounding_box_dirty = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Class doing particle as well as their spawners handling
|
||||
*/
|
||||
class ParticleManager
|
||||
{
|
||||
friend class ParticleSpawner;
|
||||
friend class ParticleSpawner;
|
||||
public:
|
||||
ParticleManager(ClientEnvironment* env);
|
||||
DISABLE_CLASS_COPY(ParticleManager)
|
||||
|
@ -213,7 +246,9 @@ protected:
|
|||
ParticleParameters &p, video::ITexture **texture, v2f &texpos,
|
||||
v2f &texsize, video::SColor *color, u8 tilenum = 0);
|
||||
|
||||
void addParticle(std::unique_ptr<Particle> toadd);
|
||||
static video::SMaterial getMaterialForParticle(const ClientParticleTexRef &texture);
|
||||
|
||||
bool addParticle(std::unique_ptr<Particle> toadd);
|
||||
|
||||
private:
|
||||
void addParticleSpawner(u64 id, std::unique_ptr<ParticleSpawner> toadd);
|
||||
|
@ -221,17 +256,23 @@ private:
|
|||
|
||||
void stepParticles(float dtime);
|
||||
void stepSpawners(float dtime);
|
||||
void stepBuffers(float dtime);
|
||||
|
||||
void clearAll();
|
||||
|
||||
std::vector<std::unique_ptr<Particle>> m_particles;
|
||||
std::unordered_map<u64, std::unique_ptr<ParticleSpawner>> m_particle_spawners;
|
||||
std::vector<std::unique_ptr<ParticleSpawner>> m_dying_particle_spawners;
|
||||
// Start the particle spawner ids generated from here after u32_max. lower values are
|
||||
// for server sent spawners.
|
||||
u64 m_next_particle_spawner_id = U32_MAX + 1;
|
||||
std::vector<irr_ptr<ParticleBuffer>> m_particle_buffers;
|
||||
|
||||
// Start the particle spawner ids generated from here after u32_max.
|
||||
// lower values are for server sent spawners.
|
||||
u64 m_next_particle_spawner_id = static_cast<u64>(U32_MAX) + 1;
|
||||
|
||||
ClientEnvironment *m_env;
|
||||
|
||||
IntervalLimiter m_buffer_gc;
|
||||
|
||||
std::mutex m_particle_list_lock;
|
||||
std::mutex m_spawner_list_lock;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue