Skip to content

Commit

Permalink
Add local particles and particlespawners.
Browse files Browse the repository at this point in the history
  • Loading branch information
red-001 authored and sofar committed Apr 9, 2017
1 parent 7641cc7 commit f955b24
Show file tree
Hide file tree
Showing 9 changed files with 493 additions and 27 deletions.
70 changes: 70 additions & 0 deletions doc/client_lua_api.md
Expand Up @@ -702,6 +702,16 @@ Call these functions only at load time!
* Returns the protocol version of the server.
* Might not be accurate at start up as the client might not be connected to the server yet, in that case it will return 0.

### Particles
* `minetest.add_particle(particle definition)`

* `minetest.add_particlespawner(particlespawner definition)`
* Add a `ParticleSpawner`, an object that spawns an amount of particles over `time` seconds
* Returns an `id`, and -1 if adding didn't succeed

* `minetest.delete_particlespawner(id)`
* Delete `ParticleSpawner` with `id` (return value from `minetest.add_particlespawner`)

### Misc.
* `minetest.parse_json(string[, nullvalue])`: returns something
* Convert a string containing JSON data into the Lua equivalent
Expand Down Expand Up @@ -856,3 +866,63 @@ Named colors are also supported and are equivalent to
To specify the value of the alpha channel, append `#AA` to the end of the color name
(e.g. `colorname#08`). For named colors the hexadecimal string representing the alpha
value must (always) be two hexadecimal digits.

### Particle definition (`add_particle`)

{
pos = {x=0, y=0, z=0},
velocity = {x=0, y=0, z=0},
acceleration = {x=0, y=0, z=0},
-- ^ Spawn particle at pos with velocity and acceleration
expirationtime = 1,
-- ^ Disappears after expirationtime seconds
size = 1,
collisiondetection = false,
-- ^ collisiondetection: if true collides with physical objects
collision_removal = false,
-- ^ collision_removal: if true then particle is removed when it collides,
-- ^ requires collisiondetection = true to have any effect
vertical = false,
-- ^ vertical: if true faces player using y axis only
texture = "image.png",
-- ^ Uses texture (string)
animation = {Tile Animation definition},
-- ^ optional, specifies how to animate the particle texture
glow = 0
-- ^ optional, specify particle self-luminescence in darkness
}

### `ParticleSpawner` definition (`add_particlespawner`)
**NOTE: `attached` is not implemented yet.**

{
amount = 1,
time = 1,
-- ^ If time is 0 has infinite lifespan and spawns the amount on a per-second base
minpos = {x=0, y=0, z=0},
maxpos = {x=0, y=0, z=0},
minvel = {x=0, y=0, z=0},
maxvel = {x=0, y=0, z=0},
minacc = {x=0, y=0, z=0},
maxacc = {x=0, y=0, z=0},
minexptime = 1,
maxexptime = 1,
minsize = 1,
maxsize = 1,
-- ^ The particle's properties are random values in between the bounds:
-- ^ minpos/maxpos, minvel/maxvel (velocity), minacc/maxacc (acceleration),
-- ^ minsize/maxsize, minexptime/maxexptime (expirationtime)
collisiondetection = false,
-- ^ collisiondetection: if true uses collision detection
collision_removal = false,
-- ^ collision_removal: if true then particle is removed when it collides,
-- ^ requires collisiondetection = true to have any effect
attached = ObjectRef,
-- ^ attached: if defined, particle positions, velocities and accelerations
-- ^ are relative to this object's position and yaw.
vertical = false,
-- ^ vertical: if true faces player using y axis only
texture = "image.png",
-- ^ Uses texture (string)
}

2 changes: 2 additions & 0 deletions src/client.h
Expand Up @@ -146,7 +146,9 @@ enum ClientEventType
CE_SHOW_LOCAL_FORMSPEC,
CE_SPAWN_PARTICLE,
CE_ADD_PARTICLESPAWNER,
CE_ADD_LOCAL_PARTICLESPAWNER,
CE_DELETE_PARTICLESPAWNER,
CE_DELETE_LOCAL_PARTICLESPAWNER,
CE_HUDADD,
CE_HUDRM,
CE_HUDCHANGE,
Expand Down
2 changes: 2 additions & 0 deletions src/game.cpp
Expand Up @@ -3118,6 +3118,8 @@ void Game::processClientEvents(CameraOrientation *cam)
case CE_SPAWN_PARTICLE:
case CE_ADD_PARTICLESPAWNER:
case CE_DELETE_PARTICLESPAWNER:
case CE_ADD_LOCAL_PARTICLESPAWNER:
case CE_DELETE_LOCAL_PARTICLESPAWNER:
client->getParticleManager()->handleParticleEvent(&event, client,
smgr, player);
break;
Expand Down
128 changes: 116 additions & 12 deletions src/particles.cpp
Expand Up @@ -18,15 +18,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/

#include "particles.h"
#include <stdlib.h>
#include "client.h"
#include "clientmap.h"
#include "collision.h"
#include <stdlib.h>
#include "util/numeric.h"
#include "light.h"
#include "environment.h"
#include "clientmap.h"
#include "light.h"
#include "mapnode.h"
#include "client.h"
#include "util/numeric.h"

/*
Utility
Expand Down Expand Up @@ -96,8 +95,7 @@ Particle::Particle(
m_glow = glow;

// Irrlicht stuff
m_collisionbox = aabb3f
(-size/2,-size/2,-size/2,size/2,size/2,size/2);
m_collisionbox = aabb3f(-size/2,-size/2,-size/2,size/2,size/2,size/2);
this->setAutomaticCulling(scene::EAC_OFF);

// Init lighting
Expand All @@ -107,21 +105,20 @@ Particle::Particle(
updateVertices();
}

Particle::~Particle()
{
}
Particle::~Particle() {}

void Particle::OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT_EFFECT);
SceneManager->registerNodeForRendering(this,
scene::ESNRP_TRANSPARENT_EFFECT);

ISceneNode::OnRegisterSceneNode();
}

void Particle::render()
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
video::IVideoDriver *driver = SceneManager->getVideoDriver();
driver->setMaterial(m_material);
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);

Expand Down Expand Up @@ -433,6 +430,7 @@ void ParticleManager::step(float dtime)
{
stepParticles (dtime);
stepSpawners (dtime);
stepSpawnersLocal (dtime);
}

void ParticleManager::stepSpawners (float dtime)
Expand All @@ -455,6 +453,26 @@ void ParticleManager::stepSpawners (float dtime)
}
}

void ParticleManager::stepSpawnersLocal (float dtime)
{
MutexAutoLock lock(m_spawner_local_list_lock);
for (UNORDERED_MAP<u32, ParticleSpawner*>::iterator i =
m_particle_spawners_local.begin();
i != m_particle_spawners_local.end();)
{
if (i->second->get_expired())
{
delete i->second;
m_particle_spawners_local.erase(i++);
}
else
{
i->second->step(dtime, m_env);
++i;
}
}
}

void ParticleManager::stepParticles (float dtime)
{
MutexAutoLock lock(m_particle_list_lock);
Expand All @@ -479,6 +497,8 @@ void ParticleManager::clearAll ()
{
MutexAutoLock lock(m_spawner_list_lock);
MutexAutoLock lock2(m_particle_list_lock);
MutexAutoLock lock3(m_spawner_local_list_lock);

for(std::map<u32, ParticleSpawner*>::iterator i =
m_particle_spawners.begin();
i != m_particle_spawners.end();)
Expand All @@ -487,6 +507,14 @@ void ParticleManager::clearAll ()
m_particle_spawners.erase(i++);
}

for(UNORDERED_MAP<u32, ParticleSpawner*>::iterator i =
m_particle_spawners_local.begin();
i != m_particle_spawners_local.end();)
{
delete i->second;
m_particle_spawners_local.erase(i++);
}

for(std::vector<Particle*>::iterator i =
m_particles.begin();
i != m_particles.end();)
Expand All @@ -511,6 +539,16 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, Client *client,
// no allocated memory in delete event
break;
}
case CE_DELETE_LOCAL_PARTICLESPAWNER: {
MutexAutoLock lock(m_spawner_local_list_lock);
if (m_particle_spawners_local.find(event->delete_particlespawner.id) !=
m_particle_spawners_local.end()) {
delete m_particle_spawners_local.find(event->delete_particlespawner.id)->second;
m_particle_spawners_local.erase(event->delete_particlespawner.id);
}
// no allocated memory in delete event
break;
}
case CE_ADD_PARTICLESPAWNER: {
{
MutexAutoLock lock(m_spawner_list_lock);
Expand Down Expand Up @@ -565,6 +603,60 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, Client *client,
}
break;
}
case CE_ADD_LOCAL_PARTICLESPAWNER: {
{
MutexAutoLock lock(m_spawner_local_list_lock);
if (m_particle_spawners_local.find(event->add_particlespawner.id) !=
m_particle_spawners_local.end()) {
delete m_particle_spawners_local.find(event->add_particlespawner.id)->second;
m_particle_spawners_local.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_local_list_lock);
m_particle_spawners_local.insert(
std::pair<u32, ParticleSpawner*>(
event->add_particlespawner.id,
toadd));
}
break;
}
case CE_SPAWN_PARTICLE: {
video::ITexture *texture =
client->tsrc()->getTextureForMesh(*(event->spawn_particle.texture));
Expand Down Expand Up @@ -679,6 +771,18 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef,
addParticle(toadd);
}

u32 ParticleManager::getSpawnerId()
{
u32 id = 0;
for (;;) { // look for unused particlespawner id
id++;
UNORDERED_MAP<u32, ParticleSpawner*>::iterator f =
m_particle_spawners_local.find(id);
if (f == m_particle_spawners_local.end()) {
return id;
}
}
}
void ParticleManager::addParticle(Particle* toadd)
{
MutexAutoLock lock(m_particle_list_lock);
Expand Down
28 changes: 16 additions & 12 deletions src/particles.h
Expand Up @@ -37,7 +37,7 @@ struct ContentFeatures;

class Particle : public scene::ISceneNode
{
public:
public:
Particle(
IGameDef* gamedef,
scene::ISceneManager* mgr,
Expand Down Expand Up @@ -119,7 +119,7 @@ class Particle : public scene::ISceneNode

class ParticleSpawner
{
public:
public:
ParticleSpawner(IGameDef* gamedef,
scene::ISceneManager *smgr,
LocalPlayer *player,
Expand All @@ -146,7 +146,7 @@ class ParticleSpawner
bool get_expired ()
{ return (m_amount <= 0) && m_spawntime != 0; }

private:
private:
ParticleManager* m_particlemanager;
float m_time;
IGameDef *m_gamedef;
Expand Down Expand Up @@ -181,10 +181,10 @@ class ParticleManager
{
friend class ParticleSpawner;
public:
ParticleManager(ClientEnvironment* env);
ParticleManager(ClientEnvironment *env);
~ParticleManager();

void step (float dtime);
void step(float dtime);

void handleParticleEvent(ClientEvent *event, Client *client,
scene::ISceneManager* smgr, LocalPlayer *player);
Expand All @@ -200,23 +200,27 @@ friend class ParticleSpawner;
void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr,
LocalPlayer *player, v3s16 pos, const MapNode &n,
const ContentFeatures &f);
u32 getSpawnerId();

protected:
void addParticle(Particle* toadd);
void addParticle(Particle *toadd);

private:

void stepParticles (float dtime);
void stepSpawners (float dtime);
void stepParticles(float dtime);
void stepSpawners(float dtime);
void stepSpawnersLocal(float dtime);

void clearAll ();
void clearAll();

std::vector<Particle*> m_particles;
std::map<u32, ParticleSpawner*> m_particle_spawners;
std::vector<Particle *> m_particles;
std::map<u32, ParticleSpawner *> m_particle_spawners;
UNORDERED_MAP<u32, ParticleSpawner *> m_particle_spawners_local;

ClientEnvironment* m_env;
ClientEnvironment *m_env;
Mutex m_particle_list_lock;
Mutex m_spawner_list_lock;
Mutex m_spawner_local_list_lock;
};

#endif

0 comments on commit f955b24

Please sign in to comment.