From 2425ea997956d874fc05a42290d7f43e7e6e0684 Mon Sep 17 00:00:00 2001 From: vrld Date: Wed, 6 Apr 2011 21:24:09 +0200 Subject: [PATCH] Change particle system to accept an arbitrary number of colors and sizes to inerpolate. API changes: - ParticleSystem:setSize(min, max, var) -> ParticleSystem:setSizes(s0, ..., sN) !! ParticleSystem:setSize() drops variation parameter !! - ParticleSystem:setColor([color1], [color2]) -> ParticleSystem:setColor([color1], ..., [colorN]) --HG-- branch : minor --- .../graphics/opengl/ParticleSystem.cpp | 94 ++++++++++--------- src/modules/graphics/opengl/ParticleSystem.h | 33 +++---- .../graphics/opengl/wrap_ParticleSystem.cpp | 54 ++++++----- .../graphics/opengl/wrap_ParticleSystem.h | 4 +- 4 files changed, 93 insertions(+), 92 deletions(-) diff --git a/src/modules/graphics/opengl/ParticleSystem.cpp b/src/modules/graphics/opengl/ParticleSystem.cpp index d1f3d2589..2d58042c0 100644 --- a/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/src/modules/graphics/opengl/ParticleSystem.cpp @@ -25,7 +25,6 @@ #include #include #include -#include namespace love { @@ -34,6 +33,13 @@ namespace graphics namespace opengl { + namespace + { + Colorf colorToFloat(const Color& c) { + return Colorf( (GLfloat)c.r/255.0f, (GLfloat)c.g/255.0f, (GLfloat)c.b/255.0f, (GLfloat)c.a/255.0f ); + } + } + float calculate_variation(float inner, float outer, float var) { float low = inner - (outer/2.0f)*var; @@ -48,14 +54,14 @@ namespace opengl direction(0), spread(0), relative(false), speedMin(0), speedMax(0), gravityMin(0), gravityMax(0), radialAccelerationMin(0), radialAccelerationMax(0), tangentialAccelerationMin(0), tangentialAccelerationMax(0), - sizeStart(1), sizeEnd(1), sizeVariation(0), rotationMin(0), rotationMax(0), + sizeVariation(0), rotationMin(0), rotationMax(0), spinStart(0), spinEnd(0), spinVariation(0), offsetX(sprite->getWidth()*0.5f), offsetY(sprite->getHeight()*0.5f) { this->sprite = sprite; sprite->retain(); - memset(colorStart, 255, 4); - memset(colorEnd, 255, 4); + sizes.push_back(1.0f); + colors.push_back( Colorf(1.0f, 1.0f, 1.0f, 1.0f) ); setBufferSize(buffer); } @@ -107,9 +113,9 @@ namespace opengl max = tangentialAccelerationMax; pLast->tangentialAcceleration = (rand() / (float(RAND_MAX)+1)) * (max - min) + min; - pLast->sizeStart = calculate_variation(sizeStart, sizeEnd, sizeVariation); - pLast->sizeEnd = calculate_variation(sizeEnd, sizeStart, sizeVariation); - pLast->size = pLast->sizeStart; + pLast->sizeOffset = (rand() / (float(RAND_MAX)+1)) * sizeVariation; // time offset for size change + pLast->sizeIntervalSize = (1.0 - (rand() / (float(RAND_MAX)+1)) * sizeVariation) - pLast->sizeOffset; + pLast->size = sizes[(size_t)(pLast->sizeOffset - .5f) * (sizes.size() - 1)]; min = rotationMin; max = rotationMax; @@ -117,10 +123,7 @@ namespace opengl pLast->spinEnd = calculate_variation(spinEnd, spinStart, spinVariation); pLast->rotation = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;; - pLast->color[0] = (float)colorStart[0] / 255; - pLast->color[1] = (float)colorStart[1] / 255; - pLast->color[2] = (float)colorStart[2] / 255; - pLast->color[3] = (float)colorStart[3] / 255; + pLast->color = colors[0]; pLast++; } @@ -237,20 +240,13 @@ namespace opengl void ParticleSystem::setSize(float size) { - sizeStart = size; - sizeEnd = size; + sizes.resize(1); + sizes[0] = size; } - void ParticleSystem::setSize(float start, float end) + void ParticleSystem::setSize(const std::vector& newSizes, float variation) { - sizeStart = start; - sizeEnd = end; - } - - void ParticleSystem::setSize(float start, float end, float variation) - { - sizeStart = start; - sizeEnd = end; + sizes = newSizes; sizeVariation = variation; } @@ -294,16 +290,17 @@ namespace opengl spinVariation = variation; } - void ParticleSystem::setColor(unsigned char * color) + void ParticleSystem::setColor(const Color& color) { - memcpy(colorStart, color, 4); - memcpy(colorEnd, color, 4); + colors.resize(1); + colors[0] = colorToFloat(color); } - void ParticleSystem::setColor(unsigned char * start, unsigned char * end) + void ParticleSystem::setColor(const std::vector& newColors) { - memcpy(colorStart, start, 4); - memcpy(colorEnd, end, 4); + colors.resize( newColors.size() ); + for (size_t i = 0; i < newColors.size(); ++i) + colors[i] = colorToFloat( newColors[i] ); } void ParticleSystem::setOffset(float x, float y) @@ -403,12 +400,8 @@ namespace opengl { glPushMatrix(); - glColor4f(p->color[0],p->color[1],p->color[2],p->color[3]); - glTranslatef(p->position[0],p->position[1],0.0f); - glRotatef(LOVE_TODEG(p->rotation), 0.0f, 0.0f, 1.0f); // rad * (180 / pi) - glScalef(p->size,p->size,1.0f); - glTranslatef(-offsetX,-offsetY,0.0f); - sprite->draw(0,0, 0, 1, 1, 0, 0); + glColor4f(p->color.r, p->color.g, p->color.b, p->color.a); + sprite->draw(p->position[0], p->position[1], p->rotation, p->size, p->size, offsetX, offsetY); glPopMatrix(); p++; @@ -481,19 +474,32 @@ namespace opengl p->position[0] = ppos.getX(); p->position[1] = ppos.getY(); - const float t = p->life / p->lifetime; - - // Change size. - p->size = p->sizeEnd - ((p->sizeEnd - p->sizeStart) * t); + const float t = 1.0f - p->life / p->lifetime; // Rotate. - p->rotation += (p->spinStart*(1-t) + p->spinEnd*t)*dt; + p->rotation += (p->spinStart * (1.0f - t) + p->spinEnd * t)*dt; - // Update color. - p->color[0] = (float)(colorEnd[0]*(1.0f-t) + colorStart[0] * t)/255.0f; - p->color[1] = (float)(colorEnd[1]*(1.0f-t) + colorStart[1] * t)/255.0f; - p->color[2] = (float)(colorEnd[2]*(1.0f-t) + colorStart[2] * t)/255.0f; - p->color[3] = (float)(colorEnd[3]*(1.0f-t) + colorStart[3] * t)/255.0f; + // Change size according to given intervals: + // i = 0 1 2 3 n-1 + // |-------|-------|------|--- ... ---| + // t = 0 1/(n-1) 3/(n-1) 1 + // + // `s' is the interpolation variable scaled to the current + // interval width, e.g. if n = 5 and t = 0.3, then the current + // indices are 1,2 and s = 0.3 - 0.25 = 0.05 + float s = p->sizeOffset + t * p->sizeIntervalSize; // size variation + s *= (float)(sizes.size() - 1); // 0 <= s < sizes.size() + size_t i = (size_t)s; + size_t k = (i == sizes.size() - 1) ? i : i + 1; // boundary check (prevents failing on t = 1.0f) + s -= (float)i; // transpose s to be in interval [0:1]: i <= s < i + 1 ~> 0 <= s < 1 + p->size = sizes[i] * (1.0f - t) + sizes[k] * t; + + // Update color according to given intervals (as above) + s = t * (float)(colors.size() - 1); + i = (size_t)s; + k = (i == colors.size() - 1) ? i : i + 1; + s -= (float)i; // 0 <= s <= 1 + p->color = colors[i] * (1.0f - s) + colors[k] * s; // Next particle. p++; diff --git a/src/modules/graphics/opengl/ParticleSystem.h b/src/modules/graphics/opengl/ParticleSystem.h index 3370f47ec..6693f46c7 100644 --- a/src/modules/graphics/opengl/ParticleSystem.h +++ b/src/modules/graphics/opengl/ParticleSystem.h @@ -26,7 +26,9 @@ #include #include #include +#include #include "Image.h" +#include namespace love { @@ -50,14 +52,14 @@ namespace opengl float tangentialAcceleration; float size; - float sizeStart; - float sizeEnd; + float sizeOffset; + float sizeIntervalSize; float rotation; float spinStart; float spinEnd; - float color[4]; + Colorf color; }; /** @@ -127,8 +129,7 @@ namespace opengl float tangentialAccelerationMax; // Size. - float sizeStart; - float sizeEnd; + std::vector sizes; float sizeVariation; // Rotation @@ -145,8 +146,7 @@ namespace opengl float offsetY; // Color. - unsigned char colorStart[4]; - unsigned char colorEnd[4]; + std::vector colors; void add(); void remove(particle * p); @@ -278,20 +278,12 @@ namespace opengl **/ void setSize(float size); - /** - * Sets the size of the sprite upon creation and upon death (1.0 being the default size). - * @param start The size of the sprite upon creation - * @param end The size of the sprite upon death. - **/ - void setSize(float start, float end); - /** * Sets the size of the sprite upon creation and upon death (1.0 being the default size) and any variation. - * @param start The size of the sprite upon creation - * @param end The size of the sprite upon death. + * @param newSizes Array of sizes * @param variation The amount of variation on the starting size (0 being no variation and 1.0 a random size between start and end). **/ - void setSize(float start, float end, float variation); + void setSize(const std::vector& newSizes, float variation = 0.0f); /** * Sets the amount of variation to the sprite's beginning size (0 being no variation and 1.0 a random size between start and end). @@ -343,7 +335,7 @@ namespace opengl * Sets the color of the particles. * @param color The color. **/ - void setColor(unsigned char * color); + void setColor(const Color& color); /** * Sets the particles' offsets for rotation. @@ -354,10 +346,9 @@ namespace opengl /** * Sets the color of the particles. - * @param start The color of the particle when created. - * @param end The color of the particle upon death. + * @param newColors Array of colors **/ - void setColor(unsigned char * start, unsigned char * end); + void setColor(const std::vector& newColors); /** * Returns the x-coordinate of the emitter's position. diff --git a/src/modules/graphics/opengl/wrap_ParticleSystem.cpp b/src/modules/graphics/opengl/wrap_ParticleSystem.cpp index d5025b824..8c6383cf3 100644 --- a/src/modules/graphics/opengl/wrap_ParticleSystem.cpp +++ b/src/modules/graphics/opengl/wrap_ParticleSystem.cpp @@ -143,13 +143,19 @@ namespace opengl return 0; } - int w_ParticleSystem_setSize(lua_State * L) + int w_ParticleSystem_setSizes(lua_State * L) { ParticleSystem * t = luax_checkparticlesystem(L, 1); - float arg1 = (float)luaL_checknumber(L, 2); - float arg2 = (float)luaL_optnumber(L, 3, arg1); - float arg3 = (float)luaL_optnumber(L, 4, 0); - t->setSize(arg1, arg2, arg3); + size_t nSizes = lua_gettop(L) - 1; + if (nSizes == 1) { + t->setSize(luaL_checknumber(L, 2)); + } else { + std::vector sizes(nSizes); + for (size_t i = 0; i < nSizes; ++i) + sizes[i] = luaL_checknumber(L, 1 + i + 1); + + t->setSize(sizes); + } return 0; } @@ -188,28 +194,26 @@ namespace opengl return 0; } - int w_ParticleSystem_setColor(lua_State * L) + int w_ParticleSystem_setColors(lua_State * L) { ParticleSystem * t = luax_checkparticlesystem(L, 1); - - unsigned char start[4]; + size_t nColors = (lua_gettop(L) - 1) / 4; - start[0] = (unsigned char)luaL_checkint(L, 2); - start[1] = (unsigned char)luaL_checkint(L, 3); - start[2] = (unsigned char)luaL_checkint(L, 4); - start[3] = (unsigned char)luaL_checkint(L, 5); - - if(lua_gettop(L) > 5) - { - unsigned char end[4]; - end[0] = (unsigned char)luaL_checkint(L, 6); - end[1] = (unsigned char)luaL_checkint(L, 7); - end[2] = (unsigned char)luaL_checkint(L, 8); - end[3] = (unsigned char)luaL_checkint(L, 9); - t->setColor(start, end); + if (nColors == 1) { + t->setColor(Color(luaL_checkint(L,2), + luaL_checkint(L,3), + luaL_checkint(L,4), + luaL_checkint(L,5))); + } else { + std::vector colors(nColors); + for (size_t i = 0; i < nColors; ++i) { + colors[i] = Color(luaL_checkint(L, 1 + i*4 + 1), + luaL_checkint(L, 1 + i*4 + 2), + luaL_checkint(L, 1 + i*4 + 3), + luaL_checkint(L, 1 + i*4 + 4)); + } + t->setColor(colors); } - else - t->setColor(start); return 0; } @@ -343,12 +347,12 @@ namespace opengl { "setGravity", w_ParticleSystem_setGravity }, { "setRadialAcceleration", w_ParticleSystem_setRadialAcceleration }, { "setTangentialAcceleration", w_ParticleSystem_setTangentialAcceleration }, - { "setSize", w_ParticleSystem_setSize }, + { "setSizes", w_ParticleSystem_setSizes }, { "setSizeVariation", w_ParticleSystem_setSizeVariation }, { "setRotation", w_ParticleSystem_setRotation }, { "setSpin", w_ParticleSystem_setSpin }, { "setSpinVariation", w_ParticleSystem_setSpinVariation }, - { "setColor", w_ParticleSystem_setColor }, + { "setColors", w_ParticleSystem_setColors }, { "setOffset", w_ParticleSystem_setOffset }, { "getX", w_ParticleSystem_getX }, { "getY", w_ParticleSystem_getY }, diff --git a/src/modules/graphics/opengl/wrap_ParticleSystem.h b/src/modules/graphics/opengl/wrap_ParticleSystem.h index 6679191e0..093458afd 100644 --- a/src/modules/graphics/opengl/wrap_ParticleSystem.h +++ b/src/modules/graphics/opengl/wrap_ParticleSystem.h @@ -46,12 +46,12 @@ namespace opengl int w_ParticleSystem_setGravity(lua_State * L); int w_ParticleSystem_setRadialAcceleration(lua_State * L); int w_ParticleSystem_setTangentialAcceleration(lua_State * L); - int w_ParticleSystem_setSize(lua_State * L); + int w_ParticleSystem_setSizes(lua_State * L); int w_ParticleSystem_setSizeVariation(lua_State * L); int w_ParticleSystem_setRotation(lua_State * L); int w_ParticleSystem_setSpin(lua_State * L); int w_ParticleSystem_setSpinVariation(lua_State * L); - int w_ParticleSystem_setColor(lua_State * L); + int w_ParticleSystem_setColors(lua_State * L); int w_ParticleSystem_setOffset(lua_State * L); int w_ParticleSystem_getX(lua_State * L); int w_ParticleSystem_getY(lua_State * L);