summaryrefslogtreecommitdiff
path: root/src/particles.cpp
diff options
context:
space:
mode:
authorFoghrye4 <foghrye4@gmail.com>2016-11-14 18:09:59 +0400
committerZeno- <kde.psych@gmail.com>2016-11-15 00:09:59 +1000
commit93e3555eae2deaeca69ee252cfa9cc9c3e0e49ef (patch)
tree9b9b665b97c01f0b281652a85088b336cc4cefde /src/particles.cpp
parent649448a2a91fbf3e944b2f2e739f4e2292af1df0 (diff)
downloadminetest-93e3555eae2deaeca69ee252cfa9cc9c3e0e49ef.tar.gz
minetest-93e3555eae2deaeca69ee252cfa9cc9c3e0e49ef.tar.bz2
minetest-93e3555eae2deaeca69ee252cfa9cc9c3e0e49ef.zip
Adding particle blend, glow and animation (#4705)
Diffstat (limited to 'src/particles.cpp')
-rw-r--r--src/particles.cpp203
1 files changed, 187 insertions, 16 deletions
diff --git a/src/particles.cpp b/src/particles.cpp
index f20fb4083..538487028 100644
--- a/src/particles.cpp
+++ b/src/particles.cpp
@@ -43,6 +43,22 @@ v3f random_v3f(v3f min, v3f max)
rand()/(float)RAND_MAX*(max.Z-min.Z)+min.Z);
}
+u32 check_material_type_param(u32 material_type_param)
+{
+ u32 alphaSource = (material_type_param & 0x0000F000) >> 12;
+ u32 modulo = (material_type_param & 0x00000F00) >> 8;
+ u32 srcFact = (material_type_param & 0x000000F0) >> 4;
+ u32 dstFact = material_type_param & 0x0000000F;
+ if (alphaSource <= 3 && modulo <= 4 && srcFact <= 10 && dstFact <= 10) {
+ return material_type_param;
+ } else {
+ errorstream << "Server send incorrect ";
+ errorstream << "material_type_param value for particle.";
+ errorstream << std::endl;
+ return 0;
+ }
+}
+
Particle::Particle(
IGameDef *gamedef,
scene::ISceneManager* smgr,
@@ -58,7 +74,14 @@ Particle::Particle(
bool vertical,
video::ITexture *texture,
v2f texpos,
- v2f texsize
+ v2f texsize,
+ u32 material_type_param,
+ u16 vertical_frame_num,
+ u16 horizontal_frame_num,
+ u16 first_frame,
+ float frame_length,
+ bool loop_animation,
+ u8 glow
):
scene::ISceneNode(smgr->getRootSceneNode(), smgr)
{
@@ -71,11 +94,26 @@ Particle::Particle(
m_material.setFlag(video::EMF_BACK_FACE_CULLING, false);
m_material.setFlag(video::EMF_BILINEAR_FILTER, false);
m_material.setFlag(video::EMF_FOG_ENABLE, true);
- m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+ if (material_type_param != 0) {
+ m_material.MaterialType = video::EMT_ONETEXTURE_BLEND;
+ m_material.MaterialTypeParam = irr::core::FR(material_type_param);
+ // We must disable z-buffer if we want to avoid transparent pixels
+ // to overlap pixels with lower z-value.
+ m_material.setFlag(video::EMF_ZWRITE_ENABLE, false);
+ } else {
+ m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+ }
m_material.setTexture(0, texture);
+
m_texpos = texpos;
m_texsize = texsize;
-
+ m_vertical_frame_num = vertical_frame_num;
+ m_horizontal_frame_num = horizontal_frame_num;
+ m_first_frame = first_frame;
+ m_frame_length = frame_length;
+ m_loop_animation = loop_animation;
+ m_texsize.Y /= m_vertical_frame_num;
+ m_texsize.X /= m_horizontal_frame_num;
// Particle related
m_pos = pos;
@@ -88,6 +126,7 @@ Particle::Particle(
m_collisiondetection = collisiondetection;
m_collision_removal = collision_removal;
m_vertical = vertical;
+ m_glow = glow;
// Irrlicht stuff
m_collisionbox = aabb3f
@@ -170,16 +209,29 @@ void Particle::updateLight()
else
light = blend_light(m_env->getDayNightRatio(), LIGHT_SUN, 0);
- m_light = decode_light(light);
+ m_light = decode_light(light + m_glow);
}
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;
+ u16 frame = m_first_frame;
+ if (m_frame_length > 0) {
+ if (m_loop_animation)
+ frame = m_first_frame + (u32)(m_time / m_frame_length)
+ % (m_vertical_frame_num *
+ m_horizontal_frame_num - m_first_frame);
+ else if (m_time >=
+ (m_vertical_frame_num * m_horizontal_frame_num
+ - m_first_frame) * m_frame_length)
+ frame = m_vertical_frame_num * m_horizontal_frame_num - 1;
+ else
+ frame = m_first_frame + (u16)(m_time / m_frame_length);
+ }
+ f32 tx0 = m_texpos.X + m_texsize.X * (frame % m_horizontal_frame_num);
+ f32 tx1 = m_texpos.X + m_texsize.X * (frame % m_horizontal_frame_num + 1);
+ f32 ty0 = m_texpos.Y + m_texsize.Y * (frame / m_horizontal_frame_num);
+ f32 ty1 = m_texpos.Y + m_texsize.Y * (frame / m_horizontal_frame_num + 1);
m_vertices[0] = video::S3DVertex(-m_size/2,-m_size/2,0, 0,0,0,
c, tx0, ty1);
@@ -214,7 +266,16 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
float minexptime, float maxexptime, float minsize, float maxsize,
bool collisiondetection, bool collision_removal, u16 attached_id, bool vertical,
- video::ITexture *texture, u32 id, ParticleManager *p_manager) :
+ video::ITexture *texture, u32 id,
+ u32 material_type_param,
+ u16 vertical_frame_num,
+ u16 horizontal_frame_num,
+ u16 min_first_frame,
+ u16 max_first_frame,
+ float frame_length,
+ bool loop_animation,
+ u8 glow,
+ ParticleManager *p_manager) :
m_particlemanager(p_manager)
{
m_gamedef = gamedef;
@@ -238,6 +299,14 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
m_vertical = vertical;
m_texture = texture;
m_time = 0;
+ m_vertical_frame_num = vertical_frame_num;
+ m_horizontal_frame_num = horizontal_frame_num;
+ m_min_first_frame = min_first_frame;
+ m_max_first_frame = max_first_frame;
+ m_frame_length = frame_length;
+ m_loop_animation = loop_animation;
+ m_material_type_param = material_type_param;
+ m_glow = glow;
for (u16 i = 0; i<=m_amount; i++)
{
@@ -251,7 +320,6 @@ ParticleSpawner::~ParticleSpawner() {}
void ParticleSpawner::step(float dtime, ClientEnvironment* env)
{
m_time += dtime;
-
bool unloaded = false;
v3f attached_offset = v3f(0,0,0);
if (m_attached_id != 0) {
@@ -285,7 +353,10 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
float size = rand()/(float)RAND_MAX
*(m_maxsize-m_minsize)
+m_minsize;
-
+ u16 first_frame = m_min_first_frame +
+ rand() %
+ (m_max_first_frame -
+ m_min_first_frame + 1);
Particle* toadd = new Particle(
m_gamedef,
m_smgr,
@@ -301,7 +372,14 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
m_vertical,
m_texture,
v2f(0.0, 0.0),
- v2f(1.0, 1.0));
+ v2f(1.0, 1.0),
+ m_material_type_param,
+ m_vertical_frame_num,
+ m_horizontal_frame_num,
+ first_frame,
+ m_frame_length,
+ m_loop_animation,
+ m_glow);
m_particlemanager->addParticle(toadd);
}
i = m_spawntimes.erase(i);
@@ -331,7 +409,10 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
float size = rand()/(float)RAND_MAX
*(m_maxsize-m_minsize)
+m_minsize;
-
+ u16 first_frame = m_min_first_frame +
+ rand() %
+ (m_max_first_frame -
+ m_min_first_frame + 1);
Particle* toadd = new Particle(
m_gamedef,
m_smgr,
@@ -347,7 +428,14 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
m_vertical,
m_texture,
v2f(0.0, 0.0),
- v2f(1.0, 1.0));
+ v2f(1.0, 1.0),
+ m_material_type_param,
+ m_vertical_frame_num,
+ m_horizontal_frame_num,
+ first_frame,
+ m_frame_length,
+ m_loop_animation,
+ m_glow);
m_particlemanager->addParticle(toadd);
}
}
@@ -459,6 +547,39 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
video::ITexture *texture =
gamedef->tsrc()->getTextureForMesh(*(event->add_particlespawner.texture));
+ float frame_length = -1;
+ u16 vertical_frame_num = 1;
+ u16 horizontal_frame_num = 1;
+ u32 material_type_param =
+ check_material_type_param(event->add_particlespawner.material_type_param);
+
+ switch (event->add_particlespawner.animation_type) {
+ case AT_NONE:
+ break;
+ case AT_VERTICAL_FRAMES: {
+ v2u32 size = texture->getOriginalSize();
+ int frame_height = (float)size.X /
+ (float)event->add_particlespawner.vertical_frame_num *
+ (float)event->add_particlespawner.horizontal_frame_num;
+ vertical_frame_num = size.Y / frame_height;
+ frame_length =
+ event->add_particlespawner.frame_length /
+ vertical_frame_num;
+ break;
+ }
+ case AT_2D_ANIMATION_SHEET: {
+ vertical_frame_num =
+ event->add_particlespawner.vertical_frame_num;
+ horizontal_frame_num =
+ event->add_particlespawner.horizontal_frame_num;
+ frame_length =
+ event->add_particlespawner.frame_length;
+ break;
+ }
+ default:
+ break;
+ }
+
ParticleSpawner* toadd = new ParticleSpawner(gamedef, smgr, player,
event->add_particlespawner.amount,
event->add_particlespawner.spawntime,
@@ -478,6 +599,14 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
event->add_particlespawner.vertical,
texture,
event->add_particlespawner.id,
+ material_type_param,
+ vertical_frame_num,
+ horizontal_frame_num,
+ event->add_particlespawner.min_first_frame,
+ event->add_particlespawner.max_first_frame,
+ frame_length,
+ event->add_particlespawner.loop_animation,
+ event->add_particlespawner.glow,
this);
/* delete allocated content of event */
@@ -502,6 +631,39 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
video::ITexture *texture =
gamedef->tsrc()->getTextureForMesh(*(event->spawn_particle.texture));
+ float frame_length = -1;
+ u16 vertical_frame_num = 1;
+ u16 horizontal_frame_num = 1;
+ u32 material_type_param =
+ check_material_type_param(event->spawn_particle.material_type_param);
+
+ switch (event->spawn_particle.animation_type) {
+ case AT_NONE:
+ break;
+ case AT_VERTICAL_FRAMES: {
+ v2u32 size = texture->getOriginalSize();
+ int frame_height = (float)size.X /
+ (float)event->spawn_particle.vertical_frame_num *
+ (float)event->spawn_particle.horizontal_frame_num;
+ vertical_frame_num = size.Y / frame_height;
+ frame_length =
+ event->spawn_particle.frame_length /
+ vertical_frame_num;
+ break;
+ }
+ case AT_2D_ANIMATION_SHEET: {
+ vertical_frame_num =
+ event->spawn_particle.vertical_frame_num;
+ horizontal_frame_num =
+ event->spawn_particle.horizontal_frame_num;
+ frame_length =
+ event->spawn_particle.frame_length;
+ break;
+ }
+ default:
+ break;
+ }
+
Particle* toadd = new Particle(gamedef, smgr, player, m_env,
*event->spawn_particle.pos,
*event->spawn_particle.vel,
@@ -513,13 +675,21 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
event->spawn_particle.vertical,
texture,
v2f(0.0, 0.0),
- v2f(1.0, 1.0));
+ v2f(1.0, 1.0),
+ material_type_param,
+ vertical_frame_num,
+ horizontal_frame_num,
+ event->spawn_particle.first_frame,
+ frame_length,
+ event->spawn_particle.loop_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;
}
@@ -588,7 +758,8 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s
false,
texture,
texpos,
- texsize);
+ texsize,
+ 0, 1, 1, 0, -1, true, 0);
addParticle(toadd);
}