From 615492540debaae6b7e65307572d120902b5f751 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Thu, 6 Feb 2014 05:46:47 -0400 Subject: [PATCH] Added ParticleSystem:setRelativeRotation. If enabled, particle rotations and angles will be relative to their current velocities. --- .../graphics/opengl/ParticleSystem.cpp | 51 +++++++++++++------ src/modules/graphics/opengl/ParticleSystem.h | 36 ++++++++----- .../graphics/opengl/wrap_ParticleSystem.cpp | 16 ++++++ .../graphics/opengl/wrap_ParticleSystem.h | 2 + 4 files changed, 77 insertions(+), 28 deletions(-) diff --git a/src/modules/graphics/opengl/ParticleSystem.cpp b/src/modules/graphics/opengl/ParticleSystem.cpp index d5d52da2b..e47525005 100644 --- a/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/src/modules/graphics/opengl/ParticleSystem.cpp @@ -94,6 +94,7 @@ ParticleSystem::ParticleSystem(Texture *texture, uint32 size) , spinVariation(0) , offsetX(float(texture->getWidth())*0.5f) , offsetY(float(texture->getHeight())*0.5f) + , relativeRotation(false) { if (size == 0 || size > MAX_PARTICLES) throw love::Exception("Invalid ParticleSystem size."); @@ -145,6 +146,7 @@ ParticleSystem::ParticleSystem(const ParticleSystem &p) , offsetX(p.offsetX) , offsetY(p.offsetY) , colors(p.colors) + , relativeRotation(p.relativeRotation) { setBufferSize(maxParticles); @@ -169,7 +171,7 @@ void ParticleSystem::createBuffers(size_t size) { try { - pFree = pMem = new particle[size]; + pFree = pMem = new Particle[size]; particleVerts = new love::Vertex[size * 4]; maxParticles = (uint32) size; } @@ -212,7 +214,7 @@ void ParticleSystem::addParticle(float t) return; // Gets a free particle and updates the allocation pointer. - particle *p = pFree++; + Particle *p = pFree++; initParticle(p, t); switch (insertMode) @@ -232,7 +234,7 @@ void ParticleSystem::addParticle(float t) activeParticles++; } -void ParticleSystem::initParticle(particle *p, float t) +void ParticleSystem::initParticle(Particle *p, float t) { float min,max; @@ -298,10 +300,14 @@ void ParticleSystem::initParticle(particle *p, float t) p->spinEnd = calculate_variation(spinEnd, spinStart, spinVariation); p->rotation = (float) rng.random(min, max); + p->angle = p->rotation; + if (relativeRotation) + p->angle += atan2f(p->speed.y, p->speed.x); + p->color = colors[0]; } -void ParticleSystem::insertTop(particle *p) +void ParticleSystem::insertTop(Particle *p) { if (pHead == nullptr) { @@ -317,7 +323,7 @@ void ParticleSystem::insertTop(particle *p) pTail = p; } -void ParticleSystem::insertBottom(particle *p) +void ParticleSystem::insertBottom(Particle *p) { if (pTail == nullptr) { @@ -333,7 +339,7 @@ void ParticleSystem::insertBottom(particle *p) pHead = p; } -void ParticleSystem::insertRandom(particle *p) +void ParticleSystem::insertRandom(Particle *p) { // Nonuniform, but 64-bit is so large nobody will notice. Hopefully. uint64 pos = rng.rand() % ((int64) activeParticles + 1); @@ -341,7 +347,7 @@ void ParticleSystem::insertRandom(particle *p) // Special case where the particle gets inserted before the head. if (pos == activeParticles) { - particle *pA = pHead; + Particle *pA = pHead; if (pA) pA->prev = p; p->prev = nullptr; @@ -351,8 +357,8 @@ void ParticleSystem::insertRandom(particle *p) } // Inserts the particle after the randomly selected particle. - particle *pA = pMem + pos; - particle *pB = pA->next; + Particle *pA = pMem + pos; + Particle *pB = pA->next; pA->next = p; if (pB) pB->prev = p; @@ -362,12 +368,12 @@ void ParticleSystem::insertRandom(particle *p) p->next = pB; } -ParticleSystem::particle *ParticleSystem::removeParticle(particle *p) +ParticleSystem::Particle *ParticleSystem::removeParticle(Particle *p) { // The linked list is updated in this function and old pointers may be // invalidated. The returned pointer will inform the caller of the new // pointer to the next particle. - particle *pNext = nullptr; + Particle *pNext = nullptr; // Removes the particle from the linked list. if (p->prev) @@ -715,6 +721,16 @@ std::vector ParticleSystem::getColor() const return ncolors; } +void ParticleSystem::setRelativeRotation(bool enable) +{ + relativeRotation = enable; +} + +bool ParticleSystem::hasRelativeRotation() const +{ + return relativeRotation; +} + uint32 ParticleSystem::getCount() const { return activeParticles; @@ -802,13 +818,13 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo const Vertex *textureVerts = texture->getVertices(); Vertex *pVerts = particleVerts; - particle *p = pHead; + Particle *p = pHead; // set the vertex data for each particle (transformation, texcoords, color) while (p) { // particle vertices are image vertices transformed by particle information - t.setTransformation(p->position[0], p->position[1], p->rotation, p->size, p->size, offsetX, offsetY, 0.0f, 0.0f); + t.setTransformation(p->position[0], p->position[1], p->angle, p->size, p->size, offsetX, offsetY, 0.0f, 0.0f); t.transform(pVerts, textureVerts, 4); // set the texture coordinate and color data for particle vertices @@ -858,7 +874,7 @@ void ParticleSystem::update(float dt) return; // Traverse all particles and update. - particle *p = pHead; + Particle *p = pHead; while (p) { @@ -903,7 +919,12 @@ void ParticleSystem::update(float dt) const float t = 1.0f - p->life / p->lifetime; // Rotate. - p->rotation += (p->spinStart * (1.0f - t) + p->spinEnd * t)*dt; + p->rotation += (p->spinStart * (1.0f - t) + p->spinEnd * t) * dt; + + p->angle = p->rotation; + + if (relativeRotation) + p->angle += atan2f(p->speed.y, p->speed.x); // Change size according to given intervals: // i = 0 1 2 3 n-1 diff --git a/src/modules/graphics/opengl/ParticleSystem.h b/src/modules/graphics/opengl/ParticleSystem.h index 8ebdf1d8e..8b27192d6 100644 --- a/src/modules/graphics/opengl/ParticleSystem.h +++ b/src/modules/graphics/opengl/ParticleSystem.h @@ -421,6 +421,12 @@ public: **/ std::vector getColor() const; + /** + * sets whether particle angles & rotations are relative to their velocities. + **/ + void setRelativeRotation(bool enable); + bool hasRelativeRotation() const; + /** * Returns the amount of particles that are currently active in the system. **/ @@ -494,11 +500,12 @@ public: static bool getConstant(InsertMode in, const char *&out); protected: + // Represents a single particle. - struct particle + struct Particle { - particle *prev; - particle *next; + Particle *prev; + Particle *next; float lifetime; float life; @@ -518,7 +525,8 @@ protected: float sizeOffset; float sizeIntervalSize; - float rotation; + float rotation; // Amount of rotation applied to the final angle. + float angle; float spinStart; float spinEnd; @@ -526,16 +534,16 @@ protected: }; // Pointer to the beginning of the allocated memory. - particle *pMem; + Particle *pMem; // Pointer to a free particle. - particle *pFree; + Particle *pFree; // Pointer to the start of the linked list. - particle *pHead; + Particle *pHead; // Pointer to the end of the linked list. - particle *pTail; + Particle *pTail; // array of transformed vertex data for all particles, for drawing Vertex *particleVerts; @@ -617,17 +625,19 @@ protected: // Color. std::vector colors; + bool relativeRotation; + void createBuffers(size_t size); void deleteBuffers(); void addParticle(float t); - particle *removeParticle(particle *p); + Particle *removeParticle(Particle *p); // Called by addParticle. - void initParticle(particle *p, float t); - void insertTop(particle *p); - void insertBottom(particle *p); - void insertRandom(particle *p); + void initParticle(Particle *p, float t); + void insertTop(Particle *p); + void insertBottom(Particle *p); + void insertRandom(Particle *p); static StringMap::Entry distributionsEntries[]; static StringMap distributions; diff --git a/src/modules/graphics/opengl/wrap_ParticleSystem.cpp b/src/modules/graphics/opengl/wrap_ParticleSystem.cpp index 6e875b645..6cb3c0416 100644 --- a/src/modules/graphics/opengl/wrap_ParticleSystem.cpp +++ b/src/modules/graphics/opengl/wrap_ParticleSystem.cpp @@ -569,6 +569,20 @@ int w_ParticleSystem_getColors(lua_State *L) return colors.size(); } +int w_ParticleSystem_setRelativeRotation(lua_State *L) +{ + ParticleSystem *t = luax_checkparticlesystem(L, 1); + t->setRelativeRotation(luax_toboolean(L, 2)); + return 0; +} + +int w_ParticleSystem_hasRelativeRotation(lua_State *L) +{ + ParticleSystem *t = luax_checkparticlesystem(L, 1); + luax_pushboolean(L, t->hasRelativeRotation()); + return 1; +} + int w_ParticleSystem_getCount(lua_State *L) { ParticleSystem *t = luax_checkparticlesystem(L, 1); @@ -687,6 +701,8 @@ static const luaL_Reg functions[] = { "getColors", w_ParticleSystem_getColors }, { "setOffset", w_ParticleSystem_setOffset }, { "getOffset", w_ParticleSystem_getOffset }, + { "setRelativeRotation", w_ParticleSystem_setRelativeRotation }, + { "hasRelativeRotation", w_ParticleSystem_hasRelativeRotation }, { "getCount", w_ParticleSystem_getCount }, { "start", w_ParticleSystem_start }, { "stop", w_ParticleSystem_stop }, diff --git a/src/modules/graphics/opengl/wrap_ParticleSystem.h b/src/modules/graphics/opengl/wrap_ParticleSystem.h index 08948c386..b3c96a54f 100644 --- a/src/modules/graphics/opengl/wrap_ParticleSystem.h +++ b/src/modules/graphics/opengl/wrap_ParticleSystem.h @@ -77,6 +77,8 @@ int w_ParticleSystem_setColors(lua_State *L); int w_ParticleSystem_getColors(lua_State *L); int w_ParticleSystem_setOffset(lua_State *L); int w_ParticleSystem_getOffset(lua_State *L); +int w_ParticleSystem_setRelativeRotation(lua_State *L); +int w_ParticleSystem_hasRelativeRotation(lua_State *L); int w_ParticleSystem_getCount(lua_State *L); int w_ParticleSystem_start(lua_State *L); int w_ParticleSystem_stop(lua_State *L);