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,
62 scene::ISceneNode(smgr->getRootSceneNode(), smgr)
68 m_material.setFlag(video::EMF_LIGHTING, false);
69 m_material.setFlag(video::EMF_BACK_FACE_CULLING, false);
70 m_material.setFlag(video::EMF_BILINEAR_FILTER, false);
71 m_material.setFlag(video::EMF_FOG_ENABLE, true);
72 m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
73 m_material.setTexture(0, ap.atlas);
79 m_velocity = velocity;
80 m_acceleration = acceleration;
81 m_expiration = expirationtime;
85 m_collisiondetection = collisiondetection;
88 m_collisionbox = core::aabbox3d<f32>
89 (-size/2,-size/2,-size/2,size/2,size/2,size/2);
90 this->setAutomaticCulling(scene::EAC_OFF);
98 all_particles.push_back(this);
101 Particle::~Particle()
105 void Particle::OnRegisterSceneNode()
109 SceneManager->registerNodeForRendering
110 (this, scene::ESNRP_TRANSPARENT);
111 SceneManager->registerNodeForRendering
112 (this, scene::ESNRP_SOLID);
115 ISceneNode::OnRegisterSceneNode();
118 void Particle::render()
120 // TODO: Render particles in front of water and the selectionbox
122 video::IVideoDriver* driver = SceneManager->getVideoDriver();
123 driver->setMaterial(m_material);
124 driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
126 u16 indices[] = {0,1,2, 2,3,0};
127 driver->drawVertexPrimitiveList(m_vertices, 4,
128 indices, 2, video::EVT_STANDARD,
129 scene::EPT_TRIANGLES, video::EIT_16BIT);
132 void Particle::step(float dtime, ClientEnvironment &env)
135 if (m_collisiondetection)
137 core::aabbox3d<f32> box = m_collisionbox;
138 v3f p_pos = m_pos*BS;
139 v3f p_velocity = m_velocity*BS;
140 v3f p_acceleration = m_acceleration*BS;
141 collisionMoveSimple(&env, m_gamedef,
144 p_pos, p_velocity, p_acceleration);
146 m_velocity = p_velocity/BS;
147 m_acceleration = p_acceleration/BS;
151 m_velocity += m_acceleration * dtime;
152 m_pos += m_velocity * dtime;
162 void Particle::updateLight(ClientEnvironment &env)
171 MapNode n = env.getClientMap().getNode(p);
172 light = n.getLightBlend(env.getDayNightRatio(), m_gamedef->ndef());
174 catch(InvalidPositionException &e){
175 light = blend_light(env.getDayNightRatio(), LIGHT_SUN, 0);
177 m_light = decode_light(light);
180 void Particle::updateVertices()
182 video::SColor c(255, m_light, m_light, m_light);
183 m_vertices[0] = video::S3DVertex(-m_size/2,-m_size/2,0, 0,0,0,
184 c, m_ap.x0(), m_ap.y1());
185 m_vertices[1] = video::S3DVertex(m_size/2,-m_size/2,0, 0,0,0,
186 c, m_ap.x1(), m_ap.y1());
187 m_vertices[2] = video::S3DVertex(m_size/2,m_size/2,0, 0,0,0,
188 c, m_ap.x1(), m_ap.y0());
189 m_vertices[3] = video::S3DVertex(-m_size/2,m_size/2,0, 0,0,0,
190 c ,m_ap.x0(), m_ap.y0());
192 for(u16 i=0; i<4; i++)
194 m_vertices[i].Pos.rotateYZBy(m_player->getPitch());
195 m_vertices[i].Pos.rotateXZBy(m_player->getYaw());
196 m_box.addInternalPoint(m_vertices[i].Pos);
197 m_vertices[i].Pos += m_pos*BS;
207 void allparticles_step (float dtime, ClientEnvironment &env)
209 for(std::vector<Particle*>::iterator i = all_particles.begin();
210 i != all_particles.end();)
212 if ((*i)->get_expired())
216 all_particles.erase(i);
220 (*i)->step(dtime, env);
226 void addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
227 LocalPlayer *player, ClientEnvironment &env, v3s16 pos,
228 const TileSpec tiles[])
230 for (u16 j = 0; j < 32; j++) // set the amount of particles here
232 addNodeParticle(gamedef, smgr, player, env, pos, tiles);
236 void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
237 LocalPlayer *player, ClientEnvironment &env,
238 v3s16 pos, const TileSpec tiles[])
240 addNodeParticle(gamedef, smgr, player, env, pos, tiles);
243 // add a particle of a node
244 // used by digging and punching particles
245 void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr,
246 LocalPlayer *player, ClientEnvironment &env, v3s16 pos,
247 const TileSpec tiles[])
250 u8 texid = myrand_range(0,5);
251 AtlasPointer ap = tiles[texid].texture;
252 float size = rand()%64/512.;
253 float visual_size = BS*size;
254 float texsize = size*2;
259 ap.size.X = (ap.x1() - ap.x0()) * texsize;
260 ap.size.Y = (ap.x1() - ap.x0()) * texsize;
262 ap.pos.X = ap.x0() + (x1 - ap.x0()) * ((rand()%64)/64.-texsize);
263 ap.pos.Y = ap.y0() + (y1 - ap.y0()) * ((rand()%64)/64.-texsize);
266 v3f velocity( (rand()%100/50.-1)/1.5,
268 (rand()%100/50.-1)/1.5);
270 v3f acceleration(0,-9,0);
271 v3f particlepos = v3f(
272 (f32)pos.X+rand()%100/200.-0.25,
273 (f32)pos.Y+rand()%100/200.-0.25,
274 (f32)pos.Z+rand()%100/200.-0.25
285 rand()%100/100., // expiration time
295 ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr, LocalPlayer *player,
296 u16 amount, float time,
297 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
298 float minexptime, float maxexptime, float minsize, float maxsize,
299 bool collisiondetection, AtlasPointer ap, u32 id)
312 m_minexptime = minexptime;
313 m_maxexptime = maxexptime;
316 m_collisiondetection = collisiondetection;
320 for (u16 i = 0; i<=m_amount; i++)
322 float spawntime = (float)rand()/(float)RAND_MAX*m_spawntime;
323 m_spawntimes.push_back(spawntime);
326 all_particlespawners.insert(std::pair<u32, ParticleSpawner*>(id, this));
329 ParticleSpawner::~ParticleSpawner() {}
331 void ParticleSpawner::step(float dtime, ClientEnvironment &env)
335 if (m_spawntime != 0) // Spawner exists for a predefined timespan
337 for(std::vector<float>::iterator i = m_spawntimes.begin();
338 i != m_spawntimes.end();)
340 if ((*i) <= m_time && m_amount > 0)
344 v3f pos = random_v3f(m_minpos, m_maxpos);
345 v3f vel = random_v3f(m_minvel, m_maxvel);
346 v3f acc = random_v3f(m_minacc, m_maxacc);
347 float exptime = rand()/(float)RAND_MAX
348 *(m_maxexptime-m_minexptime)
350 float size = rand()/(float)RAND_MAX
351 *(m_maxsize-m_minsize)
364 m_collisiondetection,
366 m_spawntimes.erase(i);
374 else // Spawner exists for an infinity timespan, spawn on a per-second base
376 for (int i = 0; i <= m_amount; i++)
378 if (rand()/(float)RAND_MAX < dtime)
380 v3f pos = random_v3f(m_minpos, m_maxpos);
381 v3f vel = random_v3f(m_minvel, m_maxvel);
382 v3f acc = random_v3f(m_minacc, m_maxacc);
383 float exptime = rand()/(float)RAND_MAX
384 *(m_maxexptime-m_minexptime)
386 float size = rand()/(float)RAND_MAX
387 *(m_maxsize-m_minsize)
400 m_collisiondetection,
407 void allparticlespawners_step (float dtime, ClientEnvironment &env)
409 for(std::map<u32, ParticleSpawner*>::iterator i =
410 all_particlespawners.begin();
411 i != all_particlespawners.end();)
413 if (i->second->get_expired())
416 all_particlespawners.erase(i++);
420 i->second->step(dtime, env);
426 void delete_particlespawner (u32 id)
428 if (all_particlespawners.find(id) != all_particlespawners.end())
430 delete all_particlespawners.find(id)->second;
431 all_particlespawners.erase(id);
435 void clear_particles ()
437 for(std::map<u32, ParticleSpawner*>::iterator i =
438 all_particlespawners.begin();
439 i != all_particlespawners.end();)
442 all_particlespawners.erase(i++);
445 for(std::vector<Particle*>::iterator i =
446 all_particles.begin();
447 i != all_particles.end();)
451 all_particles.erase(i);