particles.h 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. // Luanti
  2. // SPDX-License-Identifier: LGPL-2.1-or-later
  3. // Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. #pragma once
  5. #include <vector>
  6. #include <unordered_map>
  7. #include "irrlichttypes_extrabloated.h"
  8. #include "irr_ptr.h"
  9. #include "../particles.h"
  10. struct ClientEvent;
  11. class ParticleManager;
  12. class ClientEnvironment;
  13. struct MapNode;
  14. struct ContentFeatures;
  15. class LocalPlayer;
  16. class ITextureSource;
  17. class IGameDef;
  18. class Client;
  19. struct ClientParticleTexture
  20. {
  21. /* per-spawner structure used to store the ParticleTexture structs
  22. * that spawned particles will refer to through ClientParticleTexRef */
  23. ParticleTexture tex;
  24. video::ITexture *ref = nullptr;
  25. ClientParticleTexture() = default;
  26. ClientParticleTexture(const ServerParticleTexture& p, ITextureSource *tsrc);
  27. };
  28. struct ClientParticleTexRef
  29. {
  30. /* per-particle structure used to avoid massively duplicating the
  31. * fairly large ParticleTexture struct */
  32. ParticleTexture *tex = nullptr;
  33. video::ITexture *ref = nullptr;
  34. ClientParticleTexRef() = default;
  35. /* constructor used by particles spawned from a spawner */
  36. explicit ClientParticleTexRef(ClientParticleTexture &t):
  37. tex(&t.tex), ref(t.ref) {};
  38. /* constructor used for node particles */
  39. explicit ClientParticleTexRef(video::ITexture *tp): ref(tp) {};
  40. };
  41. class ParticleSpawner;
  42. class ParticleBuffer;
  43. class Particle
  44. {
  45. public:
  46. Particle(
  47. const ParticleParameters &p,
  48. const ClientParticleTexRef &texture,
  49. v2f texpos,
  50. v2f texsize,
  51. video::SColor color,
  52. ParticleSpawner *parent = nullptr,
  53. std::unique_ptr<ClientParticleTexture> owned_texture = nullptr
  54. );
  55. ~Particle();
  56. DISABLE_CLASS_COPY(Particle)
  57. void step(float dtime, ClientEnvironment *env);
  58. bool isExpired () const
  59. { return m_expiration < m_time; }
  60. ParticleSpawner *getParent() const { return m_parent; }
  61. const ClientParticleTexRef &getTextureRef() const { return m_texture; }
  62. ParticleParamTypes::BlendMode getBlendMode() const
  63. { return m_texture.tex ? m_texture.tex->blendmode : m_p.texture.blendmode; }
  64. ParticleBuffer *getBuffer() const { return m_buffer; }
  65. bool attachToBuffer(ParticleBuffer *buffer);
  66. private:
  67. video::SColor updateLight(ClientEnvironment *env);
  68. void updateVertices(ClientEnvironment *env, video::SColor color);
  69. ParticleBuffer *m_buffer = nullptr;
  70. u16 m_index; // index in m_buffer
  71. float m_time = 0.0f;
  72. float m_expiration;
  73. // Color without lighting
  74. video::SColor m_base_color;
  75. ClientParticleTexRef m_texture;
  76. v2f m_texpos;
  77. v2f m_texsize;
  78. v3f m_pos;
  79. v3f m_velocity;
  80. v3f m_acceleration;
  81. const ParticleParameters m_p;
  82. float m_animation_time = 0.0f;
  83. int m_animation_frame = 0;
  84. ParticleSpawner *m_parent = nullptr;
  85. // Used if not spawned from a particlespawner
  86. std::unique_ptr<ClientParticleTexture> m_owned_texture;
  87. };
  88. class ParticleSpawner
  89. {
  90. public:
  91. ParticleSpawner(LocalPlayer *player,
  92. const ParticleSpawnerParameters &params,
  93. u16 attached_id,
  94. std::vector<ClientParticleTexture> &&texpool,
  95. ParticleManager *p_manager);
  96. void step(float dtime, ClientEnvironment *env);
  97. bool getExpired() const
  98. { return p.amount <= 0 && p.time != 0; }
  99. bool hasActive() const { return m_active != 0; }
  100. void decrActive() { m_active -= 1; }
  101. private:
  102. void spawnParticle(ClientEnvironment *env, float radius,
  103. const core::matrix4 *attached_absolute_pos_rot_matrix);
  104. size_t m_active;
  105. ParticleManager *m_particlemanager;
  106. float m_time;
  107. LocalPlayer *m_player;
  108. ParticleSpawnerParameters p;
  109. std::vector<ClientParticleTexture> m_texpool;
  110. std::vector<float> m_spawntimes;
  111. u16 m_attached_id;
  112. };
  113. class ParticleBuffer : public scene::ISceneNode
  114. {
  115. friend class ParticleManager;
  116. public:
  117. ParticleBuffer(ClientEnvironment *env, const video::SMaterial &material);
  118. // for pointer stability
  119. DISABLE_CLASS_COPY(ParticleBuffer)
  120. /// Reserves one more slot for a particle (4 vertices, 6 indices)
  121. /// @return particle index within buffer
  122. std::optional<u16> allocate();
  123. /// Frees the particle at `index`
  124. void release(u16 index);
  125. /// @return video::S3DVertex[4]
  126. video::S3DVertex *getVertices(u16 index);
  127. inline bool isEmpty() const {
  128. return m_free_list.size() == m_count;
  129. }
  130. virtual video::SMaterial &getMaterial(u32 num) override {
  131. return m_mesh_buffer->getMaterial();
  132. }
  133. virtual u32 getMaterialCount() const override {
  134. return 1;
  135. }
  136. virtual const core::aabbox3df &getBoundingBox() const override;
  137. virtual void render() override;
  138. virtual void OnRegisterSceneNode() override;
  139. // we have 16-bit indices
  140. static constexpr u16 MAX_PARTICLES_PER_BUFFER = 16000;
  141. private:
  142. irr_ptr<scene::SMeshBuffer> m_mesh_buffer;
  143. // unused (e.g. expired) particle indices for re-use
  144. std::vector<u16> m_free_list;
  145. // for automatic deletion when unused for a while. is reset on allocate().
  146. float m_usage_timer = 0;
  147. // total count of contained particles
  148. u16 m_count = 0;
  149. mutable bool m_bounding_box_dirty = true;
  150. };
  151. /**
  152. * Class doing particle as well as their spawners handling
  153. */
  154. class ParticleManager
  155. {
  156. friend class ParticleSpawner;
  157. public:
  158. ParticleManager(ClientEnvironment* env);
  159. DISABLE_CLASS_COPY(ParticleManager)
  160. ~ParticleManager();
  161. void step (float dtime);
  162. void handleParticleEvent(ClientEvent *event, Client *client,
  163. LocalPlayer *player);
  164. void addDiggingParticles(IGameDef *gamedef, LocalPlayer *player, v3s16 pos,
  165. const MapNode &n, const ContentFeatures &f);
  166. void addNodeParticle(IGameDef *gamedef, LocalPlayer *player, v3s16 pos,
  167. const MapNode &n, const ContentFeatures &f);
  168. void reserveParticleSpace(size_t max_estimate);
  169. /**
  170. * This function is only used by client particle spawners
  171. *
  172. * We don't need to check the particle spawner list because client ID will
  173. * never overlap (u64)
  174. * @return new id
  175. */
  176. u64 generateSpawnerId()
  177. {
  178. return m_next_particle_spawner_id++;
  179. }
  180. protected:
  181. static bool getNodeParticleParams(const MapNode &n, const ContentFeatures &f,
  182. ParticleParameters &p, video::ITexture **texture, v2f &texpos,
  183. v2f &texsize, video::SColor *color, u8 tilenum = 0);
  184. static video::SMaterial getMaterialForParticle(const Particle *texture);
  185. bool addParticle(std::unique_ptr<Particle> toadd);
  186. private:
  187. void addParticleSpawner(u64 id, std::unique_ptr<ParticleSpawner> toadd);
  188. void deleteParticleSpawner(u64 id);
  189. void stepParticles(float dtime);
  190. void stepSpawners(float dtime);
  191. void stepBuffers(float dtime);
  192. void clearAll();
  193. std::vector<std::unique_ptr<Particle>> m_particles;
  194. std::unordered_map<u64, std::unique_ptr<ParticleSpawner>> m_particle_spawners;
  195. std::vector<std::unique_ptr<ParticleSpawner>> m_dying_particle_spawners;
  196. std::vector<irr_ptr<ParticleBuffer>> m_particle_buffers;
  197. // Start the particle spawner ids generated from here after u32_max.
  198. // lower values are for server sent spawners.
  199. u64 m_next_particle_spawner_id = static_cast<u64>(U32_MAX) + 1;
  200. ClientEnvironment *m_env;
  201. IntervalLimiter m_buffer_gc;
  202. std::mutex m_particle_list_lock;
  203. std::mutex m_spawner_list_lock;
  204. };