Add sprite frame and animation descriptors support

This commit is contained in:
DelinWorks 2022-05-21 16:48:46 +03:00
parent 6ca5481edf
commit c9ff24e830
3 changed files with 384 additions and 53 deletions

View File

@ -1,3 +1,4 @@
#include "CCParticleSystem.h"
/**************************************************************************** /****************************************************************************
Copyright (c) 2008-2010 Ricardo Quesada Copyright (c) 2008-2010 Ricardo Quesada
Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2010-2012 cocos2d-x.org
@ -98,7 +99,7 @@ inline void normalize_point(float x, float y, particle_point* out)
} }
/** /**
A more effect random number getter function, get from ejoy2d. A more effective random number generator function, made by ejoy2d.
*/ */
inline static float RANDOM_M11(unsigned int* seed) inline static float RANDOM_M11(unsigned int* seed)
{ {
@ -136,10 +137,14 @@ bool ParticleData::init(int count)
size = (float*)malloc(count * sizeof(float)); size = (float*)malloc(count * sizeof(float));
deltaSize = (float*)malloc(count * sizeof(float)); deltaSize = (float*)malloc(count * sizeof(float));
rotation = (float*)malloc(count * sizeof(float)); rotation = (float*)malloc(count * sizeof(float));
staticRotation = (float*)malloc(count * sizeof(float));
deltaRotation = (float*)malloc(count * sizeof(float)); deltaRotation = (float*)malloc(count * sizeof(float));
totalTimeToLive = (float*)malloc(count * sizeof(float)); totalTimeToLive = (float*)malloc(count * sizeof(float));
timeToLive = (float*)malloc(count * sizeof(float)); timeToLive = (float*)malloc(count * sizeof(float));
animCellIndex = (unsigned int*)malloc(count * sizeof(unsigned int)); animTimeDelta = (float*)malloc(count * sizeof(float));
animTimeLength = (float*)malloc(count * sizeof(float));
animIndex = (unsigned short*)malloc(count * sizeof(unsigned short));
animCellIndex = (unsigned short*)malloc(count * sizeof(unsigned short));
atlasIndex = (unsigned int*)malloc(count * sizeof(unsigned int)); atlasIndex = (unsigned int*)malloc(count * sizeof(unsigned int));
modeA.dirX = (float*)malloc(count * sizeof(float)); modeA.dirX = (float*)malloc(count * sizeof(float));
@ -175,9 +180,13 @@ void ParticleData::release()
CC_SAFE_FREE(size); CC_SAFE_FREE(size);
CC_SAFE_FREE(deltaSize); CC_SAFE_FREE(deltaSize);
CC_SAFE_FREE(rotation); CC_SAFE_FREE(rotation);
CC_SAFE_FREE(staticRotation);
CC_SAFE_FREE(deltaRotation); CC_SAFE_FREE(deltaRotation);
CC_SAFE_FREE(totalTimeToLive); CC_SAFE_FREE(totalTimeToLive);
CC_SAFE_FREE(timeToLive); CC_SAFE_FREE(timeToLive);
CC_SAFE_FREE(animTimeDelta);
CC_SAFE_FREE(animTimeLength);
CC_SAFE_FREE(animIndex);
CC_SAFE_FREE(animCellIndex); CC_SAFE_FREE(animCellIndex);
CC_SAFE_FREE(atlasIndex); CC_SAFE_FREE(atlasIndex);
@ -229,9 +238,13 @@ ParticleSystem::ParticleSystem()
, _opacityModifyRGB(false) , _opacityModifyRGB(false)
, _isLifeAnimated(false) , _isLifeAnimated(false)
, _isEmitterAnimated(false) , _isEmitterAnimated(false)
, _isLoopAnimated(false)
, _isAnimationAtlas(false)
, _animDir(TexAnimDir::VERTICAL) , _animDir(TexAnimDir::VERTICAL)
, _animUnifiedSize(0) , _animUnifiedSize(1)
, _animIndexCount(0)
, _isLifeAnimationReversed(false) , _isLifeAnimationReversed(false)
, _isAnimationMulti(false)
, _yCoordFlipped(1) , _yCoordFlipped(1)
, _positionType(PositionType::FREE) , _positionType(PositionType::FREE)
, _paused(false) , _paused(false)
@ -613,16 +626,21 @@ ParticleSystem::~ParticleSystem()
// it is not needed to call "unscheduleUpdate" here. In fact, it will be called in "cleanup" // it is not needed to call "unscheduleUpdate" here. In fact, it will be called in "cleanup"
// unscheduleUpdate(); // unscheduleUpdate();
_particleData.release(); _particleData.release();
_animations.clear();
CC_SAFE_RELEASE(_texture); CC_SAFE_RELEASE(_texture);
} }
void ParticleSystem::addParticles(int count, int animationCellIndex) void ParticleSystem::addParticles(int count, int animationCellIndex, int animationIndex)
{ {
if (_paused) if (_paused)
return; return;
uint32_t RANDSEED = rand(); uint32_t RANDSEED = rand();
if (_isAnimationAtlas)
{
animationCellIndex = MIN(animationCellIndex, getTotalAnimationCells() - 1); animationCellIndex = MIN(animationCellIndex, getTotalAnimationCells() - 1);
animationIndex = MIN(animationIndex, _animIndexCount - 1);
}
int start = _particleCount; int start = _particleCount;
_particleCount += count; _particleCount += count;
@ -662,6 +680,47 @@ void ParticleSystem::addParticles(int count, int animationCellIndex)
} }
} }
if (animationIndex == -1 && !_isAnimationMulti && _isLoopAnimated)
{
for (int i = start; i < _particleCount; ++i)
{
_particleData.animIndex[i] = 0;
auto descriptor = _animations.at(_particleData.animIndex[i]);
_particleData.animTimeLength[i] =
descriptor.animationSpeed + descriptor.animationSpeedVariance * RANDOM_M11(&RANDSEED);
}
}
if (animationIndex == -1 && _isAnimationMulti && _isLoopAnimated)
{
for (int i = start; i < _particleCount; ++i)
{
_particleData.animIndex[i] = _randomAnimations[abs(RANDOM_M11(&RANDSEED) * _randomAnimations.size())];
auto descriptor = _animations.at(_particleData.animIndex[i]);
_particleData.animTimeLength[i] =
descriptor.animationSpeed + descriptor.animationSpeedVariance * RANDOM_M11(&RANDSEED);
}
}
if (_isLoopAnimated)
{
for (int i = start; i < _particleCount; ++i)
{
_particleData.animTimeDelta[i] = 0;
}
}
if (animationIndex != -1)
{
for (int i = start; i < _particleCount; ++i)
{
_particleData.animIndex[i] = animationIndex;
auto descriptor = _animations.at(_particleData.animIndex[i]);
_particleData.animTimeLength[i] =
descriptor.animationSpeed + descriptor.animationSpeedVariance * RANDOM_M11(&RANDSEED);
}
}
// color // color
#define SET_COLOR(c, b, v) \ #define SET_COLOR(c, b, v) \
for (int i = start; i < _particleCount; ++i) \ for (int i = start; i < _particleCount; ++i) \
@ -725,6 +784,12 @@ void ParticleSystem::addParticles(int count, int animationCellIndex)
_particleData.deltaRotation[i] = (endA - _particleData.rotation[i]) / _particleData.timeToLive[i]; _particleData.deltaRotation[i] = (endA - _particleData.rotation[i]) / _particleData.timeToLive[i];
} }
// static rotation
for (int i = start; i < _particleCount; ++i)
{
_particleData.staticRotation[i] = _staticRotation + _staticRotationVar * RANDOM_M11(&RANDSEED);
}
// position // position
Vec2 pos; Vec2 pos;
if (_positionType == PositionType::FREE) if (_positionType == PositionType::FREE)
@ -829,6 +894,84 @@ void ParticleSystem::addParticles(int count, int animationCellIndex)
} }
} }
void ParticleSystem::setAnimationDescriptor(unsigned short indexOfDescriptor,
float time,
float timeVariance,
std::vector<unsigned short> indices,
bool reverse)
{
ParticleAnimationDescriptor desc{};
desc.animationSpeed = time;
desc.animationSpeedVariance = timeVariance;
desc.animationIndices = indices;
desc.reverseIndices = reverse;
if (_animations.find(indexOfDescriptor) == _animations.end())
_animations.insert({indexOfDescriptor, desc});
else
{
_animations.erase(indexOfDescriptor);
_animations.insert({indexOfDescriptor, desc});
}
}
void ParticleSystem::resetAnimationIndices()
{
_animIndexCount = 0;
_animationIndices.clear();
}
void ParticleSystem::resetAnimationDescriptors()
{
_animations.clear();
_randomAnimations.clear();
}
void ParticleSystem::setMultiAnimationRandom()
{
_randomAnimations.clear();
for (auto& a : _animations)
_randomAnimations.push_back(a.first);
}
void ParticleSystem::addAnimationIndex(std::string_view frameName)
{
addAnimationIndex(_animIndexCount++, frameName);
}
void ParticleSystem::addAnimationIndex(unsigned short index, std::string_view frameName)
{
auto frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(frameName);
if (frame)
addAnimationIndex(index, frame);
}
void ParticleSystem::addAnimationIndex(cocos2d::SpriteFrame* frame)
{
addAnimationIndex(_animIndexCount++, frame);
}
void ParticleSystem::addAnimationIndex(unsigned short index, cocos2d::SpriteFrame* frame)
{
//Not sure how to check texture equality truly but it won't hurt to skip it
//CCASSERT(frame->getTexture() == _texture, "Sprite frame texture and particle system texture should match!");
ParticleFrameDescriptor desc{};
desc.rect = frame->getRect();
desc.isRotated = frame->isRotated();
if (_animationIndices.find(index) == _animationIndices.end())
_animationIndices.insert({index, desc});
else
{
_animationIndices.erase(index);
_animationIndices.insert({index, desc});
}
}
void ParticleSystem::onEnter() void ParticleSystem::onEnter()
{ {
Node::onEnter(); Node::onEnter();
@ -908,12 +1051,37 @@ void ParticleSystem::update(float dt)
for (int i = 0; i < _particleCount; ++i) for (int i = 0; i < _particleCount; ++i)
{ {
_particleData.timeToLive[i] -= dt; _particleData.timeToLive[i] -= dt;
if (_isLifeAnimated) if (_isLifeAnimated && _animations.empty())
{ {
float percent = (_particleData.totalTimeToLive[i] - _particleData.timeToLive[i]) / _particleData.totalTimeToLive[i]; float percent = (_particleData.totalTimeToLive[i] - _particleData.timeToLive[i]) / _particleData.totalTimeToLive[i];
percent = _isLifeAnimationReversed ? 1 - percent : percent; percent = _isLifeAnimationReversed ? 1.0F - percent : percent;
_particleData.animCellIndex[i] = (unsigned int)MIN((percent * getTotalAnimationCells()), getTotalAnimationCells() - 1); _particleData.animCellIndex[i] = (unsigned int)MIN((percent * getTotalAnimationCells()), getTotalAnimationCells() - 1);
} }
if (_isLifeAnimated && !_animations.empty())
{
auto& anim = _animations.begin()->second;
float percent =
(_particleData.totalTimeToLive[i] - _particleData.timeToLive[i]) / _particleData.totalTimeToLive[i];
percent = (!!_isLifeAnimationReversed != !!anim.reverseIndices) ? 1.0F - percent : percent;
_particleData.animCellIndex[i] = anim.animationIndices[MIN(abs(percent * anim.animationIndices.size()),
anim.animationIndices.size() - 1)];
}
if (_isLoopAnimated)
{
auto& anim = _animations.at(_particleData.animIndex[i]);
_particleData.animTimeDelta[i] += dt;
if (_particleData.animTimeDelta[i] >= _particleData.animTimeLength[i])
_particleData.animTimeDelta[i] = 0;
float percent = _particleData.animTimeDelta[i] / _particleData.animTimeLength[i];
percent = anim.reverseIndices ? 1.0F - percent : percent;
_particleData.animCellIndex[i] = anim.animationIndices[MIN(abs(percent * anim.animationIndices.size()),
anim.animationIndices.size() - 1)];
}
} }
for (int i = 0; i < _particleCount; ++i) for (int i = 0; i < _particleCount; ++i)

View File

@ -52,6 +52,20 @@ struct particle_point
float y; float y;
}; };
struct ParticleAnimationDescriptor
{
float animationSpeed;
float animationSpeedVariance;
std::vector<unsigned short> animationIndices;
bool reverseIndices;
};
struct ParticleFrameDescriptor
{
cocos2d::Rect rect;
bool isRotated;
};
class CC_DLL ParticleData class CC_DLL ParticleData
{ {
public: public:
@ -73,10 +87,14 @@ public:
float* size; float* size;
float* deltaSize; float* deltaSize;
float* rotation; float* rotation;
float* staticRotation;
float* deltaRotation; float* deltaRotation;
float* totalTimeToLive; float* totalTimeToLive;
float* timeToLive; float* timeToLive;
unsigned int* animCellIndex; float* animTimeDelta;
float* animTimeLength;
unsigned short* animIndex;
unsigned short* animCellIndex;
unsigned int* atlasIndex; unsigned int* atlasIndex;
//! Mode A: gravity, direction, radial accel, tangential accel //! Mode A: gravity, direction, radial accel, tangential accel
@ -267,7 +285,7 @@ public:
static Vector<ParticleSystem*>& getAllParticleSystems(); static Vector<ParticleSystem*>& getAllParticleSystems();
public: public:
void addParticles(int count, int animationCellIndex = -1); void addParticles(int count, int animationCellIndex = -1, int animationIndex = -1);
void stopSystem(); void stopSystem();
/** Kill all living particles. /** Kill all living particles.
@ -717,6 +735,17 @@ public:
*/ */
void setEndSpinVar(float endSpinVar) { _endSpinVar = endSpinVar; } void setEndSpinVar(float endSpinVar) { _endSpinVar = endSpinVar; }
/** Sets the static rotation of each particle
*
* @param angle The angle in degrees that the particle will exist with
*/
virtual void setStaticRotation(float angle) { _staticRotation = angle; };
/** Sets the static rotation variance of each particle.
*
* @param angle The angle in degrees variance
*/
virtual void setStaticRotationVar(float angle) { _staticRotationVar = angle; };
/** Gets the emission rate of the particles. /** Gets the emission rate of the particles.
* *
* @return The emission rate of the particles. * @return The emission rate of the particles.
@ -744,11 +773,32 @@ public:
bool isOpacityModifyRGB() const override { return _opacityModifyRGB; } bool isOpacityModifyRGB() const override { return _opacityModifyRGB; }
/** Enables or disables tex coord animations that are set based on particle life. */ /** Enables or disables tex coord animations that are set based on particle life. */
void setLifeAnimation(bool enabled) { _isLifeAnimated = enabled; } void setLifeAnimation(bool enabled)
{
_isLifeAnimated = enabled;
_isEmitterAnimated = false;
_isLoopAnimated = false;
}
/** Enables or disables tex coord animations that are set by the emitter randomly when a particle is emitted. /** Enables or disables tex coord animations that are set by the emitter randomly when a particle is emitted.
* WARNING: this won't matter if particle life animation is enabled ie. setLifeAnimation(true) */ * WARNING: this won't matter if particle life animation is enabled ie. setLifeAnimation(true) */
void setEmitterAnimation(bool enabled) { _isEmitterAnimated = enabled; } void setEmitterAnimation(bool enabled)
{
_isEmitterAnimated = enabled;
_isLifeAnimated = false;
_isLoopAnimated = false;
}
/** Enables or disables tex coord animations that are used to make particles play a sequence forever until they die
* This interduces a new concept of animation where you specify the indices and then specify animations descriptors that tell how these indices are used and what speed they're played at.
* Functions that effect this are: setMultiAnimationParticles(), resetAnimationDescriptors(), resetAnimationIndices(), addAnimationIndex(), setAnimationDescriptor(), setMultiAnimationRandom(), setMultiAnimationRandomSpecific(),
*/
void setLoopAnimation(bool enabled)
{
_isLoopAnimated = enabled;
_isEmitterAnimated = false;
_isLifeAnimated = false;
}
bool isLifeAnimated() { return _isLifeAnimated; } bool isLifeAnimated() { return _isLifeAnimated; }
bool isEmitterAnimated() { return _isEmitterAnimated; } bool isEmitterAnimated() { return _isEmitterAnimated; }
@ -781,14 +831,82 @@ public:
} }
/** Gets the total cells viewable in a texture by dividing texture height or width into animation cell size /** Gets the total cells viewable in a texture by dividing texture height or width into animation cell size
* animation cell size can be changed using setAnimationCellUnifiedSize(int) */ * animation cell size can be changed using setAnimationCellUnifiedSize(int)
int getTotalAnimationCells() { return getAnimationPixels() / _animUnifiedSize; } * incase atlas animation is set off it will return the indices added through addAnimationIndex() */
int getTotalAnimationCells() { return _isAnimationAtlas ? getAnimationPixels() / _animUnifiedSize : _animIndexCount; }
/** Sets wether to start from first cell and go forward (normal) /** Sets wether to start from first cell and go forward (normal)
* or last cell and go backward (reversed) when using life animation */ * or last cell and go backward (reversed) when using life animation */
void setLifeAnimationReverse(bool reverse) { _isLifeAnimationReversed = reverse; } void setLifeAnimationReverse(bool reverse) { _isLifeAnimationReversed = reverse; }
bool isAnimationLifeReversed() { return _isLifeAnimationReversed; } bool isAnimationLifeReversed() { return _isLifeAnimationReversed; }
/** Sets wether to use atlas rendering or sprite frame rendering */
void setAnimationAtlas(bool atlas) { _isAnimationAtlas = atlas; }
bool isAnimationAtlas() { return _isAnimationAtlas; }
/** Sets wether to use multiable different index animations that can be randomly choosen for particles */
void setMultiAnimationParticles(bool multi) { _isAnimationMulti = multi; }
bool isMultiAnimationParticles() { return _isAnimationMulti; }
/** Resets the count of indices to 0 and empties the index array */
void resetAnimationIndices();
/** Resets the container of animation descriptors empties the random array */
void resetAnimationDescriptors();
/** Choose what animation descriptors are to be selected at random for particles
* This function should be called after you've inserted/overwritten any animation descriptors.
*
* @param animations Array of specific animations to play at random
*/
void setMultiAnimationRandomSpecific(std::vector<unsigned short> animations) { _randomAnimations = animations; };
/** Choose ALL animation descriptors to be selected at random for particles.
* This function should be called after you've inserted/overwritten any animation descriptors.
*/
void setMultiAnimationRandom();
/** Add a particle animation index based on tex coords spicified using a sprite frame if atlas mode is off.
* The index is automatically incremented on each addition.
*
* @param frameName SpriteFrame name to search for
*/
void addAnimationIndex(std::string_view frameName);
/** Add a particle animation index based on tex coords spicified using a sprite frame if atlas mode is off.
*
* @param frameName SpriteFrame name to search for
*/
void addAnimationIndex(unsigned short index, std::string_view frameName);
/** Add a particle animation index based on tex coords spicified using a sprite frame if atlas mode is off.
* The index is automatically incremented on each addition.
*
* @param frame SpriteFrame containting data about tex coords
*/
void addAnimationIndex(cocos2d::SpriteFrame* frame);
/** Add a particle animation index based on tex coords spicified using a sprite frame if atlas mode is off.
* you can specify which index you want to override in this function
* @param index Index id to override the index with
* @param frame SpriteFrame containting data about tex coords
*/
void addAnimationIndex(unsigned short index, cocos2d::SpriteFrame* frame);
/** Add a particle animation descriptor with an index.
*
* @param indexOfDescriptor Index of the animation to be added, adding to the same index will just override the pervious animation descriptor
* @param time length of the animation in seconds
* @param timeVariance Time randomly selected for each different particle added on the animation length
* @param indices An array of the indicies
* @param reverse Should the animation indicies be played backwards? (default: false)
*/
void setAnimationDescriptor(unsigned short indexOfDescriptor,
float time,
float timeVariance,
std::vector<unsigned short> indices,
bool reverse = false);
/** Gets the particles movement type: Free or Grouped. /** Gets the particles movement type: Free or Grouped.
@since v0.8 @since v0.8
* *
@ -1026,6 +1144,10 @@ protected:
float _endSpin; float _endSpin;
//* initial angle of each particle //* initial angle of each particle
float _endSpinVar; float _endSpinVar;
//* initial rotation of each particle
float _staticRotation;
//* initial rotation of each particle
float _staticRotationVar;
/** emission rate of the particles */ /** emission rate of the particles */
float _emissionRate; float _emissionRate;
/** maximum particles of the system */ /** maximum particles of the system */
@ -1040,12 +1162,27 @@ protected:
bool _isLifeAnimated; bool _isLifeAnimated;
/** is the emitter particle system animated */ /** is the emitter particle system animated */
bool _isEmitterAnimated; bool _isEmitterAnimated;
/** is the emitter particle system animated */
bool _isLoopAnimated;
/** True if you want to use an atlas with a fixed cell size
* False if you want to use SpriteFrames as your indexes using the function addAnimationIndex() */
bool _isAnimationAtlas;
/** tex coord animation direction for the system */ /** tex coord animation direction for the system */
TexAnimDir _animDir; TexAnimDir _animDir;
/** the width and height of an animated cell unified */ /** the width and height of an animated cell unified */
int _animUnifiedSize; int _animUnifiedSize;
/** variable keeping count of sprite frames added for atlas mode off */
int _animIndexCount;
/** wether to start from first or last when using life animation */ /** wether to start from first or last when using life animation */
int _isLifeAnimationReversed; bool _isLifeAnimationReversed;
/** A map that stores particle animation index coords */
std::unordered_map<unsigned short, ParticleFrameDescriptor> _animationIndices;
/** wether to start from first or last when using life animation */
int _isAnimationMulti;
/** A map that stores particle animation descriptors */
std::unordered_map<unsigned short, ParticleAnimationDescriptor> _animations;
/** A vector that stores ids of animation descriptors that are choosen at random */
std::vector<unsigned short> _randomAnimations;
/** does FlippedY variance of each particle */ /** does FlippedY variance of each particle */
int _yCoordFlipped; int _yCoordFlipped;

View File

@ -273,7 +273,11 @@ void ParticleSystemQuad::initIndices()
} }
} }
inline void updatePosWithParticle(V3F_C4B_T2F_Quad* quad, const Vec2& newPosition, float size, float rotation) inline void updatePosWithParticle(V3F_C4B_T2F_Quad* quad,
const Vec2& newPosition,
float size,
float rotation,
float staticRotation)
{ {
// vertices // vertices
float size_2 = size / 2; float size_2 = size / 2;
@ -285,7 +289,7 @@ inline void updatePosWithParticle(V3F_C4B_T2F_Quad* quad, const Vec2& newPositio
float x = newPosition.x; float x = newPosition.x;
float y = newPosition.y; float y = newPosition.y;
float r = (float)-CC_DEGREES_TO_RADIANS(rotation); float r = (float)-CC_DEGREES_TO_RADIANS(rotation + staticRotation);
float cr = cosf(r); float cr = cosf(r);
float sr = sinf(r); float sr = sinf(r);
float ax = x1 * cr - y1 * sr + x; float ax = x1 * cr - y1 * sr + x;
@ -357,8 +361,9 @@ void ParticleSystemQuad::updateParticleQuads()
float* y = _particleData.posy; float* y = _particleData.posy;
float* s = _particleData.size; float* s = _particleData.size;
float* r = _particleData.rotation; float* r = _particleData.rotation;
float* sr = _particleData.staticRotation;
V3F_C4B_T2F_Quad* quadStart = startQuad; V3F_C4B_T2F_Quad* quadStart = startQuad;
for (int i = 0; i < _particleCount; ++i, ++startX, ++startY, ++x, ++y, ++quadStart, ++s, ++r) for (int i = 0; i < _particleCount; ++i, ++startX, ++startY, ++x, ++y, ++quadStart, ++s, ++r, ++sr)
{ {
p2.set(*startX, *startY, 0); p2.set(*startX, *startY, 0);
worldToNodeTM.transformPoint(&p2); worldToNodeTM.transformPoint(&p2);
@ -366,7 +371,7 @@ void ParticleSystemQuad::updateParticleQuads()
p2 = p1 - p2; p2 = p1 - p2;
newPos.x -= p2.x - pos.x; newPos.x -= p2.x - pos.x;
newPos.y -= p2.y - pos.y; newPos.y -= p2.y - pos.y;
updatePosWithParticle(quadStart, newPos, *s, *r); updatePosWithParticle(quadStart, newPos, *s, *r, *sr);
} }
} }
else if (_positionType == PositionType::RELATIVE) else if (_positionType == PositionType::RELATIVE)
@ -378,14 +383,15 @@ void ParticleSystemQuad::updateParticleQuads()
float* y = _particleData.posy; float* y = _particleData.posy;
float* s = _particleData.size; float* s = _particleData.size;
float* r = _particleData.rotation; float* r = _particleData.rotation;
float* sr = _particleData.staticRotation;
V3F_C4B_T2F_Quad* quadStart = startQuad; V3F_C4B_T2F_Quad* quadStart = startQuad;
for (int i = 0; i < _particleCount; ++i, ++startX, ++startY, ++x, ++y, ++quadStart, ++s, ++r) for (int i = 0; i < _particleCount; ++i, ++startX, ++startY, ++x, ++y, ++quadStart, ++s, ++r, ++sr)
{ {
newPos.set(*x, *y); newPos.set(*x, *y);
newPos.x = *x - (currentPosition.x - *startX); newPos.x = *x - (currentPosition.x - *startX);
newPos.y = *y - (currentPosition.y - *startY); newPos.y = *y - (currentPosition.y - *startY);
newPos += pos; newPos += pos;
updatePosWithParticle(quadStart, newPos, *s, *r); updatePosWithParticle(quadStart, newPos, *s, *r, *sr);
} }
} }
else else
@ -397,29 +403,49 @@ void ParticleSystemQuad::updateParticleQuads()
float* y = _particleData.posy; float* y = _particleData.posy;
float* s = _particleData.size; float* s = _particleData.size;
float* r = _particleData.rotation; float* r = _particleData.rotation;
float* sr = _particleData.staticRotation;
V3F_C4B_T2F_Quad* quadStart = startQuad; V3F_C4B_T2F_Quad* quadStart = startQuad;
for (int i = 0; i < _particleCount; ++i, ++startX, ++startY, ++x, ++y, ++quadStart, ++s, ++r) for (int i = 0; i < _particleCount; ++i, ++startX, ++startY, ++x, ++y, ++quadStart, ++s, ++r, ++sr)
{ {
newPos.set(*x + pos.x, *y + pos.y); newPos.set(*x + pos.x, *y + pos.y);
updatePosWithParticle(quadStart, newPos, *s, *r); updatePosWithParticle(quadStart, newPos, *s, *r, *sr);
} }
} }
auto setTexCoords = [this](V3F_C4B_T2F_Quad* quad, unsigned short* cellIndex) {
float left = 0.0F, bottom = 0.0F, top = 1.0F, right = 1.0F;
if (_isAnimationAtlas)
{
float texPixels = getAnimationPixels(); float texPixels = getAnimationPixels();
float cellPixels = getAnimationCellUnifiedSize(); float cellPixels = getAnimationCellUnifiedSize();
auto setTexCoords = [this, texPixels, cellPixels](V3F_C4B_T2F_Quad* quad, unsigned int* cellIndex) { left = 0.0F;
right = 1.0F;
float left = 0; top = *cellIndex * cellPixels / texPixels;
float right = 1; bottom = (*cellIndex * cellPixels + cellPixels) / texPixels;
float top = *cellIndex * cellPixels / texPixels;
float bottom = (*cellIndex * cellPixels + cellPixels) / texPixels;
// Flip texture coords if direction of texture is horizontal
if (_animDir == TexAnimDir::HORIZONTAL) if (_animDir == TexAnimDir::HORIZONTAL)
{ {
std::swap(top, right); std::swap(top, right);
std::swap(left, bottom); std::swap(left, bottom);
} }
}
else
{
auto& index = _animationIndices.at(*cellIndex);
auto texWidth = _texture->getPixelsWide();
auto texHeight = _texture->getPixelsHigh();
left = index.rect.origin.x / texWidth;
right = (index.rect.origin.x + index.rect.size.x) / texWidth;
top = index.rect.origin.y / texHeight;
bottom = (index.rect.origin.y + index.rect.size.y) / texHeight;
}
quad->bl.texCoords.u = left; quad->bl.texCoords.u = left;
quad->bl.texCoords.v = bottom; quad->bl.texCoords.v = bottom;
@ -443,7 +469,7 @@ void ParticleSystemQuad::updateParticleQuads()
float* g = _particleData.colorG; float* g = _particleData.colorG;
float* b = _particleData.colorB; float* b = _particleData.colorB;
float* a = _particleData.colorA; float* a = _particleData.colorA;
unsigned int* cellIndex = _particleData.animCellIndex; unsigned short* cellIndex = _particleData.animCellIndex;
for (int i = 0; i < _particleCount; ++i, ++quad, ++r, ++g, ++b, ++a, ++cellIndex) for (int i = 0; i < _particleCount; ++i, ++quad, ++r, ++g, ++b, ++a, ++cellIndex)
{ {
@ -456,7 +482,7 @@ void ParticleSystemQuad::updateParticleQuads()
quad->tl.colors.set(colorR, colorG, colorB, colorA); quad->tl.colors.set(colorR, colorG, colorB, colorA);
quad->tr.colors.set(colorR, colorG, colorB, colorA); quad->tr.colors.set(colorR, colorG, colorB, colorA);
if (_isLifeAnimated || _isEmitterAnimated) if (_isLifeAnimated || _isEmitterAnimated || _isLoopAnimated)
setTexCoords(quad, cellIndex); setTexCoords(quad, cellIndex);
} }
} }
@ -467,7 +493,7 @@ void ParticleSystemQuad::updateParticleQuads()
float* g = _particleData.colorG; float* g = _particleData.colorG;
float* b = _particleData.colorB; float* b = _particleData.colorB;
float* a = _particleData.colorA; float* a = _particleData.colorA;
unsigned int* cellIndex = _particleData.animCellIndex; unsigned short* cellIndex = _particleData.animCellIndex;
for (int i = 0; i < _particleCount; ++i, ++quad, ++r, ++g, ++b, ++a, ++cellIndex) for (int i = 0; i < _particleCount; ++i, ++quad, ++r, ++g, ++b, ++a, ++cellIndex)
{ {
@ -480,7 +506,7 @@ void ParticleSystemQuad::updateParticleQuads()
quad->tl.colors.set(colorR, colorG, colorB, colorA); quad->tl.colors.set(colorR, colorG, colorB, colorA);
quad->tr.colors.set(colorR, colorG, colorB, colorA); quad->tr.colors.set(colorR, colorG, colorB, colorA);
if (_isLifeAnimated || _isEmitterAnimated) if (_isLifeAnimated || _isEmitterAnimated || _isLoopAnimated)
setTexCoords(quad, cellIndex); setTexCoords(quad, cellIndex);
} }
} }