mirror of https://github.com/axmolengine/axmol.git
Add HSV support and remove frame compensation.
This commit is contained in:
parent
1e2467e6dd
commit
726f40cda8
|
@ -98,18 +98,23 @@ 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 that fixes strafing for position variance, made by kiss rng.
|
||||
KEEP IT SIMPLE STUPID (KISS) rng example: https://gist.github.com/3ki5tj/7b1d51e96d1f9bfb89bc
|
||||
*/
|
||||
inline static float RANDOM_M11(unsigned int* seed)
|
||||
inline static float RANDOM_KISS(void)
|
||||
{
|
||||
*seed = *seed * 134775813 + 1;
|
||||
union
|
||||
{
|
||||
uint32_t d;
|
||||
float f;
|
||||
} u;
|
||||
u.d = (((uint32_t)(*seed) & 0x7fff) << 8) | 0x40000000;
|
||||
return u.f - 3.0f;
|
||||
#define kiss_znew(z) (z = 36969 * (z & 65535) + (z >> 16))
|
||||
#define kiss_wnew(w) (w = 18000 * (w & 65535) + (w >> 16))
|
||||
#define kiss_MWC(z, w) ((kiss_znew(z) << 16) + kiss_wnew(w))
|
||||
#define kiss_SHR3(jsr) (jsr ^= (jsr << 17), jsr ^= (jsr >> 13), jsr ^= (jsr << 5))
|
||||
#define kiss_CONG(jc) (jc = 69069 * jc + 1234567)
|
||||
#define kiss_KISS(z, w, jc, jsr) ((kiss_MWC(z, w) ^ kiss_CONG(jc)) + kiss_SHR3(jsr))
|
||||
|
||||
static unsigned kiss_z = rand(), kiss_w = rand(), kiss_jsr = rand(), kiss_jcong = rand();
|
||||
// Generate two random floats and add them to get a total of 2.0 and then subtract 1.0
|
||||
// to get a random number between -1.0 and 1.0 INCLUSIVE.
|
||||
return -1.0F + ((kiss_KISS(kiss_z, kiss_w, kiss_jcong, kiss_jsr) / 4294967296.0) +
|
||||
(kiss_KISS(kiss_z, kiss_w, kiss_jcong, kiss_jsr) / 4294967296.0));
|
||||
}
|
||||
|
||||
ParticleData::ParticleData()
|
||||
|
@ -121,24 +126,33 @@ bool ParticleData::init(int count)
|
|||
{
|
||||
maxCount = count;
|
||||
|
||||
posx = (float*)malloc(count * sizeof(float));
|
||||
posy = (float*)malloc(count * sizeof(float));
|
||||
startPosX = (float*)malloc(count * sizeof(float));
|
||||
startPosY = (float*)malloc(count * sizeof(float));
|
||||
colorR = (float*)malloc(count * sizeof(float));
|
||||
colorG = (float*)malloc(count * sizeof(float));
|
||||
colorB = (float*)malloc(count * sizeof(float));
|
||||
colorA = (float*)malloc(count * sizeof(float));
|
||||
deltaColorR = (float*)malloc(count * sizeof(float));
|
||||
deltaColorG = (float*)malloc(count * sizeof(float));
|
||||
deltaColorB = (float*)malloc(count * sizeof(float));
|
||||
deltaColorA = (float*)malloc(count * sizeof(float));
|
||||
size = (float*)malloc(count * sizeof(float));
|
||||
deltaSize = (float*)malloc(count * sizeof(float));
|
||||
rotation = (float*)malloc(count * sizeof(float));
|
||||
deltaRotation = (float*)malloc(count * sizeof(float));
|
||||
timeToLive = (float*)malloc(count * sizeof(float));
|
||||
atlasIndex = (unsigned int*)malloc(count * sizeof(unsigned int));
|
||||
posx = (float*)malloc(count * sizeof(float));
|
||||
posy = (float*)malloc(count * sizeof(float));
|
||||
startPosX = (float*)malloc(count * sizeof(float));
|
||||
startPosY = (float*)malloc(count * sizeof(float));
|
||||
colorR = (float*)malloc(count * sizeof(float));
|
||||
colorG = (float*)malloc(count * sizeof(float));
|
||||
colorB = (float*)malloc(count * sizeof(float));
|
||||
colorA = (float*)malloc(count * sizeof(float));
|
||||
deltaColorR = (float*)malloc(count * sizeof(float));
|
||||
deltaColorG = (float*)malloc(count * sizeof(float));
|
||||
deltaColorB = (float*)malloc(count * sizeof(float));
|
||||
deltaColorA = (float*)malloc(count * sizeof(float));
|
||||
hue = (float*)malloc(count * sizeof(float));
|
||||
sat = (float*)malloc(count * sizeof(float));
|
||||
val = (float*)malloc(count * sizeof(float));
|
||||
size = (float*)malloc(count * sizeof(float));
|
||||
deltaSize = (float*)malloc(count * sizeof(float));
|
||||
rotation = (float*)malloc(count * sizeof(float));
|
||||
staticRotation = (float*)malloc(count * sizeof(float));
|
||||
deltaRotation = (float*)malloc(count * sizeof(float));
|
||||
totalTimeToLive = (float*)malloc(count * sizeof(float));
|
||||
timeToLive = (float*)malloc(count * sizeof(float));
|
||||
animTimeLength = (float*)malloc(count * sizeof(float));
|
||||
animTimeDelta = (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));
|
||||
|
||||
modeA.dirX = (float*)malloc(count * sizeof(float));
|
||||
modeA.dirY = (float*)malloc(count * sizeof(float));
|
||||
|
@ -150,10 +164,11 @@ bool ParticleData::init(int count)
|
|||
modeB.deltaRadius = (float*)malloc(count * sizeof(float));
|
||||
modeB.radius = (float*)malloc(count * sizeof(float));
|
||||
|
||||
return posx && posy && startPosY && startPosX && colorR && colorG && colorB && colorA && deltaColorR &&
|
||||
deltaColorG && deltaColorB && deltaColorA && size && deltaSize && rotation && deltaRotation && timeToLive &&
|
||||
atlasIndex && modeA.dirX && modeA.dirY && modeA.radialAccel && modeA.tangentialAccel && modeB.angle &&
|
||||
modeB.degreesPerSecond && modeB.deltaRadius && modeB.radius;
|
||||
return posx && posy && startPosX && startPosY && colorR && colorG && colorB && colorA && deltaColorR &&
|
||||
deltaColorG && deltaColorB && deltaColorA && hue && sat && val && size && deltaSize && rotation &&
|
||||
staticRotation && deltaRotation && totalTimeToLive && timeToLive && animTimeLength && animTimeDelta &&
|
||||
animIndex && animCellIndex && atlasIndex && modeA.dirX && modeA.dirY && modeA.radialAccel &&
|
||||
modeA.tangentialAccel && modeB.angle && modeB.degreesPerSecond && modeB.deltaRadius && modeB.radius;
|
||||
}
|
||||
|
||||
void ParticleData::release()
|
||||
|
@ -170,11 +185,20 @@ void ParticleData::release()
|
|||
CC_SAFE_FREE(deltaColorG);
|
||||
CC_SAFE_FREE(deltaColorB);
|
||||
CC_SAFE_FREE(deltaColorA);
|
||||
CC_SAFE_FREE(hue);
|
||||
CC_SAFE_FREE(sat);
|
||||
CC_SAFE_FREE(val);
|
||||
CC_SAFE_FREE(size);
|
||||
CC_SAFE_FREE(deltaSize);
|
||||
CC_SAFE_FREE(rotation);
|
||||
CC_SAFE_FREE(staticRotation);
|
||||
CC_SAFE_FREE(deltaRotation);
|
||||
CC_SAFE_FREE(totalTimeToLive);
|
||||
CC_SAFE_FREE(timeToLive);
|
||||
CC_SAFE_FREE(animTimeLength);
|
||||
CC_SAFE_FREE(animTimeDelta);
|
||||
CC_SAFE_FREE(animIndex);
|
||||
CC_SAFE_FREE(animCellIndex);
|
||||
CC_SAFE_FREE(atlasIndex);
|
||||
|
||||
CC_SAFE_FREE(modeA.dirX);
|
||||
|
@ -218,14 +242,29 @@ ParticleSystem::ParticleSystem()
|
|||
, _startSpinVar(0)
|
||||
, _endSpin(0)
|
||||
, _endSpinVar(0)
|
||||
, _spawnAngle(0)
|
||||
, _spawnAngleVar(0)
|
||||
, _hsv(0, 1, 1)
|
||||
, _hsvVar(0, 0, 0)
|
||||
, _emissionRate(0)
|
||||
, _totalParticles(0)
|
||||
, _texture(nullptr)
|
||||
, _blendFunc(BlendFunc::ALPHA_PREMULTIPLIED)
|
||||
, _opacityModifyRGB(false)
|
||||
, _isLifeAnimated(false)
|
||||
, _isEmitterAnimated(false)
|
||||
, _isLoopAnimated(false)
|
||||
, _animIndexCount(0)
|
||||
, _isAnimationReversed(false)
|
||||
, _undefinedIndexRect({0,0,0,0})
|
||||
, _animationTimescaleInd(false)
|
||||
, _yCoordFlipped(1)
|
||||
, _positionType(PositionType::FREE)
|
||||
, _paused(false)
|
||||
, _updatePaused(false)
|
||||
, _timeScale(1)
|
||||
, _fixedFPS(0)
|
||||
, _fixedFPSDelta(0)
|
||||
, _sourcePositionCompatible(true) // In the furture this member's default value maybe false or be removed.
|
||||
{
|
||||
modeA.gravity.setZero();
|
||||
|
@ -604,14 +643,20 @@ ParticleSystem::~ParticleSystem()
|
|||
// it is not needed to call "unscheduleUpdate" here. In fact, it will be called in "cleanup"
|
||||
// unscheduleUpdate();
|
||||
_particleData.release();
|
||||
_animations.clear();
|
||||
CC_SAFE_RELEASE(_texture);
|
||||
}
|
||||
|
||||
void ParticleSystem::addParticles(int count)
|
||||
void ParticleSystem::addParticles(int count, int animationCellIndex, int animationIndex)
|
||||
{
|
||||
if (_paused)
|
||||
return;
|
||||
uint32_t RANDSEED = rand();
|
||||
|
||||
// Try to add as many particles as you can without overflowing.
|
||||
count = MIN(int(_totalParticles * __totalParticleCountFactor) - _particleCount, count);
|
||||
|
||||
animationCellIndex = MIN(animationCellIndex, _animIndexCount - 1);
|
||||
animationIndex = MIN(animationIndex, _animIndexCount - 1);
|
||||
|
||||
int start = _particleCount;
|
||||
_particleCount += count;
|
||||
|
@ -619,26 +664,70 @@ void ParticleSystem::addParticles(int count)
|
|||
// life
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
float theLife = _life + _lifeVar * RANDOM_M11(&RANDSEED);
|
||||
_particleData.timeToLive[i] = MAX(0, theLife);
|
||||
float particleLife = _life + _lifeVar * RANDOM_KISS();
|
||||
_particleData.totalTimeToLive[i] = MAX(0, particleLife);
|
||||
_particleData.timeToLive[i] = MAX(0, particleLife);
|
||||
}
|
||||
|
||||
// position
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.posx[i] = _sourcePosition.x + _posVar.x * RANDOM_M11(&RANDSEED);
|
||||
auto f = RANDOM_KISS();
|
||||
_particleData.posx[i] = _sourcePosition.x + _posVar.x * RANDOM_KISS();
|
||||
}
|
||||
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.posy[i] = _sourcePosition.y + _posVar.y * RANDOM_M11(&RANDSEED);
|
||||
_particleData.posy[i] = _sourcePosition.y + _posVar.y * RANDOM_KISS();
|
||||
}
|
||||
|
||||
if (animationCellIndex == -1 && _isEmitterAnimated)
|
||||
{
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
int rand0 = abs(RANDOM_KISS() * _animIndexCount);
|
||||
_particleData.animCellIndex[i] = MIN(rand0, _animIndexCount - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (animationCellIndex != -1)
|
||||
std::fill_n(_particleData.animCellIndex + start, _particleCount - start, animationCellIndex);
|
||||
|
||||
if (animationIndex == -1 && !_animations.empty())
|
||||
{
|
||||
if (_randomAnimations.empty())
|
||||
setMultiAnimationRandom();
|
||||
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
int rand0 = abs(RANDOM_KISS() * _randomAnimations.size());
|
||||
int index = MIN(rand0, _randomAnimations.size() - 1);
|
||||
_particleData.animIndex[i] = _randomAnimations[index];
|
||||
auto& descriptor = _animations.at(_particleData.animIndex[i]);
|
||||
_particleData.animTimeLength[i] =
|
||||
descriptor.animationSpeed + descriptor.animationSpeedVariance * RANDOM_KISS();
|
||||
}
|
||||
}
|
||||
|
||||
if (_isEmitterAnimated || _isLoopAnimated)
|
||||
std::fill_n(_particleData.animTimeDelta + start, _particleCount - start, 0);
|
||||
|
||||
if (animationIndex != -1)
|
||||
{
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.animIndex[i] = animationIndex;
|
||||
auto& descriptor = _animations.at(animationIndex);
|
||||
_particleData.animTimeLength[i] =
|
||||
descriptor.animationSpeed + descriptor.animationSpeedVariance * RANDOM_KISS();
|
||||
}
|
||||
}
|
||||
|
||||
// color
|
||||
#define SET_COLOR(c, b, v) \
|
||||
for (int i = start; i < _particleCount; ++i) \
|
||||
{ \
|
||||
c[i] = clampf(b + v * RANDOM_M11(&RANDSEED), 0, 1); \
|
||||
c[i] = clampf(b + v * RANDOM_KISS(), 0, 1); \
|
||||
}
|
||||
|
||||
SET_COLOR(_particleData.colorR, _startColor.r, _startColorVar.r);
|
||||
|
@ -662,10 +751,28 @@ void ParticleSystem::addParticles(int count)
|
|||
SET_DELTA_COLOR(_particleData.colorB, _particleData.deltaColorB);
|
||||
SET_DELTA_COLOR(_particleData.colorA, _particleData.deltaColorA);
|
||||
|
||||
// hue saturation value color
|
||||
{
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.hue[i] = _hsv.h + _hsvVar.h * RANDOM_KISS();
|
||||
}
|
||||
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.sat[i] = _hsv.s + _hsvVar.s * RANDOM_KISS();
|
||||
}
|
||||
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.val[i] = _hsv.v + _hsvVar.v * RANDOM_KISS();
|
||||
}
|
||||
}
|
||||
|
||||
// size
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.size[i] = _startSize + _startSizeVar * RANDOM_M11(&RANDSEED);
|
||||
_particleData.size[i] = _startSize + _startSizeVar * RANDOM_KISS();
|
||||
_particleData.size[i] = MAX(0, _particleData.size[i]);
|
||||
}
|
||||
|
||||
|
@ -673,30 +780,31 @@ void ParticleSystem::addParticles(int count)
|
|||
{
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
float endSize = _endSize + _endSizeVar * RANDOM_M11(&RANDSEED);
|
||||
float endSize = _endSize + _endSizeVar * RANDOM_KISS();
|
||||
endSize = MAX(0, endSize);
|
||||
_particleData.deltaSize[i] = (endSize - _particleData.size[i]) / _particleData.timeToLive[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.deltaSize[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
std::fill_n(_particleData.deltaSize + start, _particleCount - start, 0.0F);
|
||||
|
||||
// rotation
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.rotation[i] = _startSpin + _startSpinVar * RANDOM_M11(&RANDSEED);
|
||||
_particleData.rotation[i] = _startSpin + _startSpinVar * RANDOM_KISS();
|
||||
}
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
float endA = _endSpin + _endSpinVar * RANDOM_M11(&RANDSEED);
|
||||
float endA = _endSpin + _endSpinVar * RANDOM_KISS();
|
||||
_particleData.deltaRotation[i] = (endA - _particleData.rotation[i]) / _particleData.timeToLive[i];
|
||||
}
|
||||
|
||||
// static rotation
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.staticRotation[i] = _spawnAngle + _spawnAngleVar * RANDOM_KISS();
|
||||
}
|
||||
|
||||
// position
|
||||
Vec2 pos;
|
||||
if (_positionType == PositionType::FREE)
|
||||
|
@ -707,14 +815,8 @@ void ParticleSystem::addParticles(int count)
|
|||
{
|
||||
pos = _position;
|
||||
}
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.startPosX[i] = pos.x;
|
||||
}
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.startPosY[i] = pos.y;
|
||||
}
|
||||
std::fill_n(_particleData.startPosX + start, _particleCount - start, pos.x);
|
||||
std::fill_n(_particleData.startPosY + start, _particleCount - start, pos.y);
|
||||
|
||||
// Mode Gravity: A
|
||||
if (_emitterMode == Mode::GRAVITY)
|
||||
|
@ -723,14 +825,14 @@ void ParticleSystem::addParticles(int count)
|
|||
// radial accel
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.modeA.radialAccel[i] = modeA.radialAccel + modeA.radialAccelVar * RANDOM_M11(&RANDSEED);
|
||||
_particleData.modeA.radialAccel[i] = modeA.radialAccel + modeA.radialAccelVar * RANDOM_KISS();
|
||||
}
|
||||
|
||||
// tangential accel
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.modeA.tangentialAccel[i] =
|
||||
modeA.tangentialAccel + modeA.tangentialAccelVar * RANDOM_M11(&RANDSEED);
|
||||
modeA.tangentialAccel + modeA.tangentialAccelVar * RANDOM_KISS();
|
||||
}
|
||||
|
||||
// rotation is dir
|
||||
|
@ -738,9 +840,9 @@ void ParticleSystem::addParticles(int count)
|
|||
{
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
float a = CC_DEGREES_TO_RADIANS(_angle + _angleVar * RANDOM_M11(&RANDSEED));
|
||||
float a = CC_DEGREES_TO_RADIANS(_angle + _angleVar * RANDOM_KISS());
|
||||
Vec2 v(cosf(a), sinf(a));
|
||||
float s = modeA.speed + modeA.speedVar * RANDOM_M11(&RANDSEED);
|
||||
float s = modeA.speed + modeA.speedVar * RANDOM_KISS();
|
||||
Vec2 dir = v * s;
|
||||
_particleData.modeA.dirX[i] = dir.x; // v * s ;
|
||||
_particleData.modeA.dirY[i] = dir.y;
|
||||
|
@ -751,9 +853,9 @@ void ParticleSystem::addParticles(int count)
|
|||
{
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
float a = CC_DEGREES_TO_RADIANS(_angle + _angleVar * RANDOM_M11(&RANDSEED));
|
||||
float a = CC_DEGREES_TO_RADIANS(_angle + _angleVar * RANDOM_KISS());
|
||||
Vec2 v(cosf(a), sinf(a));
|
||||
float s = modeA.speed + modeA.speedVar * RANDOM_M11(&RANDSEED);
|
||||
float s = modeA.speed + modeA.speedVar * RANDOM_KISS();
|
||||
Vec2 dir = v * s;
|
||||
_particleData.modeA.dirX[i] = dir.x; // v * s ;
|
||||
_particleData.modeA.dirY[i] = dir.y;
|
||||
|
@ -768,32 +870,27 @@ void ParticleSystem::addParticles(int count)
|
|||
// Set the default diameter of the particle from the source position
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.modeB.radius[i] = modeB.startRadius + modeB.startRadiusVar * RANDOM_M11(&RANDSEED);
|
||||
_particleData.modeB.radius[i] = modeB.startRadius + modeB.startRadiusVar * RANDOM_KISS();
|
||||
}
|
||||
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.modeB.angle[i] = CC_DEGREES_TO_RADIANS(_angle + _angleVar * RANDOM_M11(&RANDSEED));
|
||||
_particleData.modeB.angle[i] = CC_DEGREES_TO_RADIANS(_angle + _angleVar * RANDOM_KISS());
|
||||
}
|
||||
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.modeB.degreesPerSecond[i] =
|
||||
CC_DEGREES_TO_RADIANS(modeB.rotatePerSecond + modeB.rotatePerSecondVar * RANDOM_M11(&RANDSEED));
|
||||
CC_DEGREES_TO_RADIANS(modeB.rotatePerSecond + modeB.rotatePerSecondVar * RANDOM_KISS());
|
||||
}
|
||||
|
||||
if (modeB.endRadius == START_RADIUS_EQUAL_TO_END_RADIUS)
|
||||
{
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.modeB.deltaRadius[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
std::fill_n(_particleData.modeB.deltaRadius + start, _particleCount - start, 0.0F);
|
||||
else
|
||||
{
|
||||
for (int i = start; i < _particleCount; ++i)
|
||||
{
|
||||
float endRadius = modeB.endRadius + modeB.endRadiusVar * RANDOM_M11(&RANDSEED);
|
||||
float endRadius = modeB.endRadius + modeB.endRadiusVar * RANDOM_KISS();
|
||||
_particleData.modeB.deltaRadius[i] =
|
||||
(endRadius - _particleData.modeB.radius[i]) / _particleData.timeToLive[i];
|
||||
}
|
||||
|
@ -801,6 +898,181 @@ void ParticleSystem::addParticles(int count)
|
|||
}
|
||||
}
|
||||
|
||||
void ParticleSystem::setAnimationDescriptor(unsigned short indexOfDescriptor,
|
||||
float time,
|
||||
float timeVariance,
|
||||
const std::vector<unsigned short> &indices,
|
||||
bool reverse)
|
||||
{
|
||||
auto iter = _animations.find(indexOfDescriptor);
|
||||
if (iter == _animations.end())
|
||||
iter = _animations.emplace(indexOfDescriptor, ParticleAnimationDescriptor{}).first;
|
||||
|
||||
auto& desc = iter->second;
|
||||
desc.animationSpeed = time;
|
||||
desc.animationSpeedVariance = timeVariance;
|
||||
desc.animationIndices = std::move(indices);
|
||||
desc.reverseIndices = reverse;
|
||||
}
|
||||
|
||||
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::setAnimationIndicesAtlas()
|
||||
{
|
||||
// VERTICAL
|
||||
if (_texture->getPixelsHigh() > _texture->getPixelsWide())
|
||||
{
|
||||
setAnimationIndicesAtlas(_texture->getPixelsWide(),
|
||||
ParticleSystem::TexAnimDir::VERTICAL);
|
||||
return;
|
||||
}
|
||||
|
||||
// HORIZONTAL
|
||||
if (_texture->getPixelsWide() > _texture->getPixelsHigh())
|
||||
{
|
||||
setAnimationIndicesAtlas(_texture->getPixelsHigh(),
|
||||
ParticleSystem::TexAnimDir::HORIZONTAL);
|
||||
return;
|
||||
}
|
||||
|
||||
CCASSERT(false, "Couldn't figure out the atlas size and direction.");
|
||||
}
|
||||
|
||||
void ParticleSystem::setAnimationIndicesAtlas(unsigned int unifiedCellSize, TexAnimDir direction)
|
||||
{
|
||||
CCASSERT(unifiedCellSize > 0, "A cell cannot have a size of zero.");
|
||||
|
||||
resetAnimationIndices();
|
||||
|
||||
auto texWidth = _texture->getPixelsWide();
|
||||
auto texHeight = _texture->getPixelsHigh();
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case TexAnimDir::VERTICAL:
|
||||
{
|
||||
for (short i = 0; i < short(texHeight / unifiedCellSize); i++)
|
||||
{
|
||||
Rect frame{};
|
||||
|
||||
frame.origin.x = 0;
|
||||
frame.origin.y = unifiedCellSize * i;
|
||||
|
||||
frame.size.x = texWidth;
|
||||
frame.size.y = unifiedCellSize;
|
||||
|
||||
addAnimationIndex(_animIndexCount++, frame);
|
||||
}
|
||||
|
||||
break;
|
||||
};
|
||||
case TexAnimDir::HORIZONTAL:
|
||||
{
|
||||
for (short i = 0; i < short(texWidth / unifiedCellSize); i++)
|
||||
{
|
||||
Rect frame{};
|
||||
|
||||
frame.origin.x = unifiedCellSize * i;
|
||||
frame.origin.y = 0;
|
||||
|
||||
frame.size.x = unifiedCellSize;
|
||||
frame.size.y = texHeight;
|
||||
|
||||
addAnimationIndex(_animIndexCount++, frame);
|
||||
}
|
||||
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
bool ParticleSystem::addAnimationIndex(std::string_view frameName)
|
||||
{
|
||||
return addAnimationIndex(_animIndexCount, frameName);
|
||||
}
|
||||
|
||||
bool ParticleSystem::addAnimationIndex(unsigned short index, std::string_view frameName)
|
||||
{
|
||||
auto frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(frameName);
|
||||
|
||||
if (frame)
|
||||
return addAnimationIndex(index, frame);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ParticleSystem::addAnimationIndex(cocos2d::SpriteFrame* frame)
|
||||
{
|
||||
return addAnimationIndex(_animIndexCount, frame);
|
||||
}
|
||||
|
||||
bool ParticleSystem::addAnimationIndex(unsigned short index, cocos2d::SpriteFrame* frame)
|
||||
{
|
||||
if (frame)
|
||||
return addAnimationIndex(index, frame->getRect(), frame->isRotated());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ParticleSystem::addAnimationIndex(unsigned short index, cocos2d::Rect rect, bool rotated)
|
||||
{
|
||||
auto iter = _animationIndices.find(index);
|
||||
if (iter == _animationIndices.end())
|
||||
iter = _animationIndices.emplace(index, ParticleFrameDescriptor{}).first;
|
||||
|
||||
auto& desc = iter->second;
|
||||
desc.rect = rect;
|
||||
desc.isRotated = rotated;
|
||||
|
||||
++_animIndexCount;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ParticleSystem::simulate(float seconds, float frameRate)
|
||||
{
|
||||
auto l_updatePaused = _updatePaused;
|
||||
_updatePaused = false;
|
||||
seconds = seconds == SIMULATION_USE_PARTICLE_LIFETIME ?
|
||||
getLife() + getLifeVar() : seconds;
|
||||
frameRate = frameRate == SIMULATION_USE_GAME_ANIMATION_INTERVAL ?
|
||||
1.0F / Director::getInstance()->getAnimationInterval() : frameRate;
|
||||
auto delta = 1.0F / frameRate;
|
||||
if (seconds > delta)
|
||||
{
|
||||
while (seconds > 0.0F)
|
||||
{
|
||||
this->update(delta);
|
||||
seconds -= delta;
|
||||
}
|
||||
this->update(seconds);
|
||||
}
|
||||
else
|
||||
this->update(seconds);
|
||||
_updatePaused = l_updatePaused;
|
||||
}
|
||||
|
||||
void ParticleSystem::resimulate(float seconds, float frameRate)
|
||||
{
|
||||
this->resetSystem();
|
||||
this->simulate(seconds, frameRate);
|
||||
}
|
||||
|
||||
void ParticleSystem::onEnter()
|
||||
{
|
||||
Node::onEnter();
|
||||
|
@ -834,10 +1106,7 @@ void ParticleSystem::resetSystem()
|
|||
{
|
||||
_isActive = true;
|
||||
_elapsed = 0;
|
||||
for (int i = 0; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.timeToLive[i] = 0.0f;
|
||||
}
|
||||
std::fill_n(_particleData.timeToLive, _particleCount, 0.0F);
|
||||
}
|
||||
|
||||
bool ParticleSystem::isFull()
|
||||
|
@ -848,8 +1117,29 @@ bool ParticleSystem::isFull()
|
|||
// ParticleSystem - MainLoop
|
||||
void ParticleSystem::update(float dt)
|
||||
{
|
||||
// don't process particles nor update gl buffer when this node is invisible.
|
||||
if (!_visible || _updatePaused)
|
||||
return;
|
||||
|
||||
CC_PROFILER_START_CATEGORY(kProfilerCategoryParticles, "CCParticleSystem - update");
|
||||
|
||||
if (_componentContainer && !_componentContainer->isEmpty())
|
||||
{
|
||||
_componentContainer->visit(dt);
|
||||
}
|
||||
|
||||
if (_fixedFPS != 0)
|
||||
{
|
||||
_fixedFPSDelta += dt;
|
||||
if (_fixedFPSDelta < 1.0F / _fixedFPS)
|
||||
return;
|
||||
dt = _fixedFPSDelta;
|
||||
_fixedFPSDelta = 0.0F;
|
||||
}
|
||||
|
||||
float pureDt = dt;
|
||||
dt *= _timeScale;
|
||||
|
||||
if (_isActive && _emissionRate)
|
||||
{
|
||||
float rate = 1.0f / _emissionRate;
|
||||
|
@ -859,8 +1149,7 @@ void ParticleSystem::update(float dt)
|
|||
if (_particleCount < totalParticles)
|
||||
{
|
||||
_emitCounter += dt;
|
||||
if (_emitCounter < 0.f)
|
||||
_emitCounter = 0.f;
|
||||
_emitCounter = MAX(0.0F, _emitCounter);
|
||||
}
|
||||
|
||||
int emitCount = MIN(totalParticles - _particleCount, _emitCounter / rate);
|
||||
|
@ -876,10 +1165,65 @@ void ParticleSystem::update(float dt)
|
|||
}
|
||||
}
|
||||
|
||||
// The reason for using for-loops separately for every property is because
|
||||
// When the processor needs to read from or write to a location in memory,
|
||||
// it first checks whether a copy of that data is in the cpu's cache.
|
||||
// And wether if every property's memory of the particle system is continuous,
|
||||
// for the purpose of improving cache hit rate, we should process only one property in one for-loop.
|
||||
// It was proved to be effective especially for low-end devices.
|
||||
{
|
||||
for (int i = 0; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.timeToLive[i] -= dt;
|
||||
if (_isEmitterAnimated && !_animations.empty())
|
||||
{
|
||||
_particleData.animTimeDelta[i] += (_animationTimescaleInd ? pureDt : dt);
|
||||
if (_particleData.animTimeDelta[i] > _particleData.animTimeLength[i])
|
||||
{
|
||||
auto& anim = _animations.at(_particleData.animIndex[i]);
|
||||
float percent = abs(RANDOM_KISS());
|
||||
percent = anim.reverseIndices ? 1.0F - percent : percent;
|
||||
|
||||
_particleData.animCellIndex[i] = anim.animationIndices[MIN(
|
||||
percent * anim.animationIndices.size(), anim.animationIndices.size() - 1)];
|
||||
_particleData.animTimeDelta[i] = 0;
|
||||
}
|
||||
}
|
||||
if (_isLifeAnimated && _animations.empty())
|
||||
{
|
||||
float percent = (_particleData.totalTimeToLive[i] - _particleData.timeToLive[i]) / _particleData.totalTimeToLive[i];
|
||||
percent = _isAnimationReversed ? 1.0F - percent : percent;
|
||||
_particleData.animCellIndex[i] = (unsigned short)MIN(percent * _animIndexCount, _animIndexCount - 1);
|
||||
}
|
||||
if (_isLifeAnimated && !_animations.empty())
|
||||
{
|
||||
auto& anim = _animations.at(_particleData.animIndex[i]);
|
||||
|
||||
float percent =
|
||||
(_particleData.totalTimeToLive[i] - _particleData.timeToLive[i]) / _particleData.totalTimeToLive[i];
|
||||
percent = (!!_isAnimationReversed != !!anim.reverseIndices) ? 1.0F - percent : percent;
|
||||
percent = MAX(0.0F, percent);
|
||||
|
||||
_particleData.animCellIndex[i] = anim.animationIndices[MIN(percent * anim.animationIndices.size(),
|
||||
anim.animationIndices.size() - 1)];
|
||||
}
|
||||
if (_isLoopAnimated && !_animations.empty())
|
||||
{
|
||||
auto& anim = _animations.at(_particleData.animIndex[i]);
|
||||
|
||||
_particleData.animTimeDelta[i] += (_animationTimescaleInd ? pureDt : 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;
|
||||
percent = MAX(0.0F, percent);
|
||||
|
||||
_particleData.animCellIndex[i] = anim.animationIndices[MIN(percent * anim.animationIndices.size(),
|
||||
anim.animationIndices.size() - 1)];
|
||||
}
|
||||
if (_isLoopAnimated && _animations.empty())
|
||||
std::fill_n(_particleData.animTimeDelta, _particleCount, 0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < _particleCount; ++i)
|
||||
|
@ -952,12 +1296,6 @@ void ParticleSystem::update(float dt)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Why use so many for-loop separately instead of putting them together?
|
||||
// When the processor needs to read from or write to a location in memory,
|
||||
// it first checks whether a copy of that data is in the cache.
|
||||
// And every property's memory of the particle system is continuous,
|
||||
// for the purpose of improving cache hit rate, we should process only one property in one for-loop AFAP.
|
||||
// It was proved to be effective especially for low-end machine.
|
||||
for (int i = 0; i < _particleCount; ++i)
|
||||
{
|
||||
_particleData.modeB.angle[i] += _particleData.modeB.degreesPerSecond[i] * dt;
|
||||
|
@ -1015,7 +1353,7 @@ void ParticleSystem::update(float dt)
|
|||
_transformSystemDirty = false;
|
||||
}
|
||||
|
||||
// only update gl buffer when visible
|
||||
// update and send gl buffer only when this node is visible.
|
||||
if (_visible && !_batchNode)
|
||||
{
|
||||
postStep();
|
||||
|
@ -1386,4 +1724,39 @@ void ParticleSystem::resumeEmissions()
|
|||
_paused = false;
|
||||
}
|
||||
|
||||
bool ParticleSystem::isUpdatePaused() const
|
||||
{
|
||||
return _updatePaused;
|
||||
}
|
||||
|
||||
void ParticleSystem::pauseUpdate()
|
||||
{
|
||||
_updatePaused = true;
|
||||
}
|
||||
|
||||
void ParticleSystem::resumeUpdate()
|
||||
{
|
||||
_updatePaused = false;
|
||||
}
|
||||
|
||||
float ParticleSystem::getFixedFPS()
|
||||
{
|
||||
return _fixedFPS;
|
||||
}
|
||||
|
||||
void ParticleSystem::setFixedFPS(float frameRate)
|
||||
{
|
||||
_fixedFPS = frameRate;
|
||||
}
|
||||
|
||||
float ParticleSystem::getTimeScale()
|
||||
{
|
||||
return _timeScale;
|
||||
}
|
||||
|
||||
void ParticleSystem::setTimeScale(float scale)
|
||||
{
|
||||
_timeScale = scale;
|
||||
}
|
||||
|
||||
NS_CC_END
|
||||
|
|
|
@ -32,6 +32,8 @@ THE SOFTWARE.
|
|||
#include "base/CCProtocols.h"
|
||||
#include "2d/CCNode.h"
|
||||
#include "base/CCValue.h"
|
||||
#include "2d/CCSpriteFrame.h"
|
||||
#include "2d/CCSpriteFrameCache.h"
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
|
@ -52,6 +54,26 @@ struct particle_point
|
|||
float y;
|
||||
};
|
||||
|
||||
/** @struct ParticleAnimationDescriptor
|
||||
Structure that contains animation description
|
||||
*/
|
||||
struct ParticleAnimationDescriptor
|
||||
{
|
||||
float animationSpeed;
|
||||
float animationSpeedVariance;
|
||||
std::vector<unsigned short> animationIndices;
|
||||
bool reverseIndices;
|
||||
};
|
||||
|
||||
/** @struct ParticleFrameDescriptor
|
||||
Structure that contains frame description
|
||||
*/
|
||||
struct ParticleFrameDescriptor
|
||||
{
|
||||
cocos2d::Rect rect;
|
||||
bool isRotated;
|
||||
};
|
||||
|
||||
class CC_DLL ParticleData
|
||||
{
|
||||
public:
|
||||
|
@ -70,11 +92,21 @@ public:
|
|||
float* deltaColorB;
|
||||
float* deltaColorA;
|
||||
|
||||
float* hue;
|
||||
float* sat;
|
||||
float* val;
|
||||
|
||||
float* size;
|
||||
float* deltaSize;
|
||||
float* rotation;
|
||||
float* staticRotation;
|
||||
float* deltaRotation;
|
||||
float* totalTimeToLive;
|
||||
float* timeToLive;
|
||||
float* animTimeDelta;
|
||||
float* animTimeLength;
|
||||
unsigned short* animIndex;
|
||||
unsigned short* animCellIndex;
|
||||
unsigned int* atlasIndex;
|
||||
|
||||
//! Mode A: gravity, direction, radial accel, tangential accel
|
||||
|
@ -118,15 +150,24 @@ public:
|
|||
deltaColorB[p1] = deltaColorB[p2];
|
||||
deltaColorA[p1] = deltaColorA[p2];
|
||||
|
||||
size[p1] = size[p2];
|
||||
deltaSize[p1] = deltaSize[p2];
|
||||
hue[p1] = hue[p2];
|
||||
sat[p1] = sat[p2];
|
||||
val[p1] = val[p2];
|
||||
|
||||
rotation[p1] = rotation[p2];
|
||||
deltaRotation[p1] = deltaRotation[p2];
|
||||
size[p1] = size[p2];
|
||||
deltaSize[p1] = deltaSize[p2];
|
||||
rotation[p1] = rotation[p2];
|
||||
staticRotation[p1] = staticRotation[p2];
|
||||
deltaRotation[p1] = deltaRotation[p2];
|
||||
|
||||
timeToLive[p1] = timeToLive[p2];
|
||||
totalTimeToLive[p1] = totalTimeToLive[p2];
|
||||
timeToLive[p1] = timeToLive[p2];
|
||||
animTimeDelta[p1] = animTimeDelta[p2];
|
||||
animTimeLength[p1] = animTimeLength[p2];
|
||||
|
||||
atlasIndex[p1] = atlasIndex[p2];
|
||||
animIndex[p1] = animIndex[p2];
|
||||
animCellIndex[p1] = animCellIndex[p2];
|
||||
atlasIndex[p1] = atlasIndex[p2];
|
||||
|
||||
modeA.dirX[p1] = modeA.dirX[p2];
|
||||
modeA.dirY[p1] = modeA.dirY[p2];
|
||||
|
@ -202,7 +243,7 @@ public:
|
|||
};
|
||||
|
||||
/** PositionType
|
||||
Possible types of particle positions.
|
||||
Types of particle positioning.
|
||||
* @js cc.ParticleSystem.TYPE_FREE
|
||||
*/
|
||||
enum class PositionType
|
||||
|
@ -216,6 +257,17 @@ public:
|
|||
|
||||
};
|
||||
|
||||
/** TexAnimDir
|
||||
Texture animation direction for the particles.
|
||||
*/
|
||||
enum class TexAnimDir
|
||||
{
|
||||
VERTICAL, /** texture coordinates are read top to bottom within the texture */
|
||||
|
||||
HORIZONTAL, /** texture coordinates are read left to right within the texture */
|
||||
|
||||
};
|
||||
|
||||
//* @enum
|
||||
enum
|
||||
{
|
||||
|
@ -227,6 +279,12 @@ public:
|
|||
|
||||
/** The starting radius of the particle is equal to the ending radius. */
|
||||
START_RADIUS_EQUAL_TO_END_RADIUS = -1,
|
||||
|
||||
/** The simulation's seconds are set to the particles' lifetime specified inclusive of variant. */
|
||||
SIMULATION_USE_PARTICLE_LIFETIME = -1,
|
||||
|
||||
/** The simulation's framerate is set to the animation interval specified in director. */
|
||||
SIMULATION_USE_GAME_ANIMATION_INTERVAL = -1,
|
||||
};
|
||||
|
||||
/** Creates an initializes a ParticleSystem from a plist file.
|
||||
|
@ -252,7 +310,7 @@ public:
|
|||
static Vector<ParticleSystem*>& getAllParticleSystems();
|
||||
|
||||
public:
|
||||
void addParticles(int count);
|
||||
void addParticles(int count, int animationCellIndex = -1, int animationIndex = -1);
|
||||
|
||||
void stopSystem();
|
||||
/** Kill all living particles.
|
||||
|
@ -658,6 +716,58 @@ public:
|
|||
*/
|
||||
void setEndColorVar(const Color4F& color) { _endColorVar = color; }
|
||||
|
||||
/** Sets wether to use HSV color system.
|
||||
* WARNING: becareful when using HSV with too many particles because it's expensive.
|
||||
*
|
||||
* @param hsv Use HSV color system.
|
||||
*/
|
||||
void useHSV(bool hsv) { _isHsv = hsv; };
|
||||
bool isHSV() { return _isHsv; };
|
||||
|
||||
/** Gets the hue of each particle.
|
||||
*
|
||||
* @return The hue of each particle.
|
||||
*/
|
||||
float getHue() const { return _hsv.h; }
|
||||
/** Sets the hue of each particle.
|
||||
*
|
||||
* @param hsv The hue color of each particle.
|
||||
*/
|
||||
void setHue(float hue) { _hsv.h = hue; }
|
||||
|
||||
/** Gets the hue variance of each particle.
|
||||
*
|
||||
* @return The hue variance of each particle.
|
||||
*/
|
||||
float getHueVar() const { return _hsvVar.h; }
|
||||
/** Sets the hue variance of each particle.
|
||||
*
|
||||
* @param hsv The hue variance color of each particle.
|
||||
*/
|
||||
void setHueVar(float hue) { _hsvVar.h = hue; }
|
||||
|
||||
/** Gets the HSV color of each particle.
|
||||
*
|
||||
* @return The HSV color of each particle.
|
||||
*/
|
||||
const HSV& getHSV() const { return _hsv; }
|
||||
/** Sets the HSV color of each particle.
|
||||
*
|
||||
* @param hsv The HSV color of each particle.
|
||||
*/
|
||||
void setHSV(const HSV& hsv) { _hsv = hsv; }
|
||||
|
||||
/** Gets the HSV color variance of each particle.
|
||||
*
|
||||
* @return The HSV color variance of each particle.
|
||||
*/
|
||||
const HSV& getHSVVar() const { return _hsvVar; }
|
||||
/** Sets the HSV color variance of each particle.
|
||||
*
|
||||
* @param hsv The HSV color variance of each particle.
|
||||
*/
|
||||
void setHSVVar(const HSV& hsv) { _hsvVar = hsv; }
|
||||
|
||||
/** Gets the start spin of each particle.
|
||||
*
|
||||
* @return The start spin of each particle.
|
||||
|
@ -702,6 +812,28 @@ public:
|
|||
*/
|
||||
void setEndSpinVar(float endSpinVar) { _endSpinVar = endSpinVar; }
|
||||
|
||||
/** Gets the spawn angle of each particle
|
||||
*
|
||||
* @return The angle in degrees of each particle.
|
||||
*/
|
||||
float getSpawnAngle() { return _spawnAngle; }
|
||||
/** Sets the spawn angle of each particle
|
||||
*
|
||||
* @param angle The angle in degrees of each particle.
|
||||
*/
|
||||
void setSpawnAngle(float angle) { _spawnAngle = angle; }
|
||||
|
||||
/** Sets the spawn angle variance of each particle.
|
||||
*
|
||||
* @return The angle variance in degrees of each particle.
|
||||
*/
|
||||
float getSpawnAngleVar() { return _spawnAngleVar; }
|
||||
/** Sets the spawn angle variance of each particle.
|
||||
*
|
||||
* @param angle The angle variance in degrees of each particle.
|
||||
*/
|
||||
void setSpawnAngleVar(float angle) { _spawnAngleVar = angle; }
|
||||
|
||||
/** Gets the emission rate of the particles.
|
||||
*
|
||||
* @return The emission rate of the particles.
|
||||
|
@ -728,6 +860,160 @@ public:
|
|||
void setOpacityModifyRGB(bool opacityModifyRGB) override { _opacityModifyRGB = opacityModifyRGB; }
|
||||
bool isOpacityModifyRGB() const override { return _opacityModifyRGB; }
|
||||
|
||||
/** Enables or disables tex coord animations that are set based on particle life. */
|
||||
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. */
|
||||
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 */
|
||||
void setLoopAnimation(bool enabled)
|
||||
{
|
||||
_isLoopAnimated = enabled;
|
||||
_isEmitterAnimated = false;
|
||||
_isLifeAnimated = false;
|
||||
}
|
||||
|
||||
bool isLifeAnimated() { return _isLifeAnimated; }
|
||||
bool isEmitterAnimated() { return _isEmitterAnimated; }
|
||||
bool isLoopAnimated() { return _isLoopAnimated; }
|
||||
|
||||
/** Gets the total number of indices.
|
||||
*
|
||||
* @return The size of the list holding animation indices.
|
||||
*/
|
||||
int getTotalAnimationIndices() { return _animIndexCount; }
|
||||
|
||||
/** Sets wether to start from first cell and go forwards (normal) or last cell and go backwards (reversed) */
|
||||
void setAnimationReverse(bool reverse) { _isAnimationReversed = reverse; }
|
||||
bool isAnimationReversed() { return _isAnimationReversed; }
|
||||
|
||||
/** Resets the count of indices to 0 and empties the animation index array */
|
||||
void resetAnimationIndices();
|
||||
|
||||
/** Empties the container of animation descriptors */
|
||||
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 indices of animations to play at random
|
||||
*/
|
||||
void setMultiAnimationRandomSpecific(const 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 all particle animation indices based on cells size and direction spicified using a texture atlas.
|
||||
* will erase the array and add new indices from the atlas.
|
||||
* This function will automatically figure out your atlas cell size and direction for you! thank her later :) */
|
||||
void setAnimationIndicesAtlas();
|
||||
|
||||
/** Add all particle animation indices based on cell size and direction spicified if the method of rendering preferred is texture atlas.
|
||||
* will erase the array and add new indices from the atlas.
|
||||
*
|
||||
* @param unifiedCellSize The size of cell unified.
|
||||
* @param direction What direction is the atlas
|
||||
*/
|
||||
void setAnimationIndicesAtlas(unsigned int unifiedCellSize, TexAnimDir direction = TexAnimDir::HORIZONTAL);
|
||||
|
||||
/** Add a particle animation index based on tex coords spicified using a sprite frame.
|
||||
* The index is automatically incremented on each addition.
|
||||
*
|
||||
* @param frameName SpriteFrame name to search for
|
||||
*
|
||||
* @return Returns true of the index was successfully found and added. Otherwise, false
|
||||
*/
|
||||
bool addAnimationIndex(std::string_view frameName);
|
||||
|
||||
/** Add a particle animation index based on tex coords spicified using a sprite frame.
|
||||
*
|
||||
* @param index Index id to add the frame to or override it with the new frame
|
||||
* @param frameName SpriteFrame name to search for
|
||||
*
|
||||
* @return Returns true of the index was successfully found and added. Otherwise, false
|
||||
*/
|
||||
bool addAnimationIndex(unsigned short index, std::string_view frameName);
|
||||
|
||||
/** Add a particle animation index based on tex coords spicified using a sprite frame.
|
||||
* The index is automatically incremented on each addition.
|
||||
*
|
||||
* @param frame SpriteFrame containting data about tex coords
|
||||
*
|
||||
* @return Returns true of the index was successfully found and added. Otherwise, false
|
||||
*/
|
||||
bool addAnimationIndex(cocos2d::SpriteFrame* frame);
|
||||
|
||||
/** Add a particle animation index based on tex coords spicified using a sprite frame.
|
||||
* you can specify which index you want to override in this function
|
||||
*
|
||||
* @param index Index id to add the frame to or override it with the new frame
|
||||
* @param frame SpriteFrame containting data about tex coords
|
||||
*
|
||||
* @return Returns true of the index was successfully found and added. Otherwise, false
|
||||
*/
|
||||
bool addAnimationIndex(unsigned short index, cocos2d::SpriteFrame* frame);
|
||||
|
||||
/** Add a particle animation index based on tex coords spicified.
|
||||
* you can specify which index you want to override in this function
|
||||
*
|
||||
* @param index Index id to add the frame to or override it with the new rect
|
||||
* @param rect Rect containting data about tex coords in pixels
|
||||
* @param rotated Not implemented.
|
||||
*
|
||||
* @return Returns true of the index was successfully found and added. Otherwise, false
|
||||
*/
|
||||
bool addAnimationIndex(unsigned short index, cocos2d::Rect rect, bool rotated = false);
|
||||
|
||||
/** You can specify what rect is used if an index in an animation descriptor wasn't found.
|
||||
*
|
||||
* @param rect Rect containting data about tex coords in pixels
|
||||
*/
|
||||
void setRectForUndefinedIndices(cocos2d::Rect rect) { _undefinedIndexRect = rect; };
|
||||
|
||||
/** 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,
|
||||
const std::vector<unsigned short> &indices,
|
||||
bool reverse = false);
|
||||
|
||||
/** Add a particle animation descriptor with the index 0.
|
||||
*
|
||||
* @param indices An array of the indicies
|
||||
* @param reverse Should the animation indicies be played backwards? (default: false)
|
||||
*/
|
||||
void setAnimationDescriptor(const std::vector<unsigned short> &indices, bool reverse = false)
|
||||
{
|
||||
setAnimationDescriptor(0, 0, 0, indices, reverse);
|
||||
};
|
||||
|
||||
/** Sets wether the animation descriptors should follow the time scale of the system or not.
|
||||
*
|
||||
* @param independent Should the animation descriptor speeds be played independently? (default: false)
|
||||
*/
|
||||
void setAnimationSpeedTimescaleIndependent(bool independent) { _animationTimescaleInd = independent; };
|
||||
bool isAnimationSpeedTimescaleIndependent() { return _animationTimescaleInd; };
|
||||
|
||||
/** Gets the particles movement type: Free or Grouped.
|
||||
@since v0.8
|
||||
*
|
||||
|
@ -741,6 +1027,23 @@ public:
|
|||
*/
|
||||
void setPositionType(PositionType type) { _positionType = type; }
|
||||
|
||||
/** Advance the particle system and make it seem like it ran for this many seconds.
|
||||
*
|
||||
* @param seconds Seconds to advance. value of -1 means (SIMULATION_USE_PARTICLE_LIFETIME)
|
||||
* @param frameRate Frame rate to run the simulation with (preferred: 30.0) The higher this value is the more accurate the simulation will be at the cost of performance. value of -1 means (SIMULATION_USE_GAME_ANIMATION_INTERVAL)
|
||||
*/
|
||||
void simulate(float seconds = SIMULATION_USE_PARTICLE_LIFETIME,
|
||||
float frameRate = SIMULATION_USE_GAME_ANIMATION_INTERVAL);
|
||||
|
||||
/** Resets the particle system and then advances the particle system and make it seem like it ran for this many
|
||||
* seconds. The frame rate used for simulation accuracy is the screens refresh rate.
|
||||
*
|
||||
* @param seconds Seconds to advance. value of -1 means (SIMULATION_USE_PARTICLE_LIFETIME)
|
||||
* @param frameRate Frame rate to run the simulation with (preferred: 30.0) The higher this value is the more accurate the simulation will be at the cost of performance. value of -1 means (SIMULATION_USE_GAME_ANIMATION_INTERVAL)
|
||||
*/
|
||||
void resimulate(float seconds = SIMULATION_USE_PARTICLE_LIFETIME,
|
||||
float frameRate = SIMULATION_USE_GAME_ANIMATION_INTERVAL);
|
||||
|
||||
// Overrides
|
||||
virtual void onEnter() override;
|
||||
virtual void onExit() override;
|
||||
|
@ -812,12 +1115,43 @@ public:
|
|||
*/
|
||||
virtual bool isPaused() const;
|
||||
|
||||
/* Pause the emissions*/
|
||||
/* Pause the emissions */
|
||||
virtual void pauseEmissions();
|
||||
|
||||
/* UnPause the emissions*/
|
||||
/* Unpause the emissions */
|
||||
virtual void resumeEmissions();
|
||||
|
||||
/** Is system update paused
|
||||
@return True if the emissions are paused, else false
|
||||
*/
|
||||
virtual bool isUpdatePaused() const;
|
||||
|
||||
/* Pause the particles from being updated */
|
||||
virtual void pauseUpdate();
|
||||
|
||||
/* Unpause the particles from being updated */
|
||||
virtual void resumeUpdate();
|
||||
|
||||
/** Gets the fixed frame rate count of the particle system.
|
||||
@return Fixed frame rate count of the particle system.
|
||||
*/
|
||||
virtual float getFixedFPS();
|
||||
|
||||
/** Sets the fixed frame rate count of the particle system.
|
||||
@param Fixed frame rate count of the particle system. (default: 0.0)
|
||||
*/
|
||||
virtual void setFixedFPS(float frameRate = 0.0F);
|
||||
|
||||
/** Gets the time scale of the particle system.
|
||||
@return Time scale of the particle system.
|
||||
*/
|
||||
virtual float getTimeScale();
|
||||
|
||||
/** Gets the time scale of the particle system.
|
||||
@param Time scale of the particle system. (default: 1.0)
|
||||
*/
|
||||
virtual void setTimeScale(float scale = 1.0F);
|
||||
|
||||
protected:
|
||||
virtual void updateBlendFunc();
|
||||
|
||||
|
@ -957,6 +1291,12 @@ protected:
|
|||
Color4F _endColor;
|
||||
/** end color variance of each particle */
|
||||
Color4F _endColorVar;
|
||||
//* Is the hsv system used or not.
|
||||
bool _isHsv;
|
||||
/** hsv color of each particle */
|
||||
HSV _hsv;
|
||||
/** hsv color variance of each particle */
|
||||
HSV _hsvVar;
|
||||
//* initial angle of each particle
|
||||
float _startSpin;
|
||||
//* initial angle of each particle
|
||||
|
@ -965,6 +1305,10 @@ protected:
|
|||
float _endSpin;
|
||||
//* initial angle of each particle
|
||||
float _endSpinVar;
|
||||
//* initial rotation of each particle
|
||||
float _spawnAngle;
|
||||
//* initial rotation of each particle
|
||||
float _spawnAngleVar;
|
||||
/** emission rate of the particles */
|
||||
float _emissionRate;
|
||||
/** maximum particles of the system */
|
||||
|
@ -975,6 +1319,26 @@ protected:
|
|||
BlendFunc _blendFunc;
|
||||
/** does the alpha value modify color */
|
||||
bool _opacityModifyRGB;
|
||||
/** is the particle system animated */
|
||||
bool _isLifeAnimated;
|
||||
/** is the emitter particle system animated */
|
||||
bool _isEmitterAnimated;
|
||||
/** is the emitter particle system animated */
|
||||
bool _isLoopAnimated;
|
||||
/** variable keeping count of sprite frames or atlas indices added */
|
||||
int _animIndexCount;
|
||||
/** wether to start from first or last when using life animation */
|
||||
bool _isAnimationReversed;
|
||||
/** A map that stores particle animation index coords */
|
||||
std::unordered_map<unsigned short, ParticleFrameDescriptor> _animationIndices;
|
||||
/** 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;
|
||||
/** Wether the animation goes with the time scale of the system or is independent. */
|
||||
bool _animationTimescaleInd;
|
||||
/** A rect that is used instead when an index is not found */
|
||||
cocos2d::Rect _undefinedIndexRect;
|
||||
/** does FlippedY variance of each particle */
|
||||
int _yCoordFlipped;
|
||||
|
||||
|
@ -986,6 +1350,18 @@ protected:
|
|||
/** is the emitter paused */
|
||||
bool _paused;
|
||||
|
||||
/** is particle system update paused */
|
||||
bool _updatePaused;
|
||||
|
||||
/** time scale of the particle system */
|
||||
float _timeScale;
|
||||
|
||||
/** Fixed frame rate of the particle system */
|
||||
float _fixedFPS;
|
||||
|
||||
/** Fixed frame rate delta (internal) */
|
||||
float _fixedFPSDelta;
|
||||
|
||||
/** is sourcePosition compatible */
|
||||
bool _sourcePositionCompatible;
|
||||
|
||||
|
|
|
@ -105,6 +105,8 @@ ParticleSystemQuad* ParticleSystemQuad::create(std::string_view filename)
|
|||
|
||||
ParticleSystemQuad* ParticleSystemQuad::createWithTotalParticles(int numberOfParticles)
|
||||
{
|
||||
CCASSERT(numberOfParticles <= 10000, "Adding more than 10000 particles will crash the renderer, the mesh generated has an index format of U_SHORT (uint16_t)");
|
||||
|
||||
ParticleSystemQuad* ret = new ParticleSystemQuad();
|
||||
if (ret->initWithTotalParticles(numberOfParticles))
|
||||
{
|
||||
|
@ -273,7 +275,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
|
||||
float size_2 = size / 2;
|
||||
|
@ -285,7 +291,7 @@ inline void updatePosWithParticle(V3F_C4B_T2F_Quad* quad, const Vec2& newPositio
|
|||
float x = newPosition.x;
|
||||
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 sr = sinf(r);
|
||||
float ax = x1 * cr - y1 * sr + x;
|
||||
|
@ -351,14 +357,15 @@ void ParticleSystemQuad::updateParticleQuads()
|
|||
worldToNodeTM.transformPoint(&p1);
|
||||
Vec3 p2;
|
||||
Vec2 newPos;
|
||||
float* startX = _particleData.startPosX;
|
||||
float* startY = _particleData.startPosY;
|
||||
float* x = _particleData.posx;
|
||||
float* y = _particleData.posy;
|
||||
float* s = _particleData.size;
|
||||
float* r = _particleData.rotation;
|
||||
float* startX = _particleData.startPosX;
|
||||
float* startY = _particleData.startPosY;
|
||||
float* x = _particleData.posx;
|
||||
float* y = _particleData.posy;
|
||||
float* s = _particleData.size;
|
||||
float* r = _particleData.rotation;
|
||||
float* sr = _particleData.staticRotation;
|
||||
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);
|
||||
worldToNodeTM.transformPoint(&p2);
|
||||
|
@ -366,7 +373,7 @@ void ParticleSystemQuad::updateParticleQuads()
|
|||
p2 = p1 - p2;
|
||||
newPos.x -= p2.x - pos.x;
|
||||
newPos.y -= p2.y - pos.y;
|
||||
updatePosWithParticle(quadStart, newPos, *s, *r);
|
||||
updatePosWithParticle(quadStart, newPos, *s, *r, *sr);
|
||||
}
|
||||
}
|
||||
else if (_positionType == PositionType::RELATIVE)
|
||||
|
@ -378,14 +385,15 @@ void ParticleSystemQuad::updateParticleQuads()
|
|||
float* y = _particleData.posy;
|
||||
float* s = _particleData.size;
|
||||
float* r = _particleData.rotation;
|
||||
float* sr = _particleData.staticRotation;
|
||||
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.x = *x - (currentPosition.x - *startX);
|
||||
newPos.y = *y - (currentPosition.y - *startY);
|
||||
newPos += pos;
|
||||
updatePosWithParticle(quadStart, newPos, *s, *r);
|
||||
updatePosWithParticle(quadStart, newPos, *s, *r, *sr);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -397,53 +405,146 @@ void ParticleSystemQuad::updateParticleQuads()
|
|||
float* y = _particleData.posy;
|
||||
float* s = _particleData.size;
|
||||
float* r = _particleData.rotation;
|
||||
float* sr = _particleData.staticRotation;
|
||||
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);
|
||||
updatePosWithParticle(quadStart, newPos, *s, *r);
|
||||
updatePosWithParticle(quadStart, newPos, *s, *r, *sr);
|
||||
}
|
||||
}
|
||||
|
||||
// set color
|
||||
if (_opacityModifyRGB)
|
||||
{
|
||||
V3F_C4B_T2F_Quad* quad = startQuad;
|
||||
float* r = _particleData.colorR;
|
||||
float* g = _particleData.colorG;
|
||||
float* b = _particleData.colorB;
|
||||
float* a = _particleData.colorA;
|
||||
V3F_C4B_T2F_Quad* quad = startQuad;
|
||||
float* r = _particleData.colorR;
|
||||
float* g = _particleData.colorG;
|
||||
float* b = _particleData.colorB;
|
||||
float* a = _particleData.colorA;
|
||||
|
||||
for (int i = 0; i < _particleCount; ++i, ++quad, ++r, ++g, ++b, ++a)
|
||||
// HSV calculation is expensive, so we should skip it if it's not enabled.
|
||||
if (_isHsv)
|
||||
{
|
||||
float* hue = _particleData.hue;
|
||||
float* sat = _particleData.sat;
|
||||
float* val = _particleData.val;
|
||||
|
||||
if (_opacityModifyRGB)
|
||||
{
|
||||
uint8_t colorR = *r * *a * 255;
|
||||
uint8_t colorG = *g * *a * 255;
|
||||
uint8_t colorB = *b * *a * 255;
|
||||
uint8_t colorA = *a * 255;
|
||||
quad->bl.colors.set(colorR, colorG, colorB, colorA);
|
||||
quad->br.colors.set(colorR, colorG, colorB, colorA);
|
||||
quad->tl.colors.set(colorR, colorG, colorB, colorA);
|
||||
quad->tr.colors.set(colorR, colorG, colorB, colorA);
|
||||
auto hsv = HSV();
|
||||
for (int i = 0; i < _particleCount; ++i, ++quad, ++r, ++g, ++b, ++a, ++hue, ++sat, ++val)
|
||||
{
|
||||
float colorR = *r * *a;
|
||||
float colorG = *g * *a;
|
||||
float colorB = *b * *a;
|
||||
float colorA = *a;
|
||||
hsv.set(colorR, colorG, colorB, colorA);
|
||||
hsv.h += *hue;
|
||||
hsv.s = abs(*sat);
|
||||
hsv.v = abs(*val);
|
||||
auto col = hsv.toColor4B();
|
||||
quad->bl.colors.set(col.r, col.g, col.b, col.a);
|
||||
quad->br.colors.set(col.r, col.g, col.b, col.a);
|
||||
quad->tl.colors.set(col.r, col.g, col.b, col.a);
|
||||
quad->tr.colors.set(col.r, col.g, col.b, col.a);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto hsv = HSV();
|
||||
for (int i = 0; i < _particleCount; ++i, ++quad, ++r, ++g, ++b, ++a, ++hue, ++sat, ++val)
|
||||
{
|
||||
float colorR = *r;
|
||||
float colorG = *g;
|
||||
float colorB = *b;
|
||||
float colorA = *a;
|
||||
hsv.set(colorR, colorG, colorB, colorA);
|
||||
hsv.h += *hue;
|
||||
hsv.s = abs(*sat);
|
||||
hsv.v = abs(*val);
|
||||
auto col = hsv.toColor4B();
|
||||
quad->bl.colors.set(col.r, col.g, col.b, col.a);
|
||||
quad->br.colors.set(col.r, col.g, col.b, col.a);
|
||||
quad->tl.colors.set(col.r, col.g, col.b, col.a);
|
||||
quad->tr.colors.set(col.r, col.g, col.b, col.a);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
V3F_C4B_T2F_Quad* quad = startQuad;
|
||||
float* r = _particleData.colorR;
|
||||
float* g = _particleData.colorG;
|
||||
float* b = _particleData.colorB;
|
||||
float* a = _particleData.colorA;
|
||||
|
||||
for (int i = 0; i < _particleCount; ++i, ++quad, ++r, ++g, ++b, ++a)
|
||||
// set color
|
||||
if (_opacityModifyRGB)
|
||||
{
|
||||
uint8_t colorR = *r * 255;
|
||||
uint8_t colorG = *g * 255;
|
||||
uint8_t colorB = *b * 255;
|
||||
uint8_t colorA = *a * 255;
|
||||
quad->bl.colors.set(colorR, colorG, colorB, colorA);
|
||||
quad->br.colors.set(colorR, colorG, colorB, colorA);
|
||||
quad->tl.colors.set(colorR, colorG, colorB, colorA);
|
||||
quad->tr.colors.set(colorR, colorG, colorB, colorA);
|
||||
for (int i = 0; i < _particleCount; ++i, ++quad, ++r, ++g, ++b, ++a)
|
||||
{
|
||||
uint8_t colorR = *r * *a * 255;
|
||||
uint8_t colorG = *g * *a * 255;
|
||||
uint8_t colorB = *b * *a * 255;
|
||||
uint8_t colorA = *a * 255;
|
||||
quad->bl.colors.set(colorR, colorG, colorB, colorA);
|
||||
quad->br.colors.set(colorR, colorG, colorB, colorA);
|
||||
quad->tl.colors.set(colorR, colorG, colorB, colorA);
|
||||
quad->tr.colors.set(colorR, colorG, colorB, colorA);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < _particleCount; ++i, ++quad, ++r, ++g, ++b, ++a)
|
||||
{
|
||||
uint8_t colorR = *r * 255;
|
||||
uint8_t colorG = *g * 255;
|
||||
uint8_t colorB = *b * 255;
|
||||
uint8_t colorA = *a * 255;
|
||||
quad->bl.colors.set(colorR, colorG, colorB, colorA);
|
||||
quad->br.colors.set(colorR, colorG, colorB, colorA);
|
||||
quad->tl.colors.set(colorR, colorG, colorB, colorA);
|
||||
quad->tr.colors.set(colorR, colorG, colorB, colorA);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The reason for using for-loops separately for every property is because
|
||||
// When the processor needs to read from or write to a location in memory,
|
||||
// it first checks whether a copy of that data is in the cpu's cache.
|
||||
// And wether if every property's memory of the particle system is continuous,
|
||||
// for the purpose of improving cache hit rate, we should process only one property in one for-loop.
|
||||
// It was proved to be effective especially for low-end devices.
|
||||
if (_isLifeAnimated || _isEmitterAnimated || _isLoopAnimated)
|
||||
{
|
||||
V3F_C4B_T2F_Quad* quad = startQuad;
|
||||
unsigned short* cellIndex = _particleData.animCellIndex;
|
||||
|
||||
ParticleFrameDescriptor index;
|
||||
for (int i = 0; i < _particleCount; ++i, ++quad, ++cellIndex)
|
||||
{
|
||||
float left = 0.0F, bottom = 0.0F, top = 1.0F, right = 1.0F;
|
||||
|
||||
// TODO: index.isRotated should be treated accordingly
|
||||
|
||||
auto iter = _animationIndices.find(*cellIndex);
|
||||
if (iter == _animationIndices.end())
|
||||
index.rect = _undefinedIndexRect;
|
||||
else
|
||||
index = iter->second;
|
||||
|
||||
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.v = bottom;
|
||||
|
||||
quad->br.texCoords.u = right;
|
||||
quad->br.texCoords.v = bottom;
|
||||
|
||||
quad->tl.texCoords.u = left;
|
||||
quad->tl.texCoords.v = top;
|
||||
|
||||
quad->tr.texCoords.u = right;
|
||||
quad->tr.texCoords.v = top;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,7 +86,6 @@ SpriteTests::SpriteTests()
|
|||
ADD_TEST_CASE(SpriteChildrenAnchorPoint);
|
||||
ADD_TEST_CASE(SpriteBatchNodeChildrenAnchorPoint);
|
||||
ADD_TEST_CASE(SpriteColorOpacity);
|
||||
ADD_TEST_CASE(SpriteColorOpacityHSVHSL);
|
||||
ADD_TEST_CASE(SpriteBatchNodeColorOpacity);
|
||||
ADD_TEST_CASE(SpriteZOrder);
|
||||
ADD_TEST_CASE(SpriteBatchNodeZOrder);
|
||||
|
@ -362,118 +361,6 @@ std::string SpriteColorOpacity::subtitle() const
|
|||
return "Color & Opacity";
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
//
|
||||
// SpriteColorOpacityHSVHSL
|
||||
//
|
||||
//------------------------------------------------------------------
|
||||
|
||||
SpriteColorOpacityHSVHSL::SpriteColorOpacityHSVHSL()
|
||||
{
|
||||
auto sprite1 = Sprite::create("Images/grossini_dance_atlas.png", Rect(85 * 0, 121 * 1, 85, 121));
|
||||
auto sprite2 = Sprite::create("Images/grossini_dance_atlas.png", Rect(85 * 1, 121 * 1, 85, 121));
|
||||
auto sprite3 = Sprite::create("Images/grossini_dance_atlas.png", Rect(85 * 2, 121 * 1, 85, 121));
|
||||
auto sprite4 = Sprite::create("Images/grossini_dance_atlas.png", Rect(85 * 3, 121 * 1, 85, 121));
|
||||
|
||||
auto sprite5 = Sprite::create("Images/grossini_dance_atlas.png", Rect(85 * 0, 121 * 1, 85, 121));
|
||||
auto sprite6 = Sprite::create("Images/grossini_dance_atlas.png", Rect(85 * 1, 121 * 1, 85, 121));
|
||||
auto sprite7 = Sprite::create("Images/grossini_dance_atlas.png", Rect(85 * 2, 121 * 1, 85, 121));
|
||||
auto sprite8 = Sprite::create("Images/grossini_dance_atlas.png", Rect(85 * 3, 121 * 1, 85, 121));
|
||||
|
||||
auto s = Director::getInstance()->getWinSize();
|
||||
sprite1->setPosition(Vec2((s.width / 5) * 1, (s.height / 3) * 1));
|
||||
sprite2->setPosition(Vec2((s.width / 5) * 2, (s.height / 3) * 1));
|
||||
sprite3->setPosition(Vec2((s.width / 5) * 3, (s.height / 3) * 1));
|
||||
sprite4->setPosition(Vec2((s.width / 5) * 4, (s.height / 3) * 1));
|
||||
sprite5->setPosition(Vec2((s.width / 5) * 1, (s.height / 3) * 2));
|
||||
sprite6->setPosition(Vec2((s.width / 5) * 2, (s.height / 3) * 2));
|
||||
sprite7->setPosition(Vec2((s.width / 5) * 3, (s.height / 3) * 2));
|
||||
sprite8->setPosition(Vec2((s.width / 5) * 4, (s.height / 3) * 2));
|
||||
|
||||
auto action = FadeIn::create(2);
|
||||
auto action_back = action->reverse();
|
||||
auto fade = RepeatForever::create(Sequence::create(action, action_back, nullptr));
|
||||
|
||||
auto col = HSV(0, 1, 1, 1).toColor3B();
|
||||
auto tintred = TintBy::create(2, col.r, col.g, col.b);
|
||||
auto tintred_back = tintred->reverse();
|
||||
auto red = RepeatForever::create(Sequence::create(tintred, tintred_back, nullptr));
|
||||
|
||||
col = HSV(120, 1, 1, 1).toColor3B();
|
||||
auto tintgreen = TintBy::create(2, col.r, col.g, col.b);
|
||||
auto tintgreen_back = tintgreen->reverse();
|
||||
auto green = RepeatForever::create(Sequence::create(tintgreen, tintgreen_back, nullptr));
|
||||
|
||||
col = HSV(240, 1, 1, 1).toColor3B();
|
||||
auto tintblue = TintBy::create(2, col.r, col.g, col.b);
|
||||
auto tintblue_back = tintblue->reverse();
|
||||
auto blue = RepeatForever::create(Sequence::create(tintblue, tintblue_back, nullptr));
|
||||
|
||||
sprite1->runAction(red);
|
||||
sprite2->runAction(green);
|
||||
sprite3->runAction(blue);
|
||||
sprite4->runAction(fade);
|
||||
|
||||
action = FadeIn::create(2);
|
||||
action_back = action->reverse();
|
||||
fade = RepeatForever::create(Sequence::create(action, action_back, nullptr));
|
||||
|
||||
col = HSL(0, 1, .7, 1).toColor3B();
|
||||
tintred = TintBy::create(2, col.r, col.g, col.b);
|
||||
tintred_back = tintred->reverse();
|
||||
red = RepeatForever::create(Sequence::create(tintred, tintred_back, nullptr));
|
||||
|
||||
col = HSL(120, 1, .7, 1).toColor3B();
|
||||
tintgreen = TintBy::create(2, col.r, col.g, col.b);
|
||||
tintgreen_back = tintgreen->reverse();
|
||||
green = RepeatForever::create(Sequence::create(tintgreen, tintgreen_back, nullptr));
|
||||
|
||||
col = HSL(240, 1, .7, 1).toColor3B();
|
||||
tintblue = TintBy::create(2, col.r, col.g, col.b);
|
||||
tintblue_back = tintblue->reverse();
|
||||
blue = RepeatForever::create(Sequence::create(tintblue, tintblue_back, nullptr));
|
||||
|
||||
sprite5->runAction(red);
|
||||
sprite6->runAction(green);
|
||||
sprite7->runAction(blue);
|
||||
sprite8->runAction(fade);
|
||||
|
||||
// late add: test dirtyColor and dirtyPosition
|
||||
addChild(sprite1, 0, kTagSprite1);
|
||||
addChild(sprite2, 0, kTagSprite2);
|
||||
addChild(sprite3, 0, kTagSprite3);
|
||||
addChild(sprite4, 0, kTagSprite4);
|
||||
addChild(sprite5, 0, kTagSprite5);
|
||||
addChild(sprite6, 0, kTagSprite6);
|
||||
addChild(sprite7, 0, kTagSprite7);
|
||||
addChild(sprite8, 0, kTagSprite8);
|
||||
|
||||
schedule(CC_CALLBACK_1(SpriteColorOpacityHSVHSL::removeAndAddSprite, this), 2, "remove_add_key");
|
||||
}
|
||||
|
||||
// this function test if remove and add works as expected:
|
||||
// color array and vertex array should be reindexed
|
||||
void SpriteColorOpacityHSVHSL::removeAndAddSprite(float dt)
|
||||
{
|
||||
auto sprite = static_cast<Sprite*>(getChildByTag(kTagSprite5));
|
||||
sprite->retain();
|
||||
|
||||
removeChild(sprite, false);
|
||||
addChild(sprite, 0, kTagSprite5);
|
||||
|
||||
sprite->release();
|
||||
}
|
||||
|
||||
std::string SpriteColorOpacityHSVHSL::title() const
|
||||
{
|
||||
return "Testing Sprite";
|
||||
}
|
||||
|
||||
std::string SpriteColorOpacityHSVHSL::subtitle() const
|
||||
{
|
||||
return "Color & Opacity using HSV/HSL";
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
//
|
||||
// SpriteBatchNodeColorOpacity
|
||||
|
|
|
@ -73,16 +73,6 @@ public:
|
|||
virtual std::string subtitle() const override;
|
||||
};
|
||||
|
||||
class SpriteColorOpacityHSVHSL : public SpriteTestDemo
|
||||
{
|
||||
public:
|
||||
CREATE_FUNC(SpriteColorOpacityHSVHSL);
|
||||
SpriteColorOpacityHSVHSL();
|
||||
void removeAndAddSprite(float dt);
|
||||
virtual std::string title() const override;
|
||||
virtual std::string subtitle() const override;
|
||||
};
|
||||
|
||||
class SpriteBatchNodeColorOpacity : public SpriteTestDemo
|
||||
{
|
||||
public:
|
||||
|
|
Loading…
Reference in New Issue