diff --git a/core/2d/CCParticleSystem.cpp b/core/2d/CCParticleSystem.cpp index c8a8435c74..3aefab8b3b 100644 --- a/core/2d/CCParticleSystem.cpp +++ b/core/2d/CCParticleSystem.cpp @@ -138,9 +138,7 @@ bool ParticleData::init(int count) 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)); @@ -148,10 +146,6 @@ bool ParticleData::init(int count) 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)); @@ -165,10 +159,10 @@ bool ParticleData::init(int count) modeB.radius = (float*)malloc(count * sizeof(float)); 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; + deltaColorG && deltaColorB && deltaColorA && size && deltaSize && rotation && staticRotation && + deltaRotation && totalTimeToLive && timeToLive && atlasIndex && modeA.dirX && modeA.dirY && + modeA.radialAccel && modeA.tangentialAccel && modeB.angle && modeB.degreesPerSecond && modeB.deltaRadius && + modeB.radius; } void ParticleData::release() @@ -226,6 +220,8 @@ ParticleSystem::ParticleSystem() , _atlasIndex(0) , _transformSystemDirty(false) , _allocatedParticles(0) + , _isAnimAllocated(false) + , _isHSVAllocated(false) , _isActive(true) , _particleCount(0) , _duration(0) @@ -244,6 +240,7 @@ ParticleSystem::ParticleSystem() , _endSpinVar(0) , _spawnAngle(0) , _spawnAngleVar(0) + , _isHsv(false) , _hsv(0, 1, 1) , _hsvVar(0, 0, 0) , _emissionRate(0) @@ -314,6 +311,51 @@ Vector& ParticleSystem::getAllParticleSystems() return __allInstances; } +bool ParticleSystem::allocAnimationMem() +{ + if (!_isAnimAllocated) + { + _particleData.animTimeLength = (float*)malloc(_totalParticles * sizeof(float)); + _particleData.animTimeDelta = (float*)malloc(_totalParticles * sizeof(float)); + _particleData.animIndex = (unsigned short*)malloc(_totalParticles * sizeof(unsigned short)); + _particleData.animCellIndex = (unsigned short*)malloc(_totalParticles * sizeof(unsigned short)); + } + return _isAnimAllocated = _particleData.animTimeLength && _particleData.animTimeDelta && + _particleData.animIndex && _particleData.animCellIndex; +} + +void ParticleSystem::deallocAnimationMem() +{ + if (!_isAnimAllocated) + { + CC_SAFE_FREE(_particleData.animTimeLength); + CC_SAFE_FREE(_particleData.animTimeDelta); + CC_SAFE_FREE(_particleData.animIndex); + CC_SAFE_FREE(_particleData.animCellIndex); + } +} + +bool ParticleSystem::allocHSVMem() +{ + if (!_isHSVAllocated) + { + _particleData.hue = (float*)malloc(_totalParticles * sizeof(float)); + _particleData.sat = (float*)malloc(_totalParticles * sizeof(float)); + _particleData.val = (float*)malloc(_totalParticles * sizeof(float)); + } + return _isHSVAllocated = _particleData.hue && _particleData.sat && _particleData.val; +} + +void ParticleSystem::deallocHSVMem() +{ + if (!_isHSVAllocated) + { + CC_SAFE_FREE(_particleData.hue); + CC_SAFE_FREE(_particleData.sat); + CC_SAFE_FREE(_particleData.val); + } +} + void ParticleSystem::setTotalParticleCountFactor(float factor) { __totalParticleCountFactor = factor; @@ -647,7 +689,7 @@ ParticleSystem::~ParticleSystem() CC_SAFE_RELEASE(_texture); } -void ParticleSystem::addParticles(int count, int animationCellIndex, int animationIndex) +void ParticleSystem::addParticles(int count, int animationIndex, int animationCellIndex) { if (_paused) return; @@ -681,46 +723,57 @@ void ParticleSystem::addParticles(int count, int animationCellIndex, int animati _particleData.posy[i] = _sourcePosition.y + _posVar.y * RANDOM_KISS(); } - if (animationCellIndex == -1 && _isEmitterAnimated) + if (animationCellIndex != -1 || animationIndex != -1) + allocAnimationMem(); + + if (_isAnimAllocated) { - for (int i = start; i < _particleCount; ++i) + if (animationCellIndex != -1) + std::fill_n(_particleData.animCellIndex + start, _particleCount - start, animationCellIndex); + else + std::fill_n(_particleData.animCellIndex + start, _particleCount - start, 0xFFFF); + + if (animationIndex != -1) { - int rand0 = abs(RANDOM_KISS() * _animIndexCount); - _particleData.animCellIndex[i] = MIN(rand0, _animIndexCount - 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(); + } } } - if (animationCellIndex != -1) - std::fill_n(_particleData.animCellIndex + start, _particleCount - start, animationCellIndex); - - if (animationIndex == -1 && !_animations.empty()) + if (_isLifeAnimated || _isEmitterAnimated || _isLoopAnimated) { - if (_randomAnimations.empty()) - setMultiAnimationRandom(); - - for (int i = start; i < _particleCount; ++i) + if (animationCellIndex == -1 && _isEmitterAnimated) { - 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(); + for (int i = start; i < _particleCount; ++i) + { + int rand0 = abs(RANDOM_KISS() * _animIndexCount); + _particleData.animCellIndex[i] = MIN(rand0, _animIndexCount - 1); + } } - } - if (_isEmitterAnimated || _isLoopAnimated) - std::fill_n(_particleData.animTimeDelta + start, _particleCount - start, 0); - - if (animationIndex != -1) - { - for (int i = start; i < _particleCount; ++i) + if (animationIndex == -1 && !_animations.empty()) { - _particleData.animIndex[i] = animationIndex; - auto& descriptor = _animations.at(animationIndex); - _particleData.animTimeLength[i] = - descriptor.animationSpeed + descriptor.animationSpeedVariance * RANDOM_KISS(); + 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); } // color @@ -752,6 +805,7 @@ void ParticleSystem::addParticles(int count, int animationCellIndex, int animati SET_DELTA_COLOR(_particleData.colorA, _particleData.deltaColorA); // hue saturation value color + if (_isHSVAllocated) { for (int i = start; i < _particleCount; ++i) { @@ -915,6 +969,45 @@ void ParticleSystem::setAnimationDescriptor(unsigned short indexOfDescriptor, desc.reverseIndices = reverse; } +void ParticleSystem::setLifeAnimation(bool enabled) +{ + if (enabled && !allocAnimationMem()) + return; + + if (!enabled) + deallocAnimationMem(); + + _isLifeAnimated = enabled; + _isEmitterAnimated = false; + _isLoopAnimated = false; +} + +void ParticleSystem::setEmitterAnimation(bool enabled) +{ + if (enabled && !allocAnimationMem()) + return; + + if (!enabled) + deallocAnimationMem(); + + _isEmitterAnimated = enabled; + _isLifeAnimated = false; + _isLoopAnimated = false; +} + +void ParticleSystem::setLoopAnimation(bool enabled) +{ + if (enabled && !allocAnimationMem()) + return; + + if (!enabled) + deallocAnimationMem(); + + _isLoopAnimated = enabled; + _isEmitterAnimated = false; + _isLifeAnimated = false; +} + void ParticleSystem::resetAnimationIndices() { _animIndexCount = 0; @@ -1175,55 +1268,64 @@ void ParticleSystem::update(float dt) for (int i = 0; i < _particleCount; ++i) { _particleData.timeToLive[i] -= dt; - if (_isEmitterAnimated && !_animations.empty()) + } + + if (_isLifeAnimated || _isEmitterAnimated || _isLoopAnimated) + { + for (int i = 0; i < _particleCount; ++i) { - _particleData.animTimeDelta[i] += (_animationTimescaleInd ? pureDt : dt); - if (_particleData.animTimeDelta[i] > _particleData.animTimeLength[i]) + if (_isEmitterAnimated && !_animations.empty()) { - auto& anim = _animations.at(_particleData.animIndex[i]); - float percent = abs(RANDOM_KISS()); - percent = anim.reverseIndices ? 1.0F - percent : percent; + _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; + _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); } - 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) @@ -1614,6 +1716,17 @@ bool ParticleSystem::isActive() const return _isActive; } +void ParticleSystem::useHSV(bool hsv) +{ + if (hsv && !allocHSVMem()) + return; + + if (!hsv) + deallocHSVMem(); + + _isHsv = hsv; +}; + int ParticleSystem::getTotalParticles() const { return _totalParticles; diff --git a/core/2d/CCParticleSystem.h b/core/2d/CCParticleSystem.h index 040db16a75..afcac79e52 100644 --- a/core/2d/CCParticleSystem.h +++ b/core/2d/CCParticleSystem.h @@ -150,9 +150,12 @@ public: deltaColorB[p1] = deltaColorB[p2]; deltaColorA[p1] = deltaColorA[p2]; - hue[p1] = hue[p2]; - sat[p1] = sat[p2]; - val[p1] = val[p2]; + if (hue && sat && val) + { + hue[p1] = hue[p2]; + sat[p1] = sat[p2]; + val[p1] = val[p2]; + } size[p1] = size[p2]; deltaSize[p1] = deltaSize[p2]; @@ -162,11 +165,15 @@ public: totalTimeToLive[p1] = totalTimeToLive[p2]; timeToLive[p1] = timeToLive[p2]; - animTimeDelta[p1] = animTimeDelta[p2]; - animTimeLength[p1] = animTimeLength[p2]; - animIndex[p1] = animIndex[p2]; - animCellIndex[p1] = animCellIndex[p2]; + if (animTimeDelta && animTimeLength && animIndex && animCellIndex) + { + animTimeDelta[p1] = animTimeDelta[p2]; + animTimeLength[p1] = animTimeLength[p2]; + animIndex[p1] = animIndex[p2]; + animCellIndex[p1] = animCellIndex[p2]; + } + atlasIndex[p1] = atlasIndex[p2]; modeA.dirX[p1] = modeA.dirX[p2]; @@ -309,8 +316,17 @@ public: */ static Vector& getAllParticleSystems(); +protected: + bool allocAnimationMem(); + void deallocAnimationMem(); + bool _isAnimAllocated; + + bool allocHSVMem(); + void deallocHSVMem(); + bool _isHSVAllocated; + public: - void addParticles(int count, int animationCellIndex = -1, int animationIndex = -1); + void addParticles(int count, int animationIndex = -1, int animationCellIndex = -1); void stopSystem(); /** Kill all living particles. @@ -721,7 +737,7 @@ public: * * @param hsv Use HSV color system. */ - void useHSV(bool hsv) { _isHsv = hsv; }; + void useHSV(bool hsv); bool isHSV() { return _isHsv; }; /** Gets the hue of each particle. @@ -861,28 +877,13 @@ public: 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; - } + void setLifeAnimation(bool enabled); /** 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; - } + void setEmitterAnimation(bool enabled); /** 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; - } + void setLoopAnimation(bool enabled); bool isLifeAnimated() { return _isLifeAnimated; } bool isEmitterAnimated() { return _isEmitterAnimated; } diff --git a/core/2d/CCParticleSystemQuad.cpp b/core/2d/CCParticleSystemQuad.cpp index 365fe0c847..ea06e9a033 100644 --- a/core/2d/CCParticleSystemQuad.cpp +++ b/core/2d/CCParticleSystemQuad.cpp @@ -507,7 +507,7 @@ void ParticleSystemQuad::updateParticleQuads() // 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) + if (_isLifeAnimated || _isEmitterAnimated || _isLoopAnimated || _isAnimAllocated) { V3F_C4B_T2F_Quad* quad = startQuad; unsigned short* cellIndex = _particleData.animCellIndex; @@ -521,7 +521,7 @@ void ParticleSystemQuad::updateParticleQuads() auto iter = _animationIndices.find(*cellIndex); if (iter == _animationIndices.end()) - index.rect = _undefinedIndexRect; + index.rect = {0, 0, float(_texture->getPixelsWide()), float(_texture->getPixelsHigh())}; else index = iter->second;