1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14 
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 
20 #pragma once
21 
22 #include <iostream>
23 #include "irrlichttypes_extrabloated.h"
24 #include "client/tile.h"
25 #include "localplayer.h"
26 #include "../particles.h"
27 
28 struct ClientEvent;
29 class ParticleManager;
30 class ClientEnvironment;
31 struct MapNode;
32 struct ContentFeatures;
33 
34 class Particle : public scene::ISceneNode
35 {
36 	public:
37 	Particle(
38 		IGameDef* gamedef,
39 		LocalPlayer *player,
40 		ClientEnvironment *env,
41 		const ParticleParameters &p,
42 		video::ITexture *texture,
43 		v2f texpos,
44 		v2f texsize,
45 		video::SColor color
46 	);
47 	~Particle() = default;
48 
getBoundingBox()49 	virtual const aabb3f &getBoundingBox() const
50 	{
51 		return m_box;
52 	}
53 
getMaterialCount()54 	virtual u32 getMaterialCount() const
55 	{
56 		return 1;
57 	}
58 
getMaterial(u32 i)59 	virtual video::SMaterial& getMaterial(u32 i)
60 	{
61 		return m_material;
62 	}
63 
64 	virtual void OnRegisterSceneNode();
65 	virtual void render();
66 
67 	void step(float dtime);
68 
get_expired()69 	bool get_expired ()
70 	{ return m_expiration < m_time; }
71 
72 private:
73 	void updateLight();
74 	void updateVertices();
75 
76 	video::S3DVertex m_vertices[4];
77 	float m_time = 0.0f;
78 	float m_expiration;
79 
80 	ClientEnvironment *m_env;
81 	IGameDef *m_gamedef;
82 	aabb3f m_box;
83 	aabb3f m_collisionbox;
84 	video::SMaterial m_material;
85 	v2f m_texpos;
86 	v2f m_texsize;
87 	v3f m_pos;
88 	v3f m_velocity;
89 	v3f m_acceleration;
90 	LocalPlayer *m_player;
91 	float m_size;
92 	//! Color without lighting
93 	video::SColor m_base_color;
94 	//! Final rendered color
95 	video::SColor m_color;
96 	bool m_collisiondetection;
97 	bool m_collision_removal;
98 	bool m_object_collision;
99 	bool m_vertical;
100 	v3s16 m_camera_offset;
101 	struct TileAnimationParams m_animation;
102 	float m_animation_time = 0.0f;
103 	int m_animation_frame = 0;
104 	u8 m_glow;
105 };
106 
107 class ParticleSpawner
108 {
109 public:
110 	ParticleSpawner(IGameDef* gamedef,
111 		LocalPlayer *player,
112 		const ParticleSpawnerParameters &p,
113 		u16 attached_id,
114 		video::ITexture *texture,
115 		ParticleManager* p_manager);
116 
117 	~ParticleSpawner() = default;
118 
119 	void step(float dtime, ClientEnvironment *env);
120 
get_expired()121 	bool get_expired ()
122 	{ return p.amount <= 0 && p.time != 0; }
123 
124 private:
125 	void spawnParticle(ClientEnvironment *env, float radius,
126 		const core::matrix4 *attached_absolute_pos_rot_matrix);
127 
128 	ParticleManager *m_particlemanager;
129 	float m_time;
130 	IGameDef *m_gamedef;
131 	LocalPlayer *m_player;
132 	ParticleSpawnerParameters p;
133 	video::ITexture *m_texture;
134 	std::vector<float> m_spawntimes;
135 	u16 m_attached_id;
136 };
137 
138 /**
139  * Class doing particle as well as their spawners handling
140  */
141 class ParticleManager
142 {
143 friend class ParticleSpawner;
144 public:
145 	ParticleManager(ClientEnvironment* env);
146 	~ParticleManager();
147 
148 	void step (float dtime);
149 
150 	void handleParticleEvent(ClientEvent *event, Client *client,
151 			LocalPlayer *player);
152 
153 	void addDiggingParticles(IGameDef *gamedef, LocalPlayer *player, v3s16 pos,
154 		const MapNode &n, const ContentFeatures &f);
155 
156 	void addNodeParticle(IGameDef *gamedef, LocalPlayer *player, v3s16 pos,
157 		const MapNode &n, const ContentFeatures &f);
158 
159 	/**
160 	 * This function is only used by client particle spawners
161 	 *
162 	 * We don't need to check the particle spawner list because client ID will
163 	 * never overlap (u64)
164 	 * @return new id
165 	 */
generateSpawnerId()166 	u64 generateSpawnerId()
167 	{
168 		return m_next_particle_spawner_id++;
169 	}
170 
171 protected:
172 	static bool getNodeParticleParams(const MapNode &n, const ContentFeatures &f,
173 		ParticleParameters &p, video::ITexture **texture, v2f &texpos,
174 		v2f &texsize, video::SColor *color, u8 tilenum = 0);
175 
176 	void addParticle(Particle* toadd);
177 
178 private:
179 	void addParticleSpawner(u64 id, ParticleSpawner *toadd);
180 	void deleteParticleSpawner(u64 id);
181 
182 	void stepParticles(float dtime);
183 	void stepSpawners(float dtime);
184 
185 	void clearAll();
186 
187 	std::vector<Particle*> m_particles;
188 	std::unordered_map<u64, ParticleSpawner*> m_particle_spawners;
189 	// Start the particle spawner ids generated from here after u32_max. lower values are
190 	// for server sent spawners.
191 	u64 m_next_particle_spawner_id = U32_MAX + 1;
192 
193 	ClientEnvironment* m_env;
194 	std::mutex m_particle_list_lock;
195 	std::mutex m_spawner_list_lock;
196 };
197