X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fparticles.cpp;h=e1f292fb60cf567cb7270a90d8a576fd160cf8c3;hb=3ad68c052bb4d58892b4d1e8cd6be59ea860df8f;hp=1d814f6191513676f76af074f93d82cb947c3d2e;hpb=8800896824d609c754eee38d3720a112f4216e57;p=dragonfireclient.git diff --git a/src/particles.cpp b/src/particles.cpp index 1d814f619..e1f292fb6 100644 --- a/src/particles.cpp +++ b/src/particles.cpp @@ -18,12 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "particles.h" -#include "constants.h" -#include "debug.h" -#include "main.h" // For g_profiler and g_settings -#include "settings.h" -#include "tile.h" -#include "gamedef.h" +#include "client.h" #include "collision.h" #include #include "util/numeric.h" @@ -31,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "environment.h" #include "clientmap.h" #include "mapnode.h" +#include "client.h" /* Utility @@ -43,26 +39,31 @@ v3f random_v3f(v3f min, v3f max) rand()/(float)RAND_MAX*(max.Z-min.Z)+min.Z); } -std::vector all_particles; -std::map all_particlespawners; - Particle::Particle( IGameDef *gamedef, scene::ISceneManager* smgr, LocalPlayer *player, - ClientEnvironment &env, + ClientEnvironment *env, v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, - AtlasPointer ap + bool collision_removal, + bool vertical, + video::ITexture *texture, + v2f texpos, + v2f texsize, + const struct TileAnimationParams &anim, + u8 glow, + video::SColor color ): scene::ISceneNode(smgr->getRootSceneNode(), smgr) { // Misc m_gamedef = gamedef; + m_env = env; // Texture m_material.setFlag(video::EMF_LIGHTING, false); @@ -70,9 +71,16 @@ Particle::Particle( m_material.setFlag(video::EMF_BILINEAR_FILTER, false); m_material.setFlag(video::EMF_FOG_ENABLE, true); m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; - m_material.setTexture(0, ap.atlas); - m_ap = ap; + m_material.setTexture(0, texture); + m_texpos = texpos; + m_texsize = texsize; + m_animation = anim; + m_animation_frame = 0; + m_animation_time = 0.0; + // Color + m_base_color = color; + m_color = color; // Particle related m_pos = pos; @@ -83,19 +91,20 @@ Particle::Particle( m_player = player; m_size = size; m_collisiondetection = collisiondetection; + m_collision_removal = collision_removal; + m_vertical = vertical; + m_glow = glow; // Irrlicht stuff - m_collisionbox = core::aabbox3d + m_collisionbox = aabb3f (-size/2,-size/2,-size/2,size/2,size/2,size/2); this->setAutomaticCulling(scene::EAC_OFF); // Init lighting - updateLight(env); + updateLight(); // Init model updateVertices(); - - all_particles.push_back(this); } Particle::~Particle() @@ -105,20 +114,13 @@ Particle::~Particle() void Particle::OnRegisterSceneNode() { if (IsVisible) - { - SceneManager->registerNodeForRendering - (this, scene::ESNRP_TRANSPARENT); - SceneManager->registerNodeForRendering - (this, scene::ESNRP_SOLID); - } + SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT_EFFECT); ISceneNode::OnRegisterSceneNode(); } void Particle::render() { - // TODO: Render particles in front of water and the selectionbox - video::IVideoDriver* driver = SceneManager->getVideoDriver(); driver->setMaterial(m_material); driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); @@ -129,165 +131,117 @@ void Particle::render() scene::EPT_TRIANGLES, video::EIT_16BIT); } -void Particle::step(float dtime, ClientEnvironment &env) +void Particle::step(float dtime) { m_time += dtime; - if (m_collisiondetection) - { - core::aabbox3d box = m_collisionbox; - v3f p_pos = m_pos*BS; - v3f p_velocity = m_velocity*BS; - v3f p_acceleration = m_acceleration*BS; - collisionMoveSimple(&env, m_gamedef, - BS*0.5, box, - 0, dtime, - p_pos, p_velocity, p_acceleration); - m_pos = p_pos/BS; - m_velocity = p_velocity/BS; - m_acceleration = p_acceleration/BS; - } - else - { + if (m_collisiondetection) { + aabb3f box = m_collisionbox; + v3f p_pos = m_pos * BS; + v3f p_velocity = m_velocity * BS; + collisionMoveResult r = collisionMoveSimple(m_env, + m_gamedef, BS * 0.5, box, 0, dtime, &p_pos, + &p_velocity, m_acceleration * BS); + if (m_collision_removal && r.collides) { + // force expiration of the particle + m_expiration = -1.0; + } else { + m_pos = p_pos / BS; + m_velocity = p_velocity / BS; + } + } else { m_velocity += m_acceleration * dtime; m_pos += m_velocity * dtime; } + if (m_animation.type != TAT_NONE) { + m_animation_time += dtime; + int frame_length_i, frame_count; + m_animation.determineParams( + m_material.getTexture(0)->getSize(), + &frame_count, &frame_length_i, NULL); + float frame_length = frame_length_i / 1000.0; + while (m_animation_time > frame_length) { + m_animation_frame++; + m_animation_time -= frame_length; + } + } // Update lighting - updateLight(env); + updateLight(); // Update model updateVertices(); } -void Particle::updateLight(ClientEnvironment &env) +void Particle::updateLight() { u8 light = 0; - try{ - v3s16 p = v3s16( - floor(m_pos.X+0.5), - floor(m_pos.Y+0.5), - floor(m_pos.Z+0.5) - ); - MapNode n = env.getClientMap().getNode(p); - light = n.getLightBlend(env.getDayNightRatio(), m_gamedef->ndef()); - } - catch(InvalidPositionException &e){ - light = blend_light(env.getDayNightRatio(), LIGHT_SUN, 0); - } - m_light = decode_light(light); + bool pos_ok; + + v3s16 p = v3s16( + floor(m_pos.X+0.5), + floor(m_pos.Y+0.5), + floor(m_pos.Z+0.5) + ); + MapNode n = m_env->getClientMap().getNodeNoEx(p, &pos_ok); + if (pos_ok) + light = n.getLightBlend(m_env->getDayNightRatio(), m_gamedef->ndef()); + else + light = blend_light(m_env->getDayNightRatio(), LIGHT_SUN, 0); + + u8 m_light = decode_light(light + m_glow); + m_color.set(255, + m_light * m_base_color.getRed() / 255, + m_light * m_base_color.getGreen() / 255, + m_light * m_base_color.getBlue() / 255); } void Particle::updateVertices() { - video::SColor c(255, m_light, m_light, m_light); - m_vertices[0] = video::S3DVertex(-m_size/2,-m_size/2,0, 0,0,0, - c, m_ap.x0(), m_ap.y1()); - m_vertices[1] = video::S3DVertex(m_size/2,-m_size/2,0, 0,0,0, - c, m_ap.x1(), m_ap.y1()); - m_vertices[2] = video::S3DVertex(m_size/2,m_size/2,0, 0,0,0, - c, m_ap.x1(), m_ap.y0()); - m_vertices[3] = video::S3DVertex(-m_size/2,m_size/2,0, 0,0,0, - c ,m_ap.x0(), m_ap.y0()); - - for(u16 i=0; i<4; i++) - { - m_vertices[i].Pos.rotateYZBy(m_player->getPitch()); - m_vertices[i].Pos.rotateXZBy(m_player->getYaw()); - m_box.addInternalPoint(m_vertices[i].Pos); - m_vertices[i].Pos += m_pos*BS; + f32 tx0, tx1, ty0, ty1; + + if (m_animation.type != TAT_NONE) { + const v2u32 texsize = m_material.getTexture(0)->getSize(); + v2f texcoord, framesize_f; + v2u32 framesize; + texcoord = m_animation.getTextureCoords(texsize, m_animation_frame); + m_animation.determineParams(texsize, NULL, NULL, &framesize); + framesize_f = v2f(framesize.X / (float) texsize.X, framesize.Y / (float) texsize.Y); + + tx0 = m_texpos.X + texcoord.X; + tx1 = m_texpos.X + texcoord.X + framesize_f.X * m_texsize.X; + ty0 = m_texpos.Y + texcoord.Y; + ty1 = m_texpos.Y + texcoord.Y + framesize_f.Y * m_texsize.Y; + } else { + tx0 = m_texpos.X; + tx1 = m_texpos.X + m_texsize.X; + ty0 = m_texpos.Y; + ty1 = m_texpos.Y + m_texsize.Y; } -} - - -/* - Helpers -*/ + m_vertices[0] = video::S3DVertex(-m_size / 2, -m_size / 2, + 0, 0, 0, 0, m_color, tx0, ty1); + m_vertices[1] = video::S3DVertex(m_size / 2, -m_size / 2, + 0, 0, 0, 0, m_color, tx1, ty1); + m_vertices[2] = video::S3DVertex(m_size / 2, m_size / 2, + 0, 0, 0, 0, m_color, tx1, ty0); + m_vertices[3] = video::S3DVertex(-m_size / 2, m_size / 2, + 0, 0, 0, 0, m_color, tx0, ty0); -void allparticles_step (float dtime, ClientEnvironment &env) -{ - for(std::vector::iterator i = all_particles.begin(); - i != all_particles.end();) + v3s16 camera_offset = m_env->getCameraOffset(); + for(u16 i=0; i<4; i++) { - if ((*i)->get_expired()) - { - (*i)->remove(); - delete *i; - all_particles.erase(i); - } - else - { - (*i)->step(dtime, env); - i++; + if (m_vertical) { + v3f ppos = m_player->getPosition()/BS; + m_vertices[i].Pos.rotateXZBy(atan2(ppos.Z-m_pos.Z, ppos.X-m_pos.X)/core::DEGTORAD+90); + } else { + m_vertices[i].Pos.rotateYZBy(m_player->getPitch()); + m_vertices[i].Pos.rotateXZBy(m_player->getYaw()); } + m_box.addInternalPoint(m_vertices[i].Pos); + m_vertices[i].Pos += m_pos*BS - intToFloat(camera_offset, BS); } } -void addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr, - LocalPlayer *player, ClientEnvironment &env, v3s16 pos, - const TileSpec tiles[]) -{ - for (u16 j = 0; j < 32; j++) // set the amount of particles here - { - addNodeParticle(gamedef, smgr, player, env, pos, tiles); - } -} - -void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr, - LocalPlayer *player, ClientEnvironment &env, - v3s16 pos, const TileSpec tiles[]) -{ - addNodeParticle(gamedef, smgr, player, env, pos, tiles); -} - -// add a particle of a node -// used by digging and punching particles -void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr, - LocalPlayer *player, ClientEnvironment &env, v3s16 pos, - const TileSpec tiles[]) -{ - // Texture - u8 texid = myrand_range(0,5); - AtlasPointer ap = tiles[texid].texture; - float size = rand()%64/512.; - float visual_size = BS*size; - float texsize = size*2; - - float x1 = ap.x1(); - float y1 = ap.y1(); - - ap.size.X = (ap.x1() - ap.x0()) * texsize; - ap.size.Y = (ap.x1() - ap.x0()) * texsize; - - ap.pos.X = ap.x0() + (x1 - ap.x0()) * ((rand()%64)/64.-texsize); - ap.pos.Y = ap.y0() + (y1 - ap.y0()) * ((rand()%64)/64.-texsize); - - // Physics - v3f velocity( (rand()%100/50.-1)/1.5, - rand()%100/35., - (rand()%100/50.-1)/1.5); - - v3f acceleration(0,-9,0); - v3f particlepos = v3f( - (f32)pos.X+rand()%100/200.-0.25, - (f32)pos.Y+rand()%100/200.-0.25, - (f32)pos.Z+rand()%100/200.-0.25 - ); - - new Particle( - gamedef, - smgr, - player, - env, - particlepos, - velocity, - acceleration, - rand()%100/100., // expiration time - visual_size, - true, - ap); -} - /* ParticleSpawner */ @@ -296,7 +250,11 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr, u16 amount, float time, v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime, float minsize, float maxsize, - bool collisiondetection, AtlasPointer ap, u32 id) + bool collisiondetection, bool collision_removal, u16 attached_id, bool vertical, + video::ITexture *texture, u32 id, const struct TileAnimationParams &anim, + u8 glow, + ParticleManager *p_manager) : + m_particlemanager(p_manager) { m_gamedef = gamedef; m_smgr = smgr; @@ -314,24 +272,41 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr, m_minsize = minsize; m_maxsize = maxsize; m_collisiondetection = collisiondetection; - m_ap = ap; + m_collision_removal = collision_removal; + m_attached_id = attached_id; + m_vertical = vertical; + m_texture = texture; m_time = 0; + m_animation = anim; + m_glow = glow; for (u16 i = 0; i<=m_amount; i++) { float spawntime = (float)rand()/(float)RAND_MAX*m_spawntime; m_spawntimes.push_back(spawntime); } - - all_particlespawners.insert(std::pair(id, this)); } ParticleSpawner::~ParticleSpawner() {} -void ParticleSpawner::step(float dtime, ClientEnvironment &env) +void ParticleSpawner::step(float dtime, ClientEnvironment* env) { m_time += dtime; + bool unloaded = false; + bool is_attached = false; + v3f attached_pos = v3f(0,0,0); + float attached_yaw = 0; + if (m_attached_id != 0) { + if (ClientActiveObject *attached = env->getActiveObject(m_attached_id)) { + attached_pos = attached->getPosition() / BS; + attached_yaw = attached->getYaw(); + is_attached = true; + } else { + unloaded = true; + } + } + if (m_spawntime != 0) // Spawner exists for a predefined timespan { for(std::vector::iterator i = m_spawntimes.begin(); @@ -341,38 +316,62 @@ void ParticleSpawner::step(float dtime, ClientEnvironment &env) { m_amount--; - v3f pos = random_v3f(m_minpos, m_maxpos); - v3f vel = random_v3f(m_minvel, m_maxvel); - v3f acc = random_v3f(m_minacc, m_maxacc); - float exptime = rand()/(float)RAND_MAX - *(m_maxexptime-m_minexptime) - +m_minexptime; - float size = rand()/(float)RAND_MAX - *(m_maxsize-m_minsize) - +m_minsize; - - new Particle( - m_gamedef, - m_smgr, - m_player, - env, - pos, - vel, - acc, - exptime, - size, - m_collisiondetection, - m_ap); - m_spawntimes.erase(i); + // Pretend to, but don't actually spawn a + // particle if it is attached to an unloaded + // object. + if (!unloaded) { + v3f pos = random_v3f(m_minpos, m_maxpos); + v3f vel = random_v3f(m_minvel, m_maxvel); + v3f acc = random_v3f(m_minacc, m_maxacc); + + if (is_attached) { + // Apply attachment yaw and position + pos.rotateXZBy(attached_yaw); + pos += attached_pos; + vel.rotateXZBy(attached_yaw); + acc.rotateXZBy(attached_yaw); + } + + float exptime = rand()/(float)RAND_MAX + *(m_maxexptime-m_minexptime) + +m_minexptime; + float size = rand()/(float)RAND_MAX + *(m_maxsize-m_minsize) + +m_minsize; + + Particle* toadd = new Particle( + m_gamedef, + m_smgr, + m_player, + env, + pos, + vel, + acc, + exptime, + size, + m_collisiondetection, + m_collision_removal, + m_vertical, + m_texture, + v2f(0.0, 0.0), + v2f(1.0, 1.0), + m_animation, + m_glow); + m_particlemanager->addParticle(toadd); + } + i = m_spawntimes.erase(i); } else { - i++; + ++i; } } } else // Spawner exists for an infinity timespan, spawn on a per-second base { + // Skip this step if attached to an unloaded object + if (unloaded) + return; for (int i = 0; i <= m_amount; i++) { if (rand()/(float)RAND_MAX < dtime) @@ -380,6 +379,15 @@ void ParticleSpawner::step(float dtime, ClientEnvironment &env) v3f pos = random_v3f(m_minpos, m_maxpos); v3f vel = random_v3f(m_minvel, m_maxvel); v3f acc = random_v3f(m_minacc, m_maxacc); + + if (is_attached) { + // Apply attachment yaw and position + pos.rotateXZBy(attached_yaw); + pos += attached_pos; + vel.rotateXZBy(attached_yaw); + acc.rotateXZBy(attached_yaw); + } + float exptime = rand()/(float)RAND_MAX *(m_maxexptime-m_minexptime) +m_minexptime; @@ -387,7 +395,7 @@ void ParticleSpawner::step(float dtime, ClientEnvironment &env) *(m_maxsize-m_minsize) +m_minsize; - new Particle( + Particle* toadd = new Particle( m_gamedef, m_smgr, m_player, @@ -398,56 +406,281 @@ void ParticleSpawner::step(float dtime, ClientEnvironment &env) exptime, size, m_collisiondetection, - m_ap); + m_collision_removal, + m_vertical, + m_texture, + v2f(0.0, 0.0), + v2f(1.0, 1.0), + m_animation, + m_glow); + m_particlemanager->addParticle(toadd); } } } } -void allparticlespawners_step (float dtime, ClientEnvironment &env) + +ParticleManager::ParticleManager(ClientEnvironment* env) : + m_env(env) +{} + +ParticleManager::~ParticleManager() +{ + clearAll(); +} + +void ParticleManager::step(float dtime) +{ + stepParticles (dtime); + stepSpawners (dtime); +} + +void ParticleManager::stepSpawners (float dtime) { - for(std::map::iterator i = - all_particlespawners.begin(); - i != all_particlespawners.end();) + MutexAutoLock lock(m_spawner_list_lock); + for (std::map::iterator i = + m_particle_spawners.begin(); + i != m_particle_spawners.end();) { if (i->second->get_expired()) { delete i->second; - all_particlespawners.erase(i++); + m_particle_spawners.erase(i++); } else { - i->second->step(dtime, env); - i++; + i->second->step(dtime, m_env); + ++i; } } } -void delete_particlespawner (u32 id) +void ParticleManager::stepParticles (float dtime) { - if (all_particlespawners.find(id) != all_particlespawners.end()) + MutexAutoLock lock(m_particle_list_lock); + for(std::vector::iterator i = m_particles.begin(); + i != m_particles.end();) { - delete all_particlespawners.find(id)->second; - all_particlespawners.erase(id); + if ((*i)->get_expired()) + { + (*i)->remove(); + delete *i; + i = m_particles.erase(i); + } + else + { + (*i)->step(dtime); + ++i; + } } } -void clear_particles () +void ParticleManager::clearAll () { + MutexAutoLock lock(m_spawner_list_lock); + MutexAutoLock lock2(m_particle_list_lock); for(std::map::iterator i = - all_particlespawners.begin(); - i != all_particlespawners.end();) + m_particle_spawners.begin(); + i != m_particle_spawners.end();) { delete i->second; - all_particlespawners.erase(i++); + m_particle_spawners.erase(i++); } for(std::vector::iterator i = - all_particles.begin(); - i != all_particles.end();) + m_particles.begin(); + i != m_particles.end();) { (*i)->remove(); delete *i; - all_particles.erase(i); - } + i = m_particles.erase(i); + } +} + +void ParticleManager::handleParticleEvent(ClientEvent *event, Client *client, + scene::ISceneManager* smgr, LocalPlayer *player) +{ + switch (event->type) { + case CE_DELETE_PARTICLESPAWNER: { + MutexAutoLock lock(m_spawner_list_lock); + if (m_particle_spawners.find(event->delete_particlespawner.id) != + m_particle_spawners.end()) { + delete m_particle_spawners.find(event->delete_particlespawner.id)->second; + m_particle_spawners.erase(event->delete_particlespawner.id); + } + // no allocated memory in delete event + break; + } + case CE_ADD_PARTICLESPAWNER: { + { + MutexAutoLock lock(m_spawner_list_lock); + if (m_particle_spawners.find(event->add_particlespawner.id) != + m_particle_spawners.end()) { + delete m_particle_spawners.find(event->add_particlespawner.id)->second; + m_particle_spawners.erase(event->add_particlespawner.id); + } + } + + video::ITexture *texture = + client->tsrc()->getTextureForMesh(*(event->add_particlespawner.texture)); + + ParticleSpawner* toadd = new ParticleSpawner(client, smgr, player, + event->add_particlespawner.amount, + event->add_particlespawner.spawntime, + *event->add_particlespawner.minpos, + *event->add_particlespawner.maxpos, + *event->add_particlespawner.minvel, + *event->add_particlespawner.maxvel, + *event->add_particlespawner.minacc, + *event->add_particlespawner.maxacc, + event->add_particlespawner.minexptime, + event->add_particlespawner.maxexptime, + event->add_particlespawner.minsize, + event->add_particlespawner.maxsize, + event->add_particlespawner.collisiondetection, + event->add_particlespawner.collision_removal, + event->add_particlespawner.attached_id, + event->add_particlespawner.vertical, + texture, + event->add_particlespawner.id, + event->add_particlespawner.animation, + event->add_particlespawner.glow, + this); + + /* delete allocated content of event */ + delete event->add_particlespawner.minpos; + delete event->add_particlespawner.maxpos; + delete event->add_particlespawner.minvel; + delete event->add_particlespawner.maxvel; + delete event->add_particlespawner.minacc; + delete event->add_particlespawner.texture; + delete event->add_particlespawner.maxacc; + + { + MutexAutoLock lock(m_spawner_list_lock); + m_particle_spawners.insert( + std::pair( + event->add_particlespawner.id, + toadd)); + } + break; + } + case CE_SPAWN_PARTICLE: { + video::ITexture *texture = + client->tsrc()->getTextureForMesh(*(event->spawn_particle.texture)); + + Particle* toadd = new Particle(client, smgr, player, m_env, + *event->spawn_particle.pos, + *event->spawn_particle.vel, + *event->spawn_particle.acc, + event->spawn_particle.expirationtime, + event->spawn_particle.size, + event->spawn_particle.collisiondetection, + event->spawn_particle.collision_removal, + event->spawn_particle.vertical, + texture, + v2f(0.0, 0.0), + v2f(1.0, 1.0), + event->spawn_particle.animation, + event->spawn_particle.glow); + + addParticle(toadd); + + delete event->spawn_particle.pos; + delete event->spawn_particle.vel; + delete event->spawn_particle.acc; + delete event->spawn_particle.texture; + + break; + } + default: break; + } +} + +void ParticleManager::addDiggingParticles(IGameDef* gamedef, + scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos, + const MapNode &n, const ContentFeatures &f) +{ + for (u16 j = 0; j < 32; j++) // set the amount of particles here + { + addNodeParticle(gamedef, smgr, player, pos, n, f); + } +} + +void ParticleManager::addPunchingParticles(IGameDef* gamedef, + scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos, + const MapNode &n, const ContentFeatures &f) +{ + addNodeParticle(gamedef, smgr, player, pos, n, f); +} + +void ParticleManager::addNodeParticle(IGameDef* gamedef, + scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos, + const MapNode &n, const ContentFeatures &f) +{ + // Texture + u8 texid = myrand_range(0, 5); + const TileSpec &tile = f.tiles[texid]; + video::ITexture *texture; + struct TileAnimationParams anim; + anim.type = TAT_NONE; + + // Only use first frame of animated texture + if (tile.material_flags & MATERIAL_FLAG_ANIMATION) + texture = tile.frames[0].texture; + else + texture = tile.texture; + + float size = rand() % 64 / 512.; + float visual_size = BS * size; + v2f texsize(size * 2, size * 2); + v2f texpos; + texpos.X = ((rand() % 64) / 64. - texsize.X); + texpos.Y = ((rand() % 64) / 64. - texsize.Y); + + // Physics + v3f velocity((rand() % 100 / 50. - 1) / 1.5, + rand() % 100 / 35., + (rand() % 100 / 50. - 1) / 1.5); + + v3f acceleration(0,-9,0); + v3f particlepos = v3f( + (f32) pos.X + rand() %100 /200. - 0.25, + (f32) pos.Y + rand() %100 /200. - 0.25, + (f32) pos.Z + rand() %100 /200. - 0.25 + ); + + video::SColor color; + if (tile.has_color) + color = tile.color; + else + n.getColor(f, &color); + + Particle* toadd = new Particle( + gamedef, + smgr, + player, + m_env, + particlepos, + velocity, + acceleration, + rand() % 100 / 100., // expiration time + visual_size, + true, + false, + false, + texture, + texpos, + texsize, + anim, + 0, + color); + + addParticle(toadd); +} + +void ParticleManager::addParticle(Particle* toadd) +{ + MutexAutoLock lock(m_particle_list_lock); + m_particles.push_back(toadd); }