3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
20 #include "particles.h"
21 #include "constants.h"
23 #include "main.h" // For g_profiler and g_settings
27 #include "collision.h"
29 #include "util/numeric.h"
31 #include "environment.h"
32 #include "clientmap.h"
39 v3f random_v3f(v3f min, v3f max)
41 return v3f( rand()/(float)RAND_MAX*(max.X-min.X)+min.X,
42 rand()/(float)RAND_MAX*(max.Y-min.Y)+min.Y,
43 rand()/(float)RAND_MAX*(max.Z-min.Z)+min.Z);
46 std::vector<Particle*> all_particles;
47 std::map<u32, ParticleSpawner*> all_particlespawners;
51 scene::ISceneManager* smgr,
53 ClientEnvironment &env,
59 bool collisiondetection,
60 video::ITexture *texture,
64 scene::ISceneNode(smgr->getRootSceneNode(), smgr)
70 m_material.setFlag(video::EMF_LIGHTING, false);
71 m_material.setFlag(video::EMF_BACK_FACE_CULLING, false);
72 m_material.setFlag(video::EMF_BILINEAR_FILTER, false);
73 m_material.setFlag(video::EMF_FOG_ENABLE, true);
74 m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
75 m_material.setTexture(0, texture);
82 m_velocity = velocity;
83 m_acceleration = acceleration;
84 m_expiration = expirationtime;
88 m_collisiondetection = collisiondetection;
91 m_collisionbox = core::aabbox3d<f32>
92 (-size/2,-size/2,-size/2,size/2,size/2,size/2);
93 this->setAutomaticCulling(scene::EAC_OFF);
101 all_particles.push_back(this);
104 Particle::~Particle()
108 void Particle::OnRegisterSceneNode()
112 SceneManager->registerNodeForRendering
113 (this, scene::ESNRP_TRANSPARENT);
114 SceneManager->registerNodeForRendering
115 (this, scene::ESNRP_SOLID);
118 ISceneNode::OnRegisterSceneNode();
121 void Particle::render()
123 // TODO: Render particles in front of water and the selectionbox
125 video::IVideoDriver* driver = SceneManager->getVideoDriver();
126 driver->setMaterial(m_material);
127 driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
129 u16 indices[] = {0,1,2, 2,3,0};
130 driver->drawVertexPrimitiveList(m_vertices, 4,
131 indices, 2, video::EVT_STANDARD,
132 scene::EPT_TRIANGLES, video::EIT_16BIT);
135 void Particle::step(float dtime, ClientEnvironment &env)
138 if (m_collisiondetection)
140 core::aabbox3d<f32> box = m_collisionbox;
141 v3f p_pos = m_pos*BS;
142 v3f p_velocity = m_velocity*BS;
143 v3f p_acceleration = m_acceleration*BS;
144 collisionMoveSimple(&env, m_gamedef,
147 p_pos, p_velocity, p_acceleration);
149 m_velocity = p_velocity/BS;
150 m_acceleration = p_acceleration/BS;
154 m_velocity += m_acceleration * dtime;
155 m_pos += m_velocity * dtime;
165 void Particle::updateLight(ClientEnvironment &env)
174 MapNode n = env.getClientMap().getNode(p);
175 light = n.getLightBlend(env.getDayNightRatio(), m_gamedef->ndef());
177 catch(InvalidPositionException &e){
178 light = blend_light(env.getDayNightRatio(), LIGHT_SUN, 0);
180 m_light = decode_light(light);
183 void Particle::updateVertices()
185 video::SColor c(255, m_light, m_light, m_light);
186 f32 tx0 = m_texpos.X;
187 f32 tx1 = m_texpos.X + m_texsize.X;
188 f32 ty0 = m_texpos.Y;
189 f32 ty1 = m_texpos.Y + m_texsize.Y;
191 m_vertices[0] = video::S3DVertex(-m_size/2,-m_size/2,0, 0,0,0,
193 m_vertices[1] = video::S3DVertex(m_size/2,-m_size/2,0, 0,0,0,
195 m_vertices[2] = video::S3DVertex(m_size/2,m_size/2,0, 0,0,0,
197 m_vertices[3] = video::S3DVertex(-m_size/2,m_size/2,0, 0,0,0,
200 for(u16 i=0; i<4; i++)
202 m_vertices[i].Pos.rotateYZBy(m_player->getPitch());
203 m_vertices[i].Pos.rotateXZBy(m_player->getYaw());
204 m_box.addInternalPoint(m_vertices[i].Pos);
205 m_vertices[i].Pos += m_pos*BS;
215 void allparticles_step (float dtime, ClientEnvironment &env)
217 for(std::vector<Particle*>::iterator i = all_particles.begin();
218 i != all_particles.end();)
220 if ((*i)->get_expired())
224 all_particles.erase(i);
228 (*i)->step(dtime, env);
234 void addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
235 LocalPlayer *player, ClientEnvironment &env, v3s16 pos,
236 const TileSpec tiles[])
238 for (u16 j = 0; j < 32; j++) // set the amount of particles here
240 addNodeParticle(gamedef, smgr, player, env, pos, tiles);
244 void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
245 LocalPlayer *player, ClientEnvironment &env,
246 v3s16 pos, const TileSpec tiles[])
248 addNodeParticle(gamedef, smgr, player, env, pos, tiles);
251 // add a particle of a node
252 // used by digging and punching particles
253 void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr,
254 LocalPlayer *player, ClientEnvironment &env, v3s16 pos,
255 const TileSpec tiles[])
258 u8 texid = myrand_range(0,5);
259 video::ITexture *texture = tiles[texid].texture;
261 // Only use first frame of animated texture
263 if(tiles[texid].material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
264 ymax /= tiles[texid].animation_frame_count;
266 float size = rand()%64/512.;
267 float visual_size = BS*size;
268 v2f texsize(size*2, ymax*size*2);
270 texpos.X = ((rand()%64)/64.-texsize.X);
271 texpos.Y = ymax*((rand()%64)/64.-texsize.Y);
274 v3f velocity( (rand()%100/50.-1)/1.5,
276 (rand()%100/50.-1)/1.5);
278 v3f acceleration(0,-9,0);
279 v3f particlepos = v3f(
280 (f32)pos.X+rand()%100/200.-0.25,
281 (f32)pos.Y+rand()%100/200.-0.25,
282 (f32)pos.Z+rand()%100/200.-0.25
293 rand()%100/100., // expiration time
305 ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr, LocalPlayer *player,
306 u16 amount, float time,
307 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
308 float minexptime, float maxexptime, float minsize, float maxsize,
309 bool collisiondetection, video::ITexture *texture, u32 id)
322 m_minexptime = minexptime;
323 m_maxexptime = maxexptime;
326 m_collisiondetection = collisiondetection;
330 for (u16 i = 0; i<=m_amount; i++)
332 float spawntime = (float)rand()/(float)RAND_MAX*m_spawntime;
333 m_spawntimes.push_back(spawntime);
336 all_particlespawners.insert(std::pair<u32, ParticleSpawner*>(id, this));
339 ParticleSpawner::~ParticleSpawner() {}
341 void ParticleSpawner::step(float dtime, ClientEnvironment &env)
345 if (m_spawntime != 0) // Spawner exists for a predefined timespan
347 for(std::vector<float>::iterator i = m_spawntimes.begin();
348 i != m_spawntimes.end();)
350 if ((*i) <= m_time && m_amount > 0)
354 v3f pos = random_v3f(m_minpos, m_maxpos);
355 v3f vel = random_v3f(m_minvel, m_maxvel);
356 v3f acc = random_v3f(m_minacc, m_maxacc);
357 float exptime = rand()/(float)RAND_MAX
358 *(m_maxexptime-m_minexptime)
360 float size = rand()/(float)RAND_MAX
361 *(m_maxsize-m_minsize)
374 m_collisiondetection,
378 m_spawntimes.erase(i);
386 else // Spawner exists for an infinity timespan, spawn on a per-second base
388 for (int i = 0; i <= m_amount; i++)
390 if (rand()/(float)RAND_MAX < dtime)
392 v3f pos = random_v3f(m_minpos, m_maxpos);
393 v3f vel = random_v3f(m_minvel, m_maxvel);
394 v3f acc = random_v3f(m_minacc, m_maxacc);
395 float exptime = rand()/(float)RAND_MAX
396 *(m_maxexptime-m_minexptime)
398 float size = rand()/(float)RAND_MAX
399 *(m_maxsize-m_minsize)
412 m_collisiondetection,
421 void allparticlespawners_step (float dtime, ClientEnvironment &env)
423 for(std::map<u32, ParticleSpawner*>::iterator i =
424 all_particlespawners.begin();
425 i != all_particlespawners.end();)
427 if (i->second->get_expired())
430 all_particlespawners.erase(i++);
434 i->second->step(dtime, env);
440 void delete_particlespawner (u32 id)
442 if (all_particlespawners.find(id) != all_particlespawners.end())
444 delete all_particlespawners.find(id)->second;
445 all_particlespawners.erase(id);
449 void clear_particles ()
451 for(std::map<u32, ParticleSpawner*>::iterator i =
452 all_particlespawners.begin();
453 i != all_particlespawners.end();)
456 all_particlespawners.erase(i++);
459 for(std::vector<Particle*>::iterator i =
460 all_particles.begin();
461 i != all_particles.end();)
465 all_particles.erase(i);