aboutsummaryrefslogtreecommitdiff
path: root/src/client/particles.h
blob: 36be903f1a6100f1515cc5524aee9397bd14c204 (plain)
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#pragma once

#include <iostream>
#include "irrlichttypes_extrabloated.h"
#include "client/tile.h"
#include "localplayer.h"
#include "../particles.h"

struct ClientEvent;
class ParticleManager;
class ClientEnvironment;
struct MapNode;
struct ContentFeatures;

struct ClientTexture
{
	/* per-spawner structure used to store the ParticleTexture structs
	 * that spawned particles will refer to through ClientTexRef */
	ParticleTexture tex;
	video::ITexture *ref = nullptr;

	ClientTexture() = default;
	ClientTexture(const ClientTexture&) = default;
	ClientTexture(const ServerParticleTexture& p, ITextureSource *t):
			tex(p),
			ref(t->getTextureForMesh(p.string)) {};
};

struct ClientTexRef
{
	/* per-particle structure used to avoid massively duplicating the
	 * fairly large ParticleTexture struct */
	ParticleTexture* tex = nullptr;
	video::ITexture* ref = nullptr;
	ClientTexRef() = default;
	ClientTexRef(const ClientTexRef&) = default;

	/* constructor used by particles spawned from a spawner */
	ClientTexRef(ClientTexture& t):
			tex(&t.tex), ref(t.ref) {};

	/* constructor used for node particles */
	ClientTexRef(decltype(ref) tp): ref(tp) {};
};

class ParticleSpawner;

class Particle : public scene::ISceneNode
{
public:
	Particle(
		IGameDef *gamedef,
		LocalPlayer *player,
		ClientEnvironment *env,
		const ParticleParameters &p,
		const ClientTexRef &texture,
		v2f texpos,
		v2f texsize,
		video::SColor color
	);
	~Particle();

	virtual const aabb3f &getBoundingBox() const
	{
		return m_box;
	}

	virtual u32 getMaterialCount() const
	{
		return 1;
	}

	virtual video::SMaterial& getMaterial(u32 i)
	{
		return m_material;
	}

	virtual void OnRegisterSceneNode();
	virtual void render();

	void step(float dtime);

	bool get_expired ()
	{ return m_expiration < m_time; }

	ParticleSpawner *m_parent;

private:
	void updateLight();
	void updateVertices();
	void setVertexAlpha(float a);

	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;
	ClientTexRef m_texture;
	video::SMaterial m_material;
	v2f m_texpos;
	v2f m_texsize;
	v3f m_pos;
	v3f m_velocity;
	v3f m_acceleration;
	v3f m_drag;
	ParticleParamTypes::v3fRange m_jitter;
	ParticleParamTypes::f32Range m_bounce;
	LocalPlayer *m_player;
	float m_size;

	//! Color without lighting
	video::SColor m_base_color;
	//! Final rendered color
	video::SColor m_color;
	bool m_collisiondetection;
	bool m_collision_removal;
	bool m_object_collision;
	bool m_vertical;
	v3s16 m_camera_offset;
	struct TileAnimationParams m_animation;
	float m_animation_time = 0.0f;
	int m_animation_frame = 0;
	u8 m_glow;
	float m_alpha = 0.0f;
};

class ParticleSpawner
{
public:
	ParticleSpawner(IGameDef *gamedef,
		LocalPlayer *player,
		const ParticleSpawnerParameters &p,
		u16 attached_id,
		std::unique_ptr<ClientTexture[]> &texpool,
		size_t texcount,
		ParticleManager* p_manager);

	void step(float dtime, ClientEnvironment *env);

	size_t m_active;

	bool getExpired() const
	{ return m_dying || (p.amount <= 0 && p.time != 0); }
	void setDying() { m_dying = true; }

private:
	void spawnParticle(ClientEnvironment *env, float radius,
		const core::matrix4 *attached_absolute_pos_rot_matrix);

	ParticleManager *m_particlemanager;
	float m_time;
	bool m_dying;
	IGameDef *m_gamedef;
	LocalPlayer *m_player;
	ParticleSpawnerParameters p;
	std::unique_ptr<ClientTexture[]> m_texpool;
	size_t m_texcount;
	std::vector<float> m_spawntimes;
	u16 m_attached_id;
};

/**
 * Class doing particle as well as their spawners handling
 */
class ParticleManager
{
friend class ParticleSpawner;
public:
	ParticleManager(ClientEnvironment* env);
	~ParticleManager();

	void step (float dtime);

	void handleParticleEvent(ClientEvent *event, Client *client,
			LocalPlayer *player);

	void addDiggingParticles(IGameDef *gamedef, LocalPlayer *player, v3s16 pos,
		const MapNode &n, const ContentFeatures &f);

	void addNodeParticle(IGameDef *gamedef, LocalPlayer *player, v3s16 pos,
		const MapNode &n, const ContentFeatures &f);

	void reserveParticleSpace(size_t max_estimate);

	/**
	 * This function is only used by client particle spawners
	 *
	 * We don't need to check the particle spawner list because client ID will
	 * never overlap (u64)
	 * @return new id
	 */
	u64 generateSpawnerId()
	{
		return m_next_particle_spawner_id++;
	}

protected:
	static bool getNodeParticleParams(const MapNode &n, const ContentFeatures &f,
		ParticleParameters &p, video::ITexture **texture, v2f &texpos,
		v2f &texsize, video::SColor *color, u8 tilenum = 0);

	void addParticle(Particle* toadd);

private:
	void addParticleSpawner(u64 id, ParticleSpawner *toadd);
	void deleteParticleSpawner(u64 id);

	void stepParticles(float dtime);
	void stepSpawners(float dtime);

	void clearAll();

	std::vector<Particle*> m_particles;
	std::unordered_map<u64, ParticleSpawner*> m_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;

	ClientEnvironment* m_env;
	std::mutex m_particle_list_lock;
	std::mutex m_spawner_list_lock;
};