X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fparticles.cpp;h=19bdaf1215f7c5258f168f39ecc514ea1954fedd;hb=2a01050a0cf0826f25240e2cb407535394ee360f;hp=fef21d91b1f043fd08a080f6d85abe7c44a6a1b7;hpb=22e186b4aa88b585e71500c4e9a03bf69b0b6191;p=minetest.git diff --git a/src/particles.cpp b/src/particles.cpp index fef21d91b..19bdaf121 100644 --- a/src/particles.cpp +++ b/src/particles.cpp @@ -32,19 +32,37 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "clientmap.h" #include "mapnode.h" +/* + Utility +*/ + +v3f random_v3f(v3f min, v3f max) +{ + return v3f( rand()/(float)RAND_MAX*(max.X-min.X)+min.X, + rand()/(float)RAND_MAX*(max.Y-min.Y)+min.Y, + 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, - s32 id, + ClientEnvironment &env, v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, - AtlasPointer ap + bool collisiondetection, + bool vertical, + video::ITexture *texture, + v2f texpos, + v2f texsize ): - scene::ISceneNode(smgr->getRootSceneNode(), smgr, id) + scene::ISceneNode(smgr->getRootSceneNode(), smgr) { // Misc m_gamedef = gamedef; @@ -55,9 +73,9 @@ 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_light = 0; + m_material.setTexture(0, texture); + m_texpos = texpos; + m_texsize = texsize; // Particle related @@ -68,10 +86,21 @@ Particle::Particle( m_time = 0; m_player = player; m_size = size; + m_collisiondetection = collisiondetection; + m_vertical = vertical; - // Irrlicht stuff (TODO) - m_collisionbox = core::aabbox3d(-size/2,-size/2,-size/2,size/2,size/2,size/2); + // Irrlicht stuff + m_collisionbox = core::aabbox3d + (-size/2,-size/2,-size/2,size/2,size/2,size/2); this->setAutomaticCulling(scene::EAC_OFF); + + // Init lighting + updateLight(env); + + // Init model + updateVertices(); + + all_particles.push_back(this); } Particle::~Particle() @@ -82,8 +111,10 @@ void Particle::OnRegisterSceneNode() { if (IsVisible) { - SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT); - SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID); + SceneManager->registerNodeForRendering + (this, scene::ESNRP_TRANSPARENT); + SceneManager->registerNodeForRendering + (this, scene::ESNRP_SOLID); } ISceneNode::OnRegisterSceneNode(); @@ -96,45 +127,45 @@ void Particle::render() video::IVideoDriver* driver = SceneManager->getVideoDriver(); driver->setMaterial(m_material); driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); - video::SColor c(255, m_light, m_light, m_light); - - video::S3DVertex vertices[4] = - { - video::S3DVertex(-m_size/2,-m_size/2,0, 0,0,0, c, m_ap.x0(), m_ap.y1()), - video::S3DVertex(m_size/2,-m_size/2,0, 0,0,0, c, m_ap.x1(), m_ap.y1()), - video::S3DVertex(m_size/2,m_size/2,0, 0,0,0, c, m_ap.x1(), m_ap.y0()), - 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++) - { - vertices[i].Pos.rotateYZBy(m_player->getPitch()); - vertices[i].Pos.rotateXZBy(m_player->getYaw()); - m_box.addInternalPoint(vertices[i].Pos); - vertices[i].Pos += m_pos*BS; - } u16 indices[] = {0,1,2, 2,3,0}; - driver->drawVertexPrimitiveList(vertices, 4, indices, 2, - video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT); + driver->drawVertexPrimitiveList(m_vertices, 4, + indices, 2, video::EVT_STANDARD, + scene::EPT_TRIANGLES, video::EIT_16BIT); } void Particle::step(float dtime, ClientEnvironment &env) { - 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.getClientMap(), 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; 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 + { + m_velocity += m_acceleration * dtime; + m_pos += m_velocity * dtime; + } // Update lighting + updateLight(env); + + // Update model + updateVertices(); +} + +void Particle::updateLight(ClientEnvironment &env) +{ u8 light = 0; try{ v3s16 p = v3s16( @@ -151,17 +182,53 @@ void Particle::step(float dtime, ClientEnvironment &env) m_light = decode_light(light); } -std::vector all_particles; +void Particle::updateVertices() +{ + video::SColor c(255, m_light, m_light, m_light); + f32 tx0 = m_texpos.X; + f32 tx1 = m_texpos.X + m_texsize.X; + f32 ty0 = m_texpos.Y; + f32 ty1 = m_texpos.Y + m_texsize.Y; + + m_vertices[0] = video::S3DVertex(-m_size/2,-m_size/2,0, 0,0,0, + c, tx0, ty1); + m_vertices[1] = video::S3DVertex(m_size/2,-m_size/2,0, 0,0,0, + c, tx1, ty1); + m_vertices[2] = video::S3DVertex(m_size/2,m_size/2,0, 0,0,0, + c, tx1, ty0); + m_vertices[3] = video::S3DVertex(-m_size/2,m_size/2,0, 0,0,0, + c, tx0, ty0); + + for(u16 i=0; i<4; 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; + } +} + + +/* + Helpers +*/ + void allparticles_step (float dtime, ClientEnvironment &env) { - for(std::vector::iterator i = all_particles.begin(); i != all_particles.end();) + for(std::vector::iterator i = all_particles.begin(); + i != all_particles.end();) { if ((*i)->get_expired()) { (*i)->remove(); delete *i; - all_particles.erase(i); + i = all_particles.erase(i); } else { @@ -171,41 +238,50 @@ void allparticles_step (float dtime, ClientEnvironment &env) } } -void addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos, const TileSpec tiles[]) +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, pos, tiles); + addNodeParticle(gamedef, smgr, player, env, pos, tiles); } } -void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos, const TileSpec tiles[]) +void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr, + LocalPlayer *player, ClientEnvironment &env, + v3s16 pos, const TileSpec tiles[]) { - addNodeParticle(gamedef, smgr, player, pos, 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, v3s16 pos, const TileSpec tiles[]) +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(); + video::ITexture *texture = tiles[texid].texture; - ap.size.X = (ap.x1() - ap.x0()) * texsize; - ap.size.Y = (ap.x1() - ap.x0()) * texsize; + // Only use first frame of animated texture + f32 ymax = 1; + if(tiles[texid].material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES) + ymax /= tiles[texid].animation_frame_count; - ap.pos.X = ap.x0() + (x1 - ap.x0()) * ((rand()%64)/64.-texsize); - ap.pos.Y = ap.y0() + (y1 - ap.y0()) * ((rand()%64)/64.-texsize); + float size = rand()%64/512.; + float visual_size = BS*size; + v2f texsize(size*2, ymax*size*2); + v2f texpos; + texpos.X = ((rand()%64)/64.-texsize.X); + texpos.Y = ymax*((rand()%64)/64.-texsize.Y); // Physics - v3f velocity((rand()%100/50.-1)/1.5, rand()%100/35., (rand()%100/50.-1)/1.5); + 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, @@ -213,17 +289,190 @@ void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr, LocalPlayer (f32)pos.Z+rand()%100/200.-0.25 ); - Particle *particle = new Particle( + new Particle( gamedef, smgr, player, - 0, + env, particlepos, velocity, acceleration, rand()%100/100., // expiration time visual_size, - ap); + true, + false, + texture, + texpos, + texsize); +} + +/* + ParticleSpawner +*/ + +ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr, LocalPlayer *player, + 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, bool vertical, video::ITexture *texture, u32 id) +{ + m_gamedef = gamedef; + m_smgr = smgr; + m_player = player; + m_amount = amount; + m_spawntime = time; + m_minpos = minpos; + m_maxpos = maxpos; + m_minvel = minvel; + m_maxvel = maxvel; + m_minacc = minacc; + m_maxacc = maxacc; + m_minexptime = minexptime; + m_maxexptime = maxexptime; + m_minsize = minsize; + m_maxsize = maxsize; + m_collisiondetection = collisiondetection; + m_vertical = vertical; + m_texture = texture; + m_time = 0; + + 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) +{ + m_time += dtime; + + if (m_spawntime != 0) // Spawner exists for a predefined timespan + { + for(std::vector::iterator i = m_spawntimes.begin(); + i != m_spawntimes.end();) + { + if ((*i) <= m_time && m_amount > 0) + { + 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_vertical, + m_texture, + v2f(0.0, 0.0), + v2f(1.0, 1.0)); + i = m_spawntimes.erase(i); + } + else + { + i++; + } + } + } + else // Spawner exists for an infinity timespan, spawn on a per-second base + { + for (int i = 0; i <= m_amount; i++) + { + if (rand()/(float)RAND_MAX < dtime) + { + 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_vertical, + m_texture, + v2f(0.0, 0.0), + v2f(1.0, 1.0)); + } + } + } +} - all_particles.push_back(particle); +void allparticlespawners_step (float dtime, ClientEnvironment &env) +{ + for(std::map::iterator i = + all_particlespawners.begin(); + i != all_particlespawners.end();) + { + if (i->second->get_expired()) + { + delete i->second; + all_particlespawners.erase(i++); + } + else + { + i->second->step(dtime, env); + i++; + } + } +} + +void delete_particlespawner (u32 id) +{ + if (all_particlespawners.find(id) != all_particlespawners.end()) + { + delete all_particlespawners.find(id)->second; + all_particlespawners.erase(id); + } +} + +void clear_particles () +{ + for(std::map::iterator i = + all_particlespawners.begin(); + i != all_particlespawners.end();) + { + delete i->second; + all_particlespawners.erase(i++); + } + + for(std::vector::iterator i = + all_particles.begin(); + i != all_particles.end();) + { + (*i)->remove(); + delete *i; + i = all_particles.erase(i); + } }