Conserve memory allocations & Improve animation system.

Use memory when we need it 😠
This commit is contained in:
DelinWorks 2022-05-26 15:56:56 +03:00
parent 7599aa29b1
commit 67098c979c
3 changed files with 228 additions and 114 deletions

View File

@ -138,9 +138,7 @@ bool ParticleData::init(int count)
deltaColorG = (float*)malloc(count * sizeof(float)); deltaColorG = (float*)malloc(count * sizeof(float));
deltaColorB = (float*)malloc(count * sizeof(float)); deltaColorB = (float*)malloc(count * sizeof(float));
deltaColorA = (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)); 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));
@ -148,10 +146,6 @@ bool ParticleData::init(int count)
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));
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)); atlasIndex = (unsigned int*)malloc(count * sizeof(unsigned int));
modeA.dirX = (float*)malloc(count * sizeof(float)); modeA.dirX = (float*)malloc(count * sizeof(float));
@ -165,10 +159,10 @@ bool ParticleData::init(int count)
modeB.radius = (float*)malloc(count * sizeof(float)); modeB.radius = (float*)malloc(count * sizeof(float));
return posx && posy && startPosX && startPosY && colorR && colorG && colorB && colorA && deltaColorR && return posx && posy && startPosX && startPosY && colorR && colorG && colorB && colorA && deltaColorR &&
deltaColorG && deltaColorB && deltaColorA && hue && sat && val && size && deltaSize && rotation && deltaColorG && deltaColorB && deltaColorA && size && deltaSize && rotation && staticRotation &&
staticRotation && deltaRotation && totalTimeToLive && timeToLive && animTimeLength && animTimeDelta && deltaRotation && totalTimeToLive && timeToLive && atlasIndex && modeA.dirX && modeA.dirY &&
animIndex && animCellIndex && atlasIndex && modeA.dirX && modeA.dirY && modeA.radialAccel && modeA.radialAccel && modeA.tangentialAccel && modeB.angle && modeB.degreesPerSecond && modeB.deltaRadius &&
modeA.tangentialAccel && modeB.angle && modeB.degreesPerSecond && modeB.deltaRadius && modeB.radius; modeB.radius;
} }
void ParticleData::release() void ParticleData::release()
@ -226,6 +220,8 @@ ParticleSystem::ParticleSystem()
, _atlasIndex(0) , _atlasIndex(0)
, _transformSystemDirty(false) , _transformSystemDirty(false)
, _allocatedParticles(0) , _allocatedParticles(0)
, _isAnimAllocated(false)
, _isHSVAllocated(false)
, _isActive(true) , _isActive(true)
, _particleCount(0) , _particleCount(0)
, _duration(0) , _duration(0)
@ -244,6 +240,7 @@ ParticleSystem::ParticleSystem()
, _endSpinVar(0) , _endSpinVar(0)
, _spawnAngle(0) , _spawnAngle(0)
, _spawnAngleVar(0) , _spawnAngleVar(0)
, _isHsv(false)
, _hsv(0, 1, 1) , _hsv(0, 1, 1)
, _hsvVar(0, 0, 0) , _hsvVar(0, 0, 0)
, _emissionRate(0) , _emissionRate(0)
@ -314,6 +311,51 @@ Vector<ParticleSystem*>& ParticleSystem::getAllParticleSystems()
return __allInstances; 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) void ParticleSystem::setTotalParticleCountFactor(float factor)
{ {
__totalParticleCountFactor = factor; __totalParticleCountFactor = factor;
@ -647,7 +689,7 @@ ParticleSystem::~ParticleSystem()
CC_SAFE_RELEASE(_texture); CC_SAFE_RELEASE(_texture);
} }
void ParticleSystem::addParticles(int count, int animationCellIndex, int animationIndex) void ParticleSystem::addParticles(int count, int animationIndex, int animationCellIndex)
{ {
if (_paused) if (_paused)
return; return;
@ -681,46 +723,57 @@ void ParticleSystem::addParticles(int count, int animationCellIndex, int animati
_particleData.posy[i] = _sourcePosition.y + _posVar.y * RANDOM_KISS(); _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); for (int i = start; i < _particleCount; ++i)
_particleData.animCellIndex[i] = MIN(rand0, _animIndexCount - 1); {
_particleData.animIndex[i] = animationIndex;
auto& descriptor = _animations.at(animationIndex);
_particleData.animTimeLength[i] =
descriptor.animationSpeed + descriptor.animationSpeedVariance * RANDOM_KISS();
}
} }
} }
if (animationCellIndex != -1) if (_isLifeAnimated || _isEmitterAnimated || _isLoopAnimated)
std::fill_n(_particleData.animCellIndex + start, _particleCount - start, animationCellIndex);
if (animationIndex == -1 && !_animations.empty())
{ {
if (_randomAnimations.empty()) if (animationCellIndex == -1 && _isEmitterAnimated)
setMultiAnimationRandom();
for (int i = start; i < _particleCount; ++i)
{ {
int rand0 = abs(RANDOM_KISS() * _randomAnimations.size()); for (int i = start; i < _particleCount; ++i)
int index = MIN(rand0, _randomAnimations.size() - 1); {
_particleData.animIndex[i] = _randomAnimations[index]; int rand0 = abs(RANDOM_KISS() * _animIndexCount);
auto& descriptor = _animations.at(_particleData.animIndex[i]); _particleData.animCellIndex[i] = MIN(rand0, _animIndexCount - 1);
_particleData.animTimeLength[i] = }
descriptor.animationSpeed + descriptor.animationSpeedVariance * RANDOM_KISS();
} }
}
if (_isEmitterAnimated || _isLoopAnimated) if (animationIndex == -1 && !_animations.empty())
std::fill_n(_particleData.animTimeDelta + start, _particleCount - start, 0);
if (animationIndex != -1)
{
for (int i = start; i < _particleCount; ++i)
{ {
_particleData.animIndex[i] = animationIndex; if (_randomAnimations.empty())
auto& descriptor = _animations.at(animationIndex); setMultiAnimationRandom();
_particleData.animTimeLength[i] =
descriptor.animationSpeed + descriptor.animationSpeedVariance * RANDOM_KISS(); 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 // color
@ -752,6 +805,7 @@ void ParticleSystem::addParticles(int count, int animationCellIndex, int animati
SET_DELTA_COLOR(_particleData.colorA, _particleData.deltaColorA); SET_DELTA_COLOR(_particleData.colorA, _particleData.deltaColorA);
// hue saturation value color // hue saturation value color
if (_isHSVAllocated)
{ {
for (int i = start; i < _particleCount; ++i) for (int i = start; i < _particleCount; ++i)
{ {
@ -915,6 +969,45 @@ void ParticleSystem::setAnimationDescriptor(unsigned short indexOfDescriptor,
desc.reverseIndices = reverse; 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() void ParticleSystem::resetAnimationIndices()
{ {
_animIndexCount = 0; _animIndexCount = 0;
@ -1175,55 +1268,64 @@ 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 (_isEmitterAnimated && !_animations.empty()) }
if (_isLifeAnimated || _isEmitterAnimated || _isLoopAnimated)
{
for (int i = 0; i < _particleCount; ++i)
{ {
_particleData.animTimeDelta[i] += (_animationTimescaleInd ? pureDt : dt); if (_isEmitterAnimated && !_animations.empty())
if (_particleData.animTimeDelta[i] > _particleData.animTimeLength[i])
{ {
auto& anim = _animations.at(_particleData.animIndex[i]); _particleData.animTimeDelta[i] += (_animationTimescaleInd ? pureDt : dt);
float percent = abs(RANDOM_KISS()); if (_particleData.animTimeDelta[i] > _particleData.animTimeLength[i])
percent = anim.reverseIndices ? 1.0F - percent : percent; {
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( _particleData.animCellIndex[i] = anim.animationIndices[MIN(
percent * anim.animationIndices.size(), anim.animationIndices.size() - 1)]; percent * anim.animationIndices.size(), anim.animationIndices.size() - 1)];
_particleData.animTimeDelta[i] = 0; _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) for (int i = 0; i < _particleCount; ++i)
@ -1614,6 +1716,17 @@ bool ParticleSystem::isActive() const
return _isActive; return _isActive;
} }
void ParticleSystem::useHSV(bool hsv)
{
if (hsv && !allocHSVMem())
return;
if (!hsv)
deallocHSVMem();
_isHsv = hsv;
};
int ParticleSystem::getTotalParticles() const int ParticleSystem::getTotalParticles() const
{ {
return _totalParticles; return _totalParticles;

View File

@ -150,9 +150,12 @@ public:
deltaColorB[p1] = deltaColorB[p2]; deltaColorB[p1] = deltaColorB[p2];
deltaColorA[p1] = deltaColorA[p2]; deltaColorA[p1] = deltaColorA[p2];
hue[p1] = hue[p2]; if (hue && sat && val)
sat[p1] = sat[p2]; {
val[p1] = val[p2]; hue[p1] = hue[p2];
sat[p1] = sat[p2];
val[p1] = val[p2];
}
size[p1] = size[p2]; size[p1] = size[p2];
deltaSize[p1] = deltaSize[p2]; deltaSize[p1] = deltaSize[p2];
@ -162,11 +165,15 @@ public:
totalTimeToLive[p1] = totalTimeToLive[p2]; totalTimeToLive[p1] = totalTimeToLive[p2];
timeToLive[p1] = timeToLive[p2]; timeToLive[p1] = timeToLive[p2];
animTimeDelta[p1] = animTimeDelta[p2];
animTimeLength[p1] = animTimeLength[p2];
animIndex[p1] = animIndex[p2]; if (animTimeDelta && animTimeLength && animIndex && animCellIndex)
animCellIndex[p1] = animCellIndex[p2]; {
animTimeDelta[p1] = animTimeDelta[p2];
animTimeLength[p1] = animTimeLength[p2];
animIndex[p1] = animIndex[p2];
animCellIndex[p1] = animCellIndex[p2];
}
atlasIndex[p1] = atlasIndex[p2]; atlasIndex[p1] = atlasIndex[p2];
modeA.dirX[p1] = modeA.dirX[p2]; modeA.dirX[p1] = modeA.dirX[p2];
@ -309,8 +316,17 @@ public:
*/ */
static Vector<ParticleSystem*>& getAllParticleSystems(); static Vector<ParticleSystem*>& getAllParticleSystems();
protected:
bool allocAnimationMem();
void deallocAnimationMem();
bool _isAnimAllocated;
bool allocHSVMem();
void deallocHSVMem();
bool _isHSVAllocated;
public: public:
void addParticles(int count, int animationCellIndex = -1, int animationIndex = -1); void addParticles(int count, int animationIndex = -1, int animationCellIndex = -1);
void stopSystem(); void stopSystem();
/** Kill all living particles. /** Kill all living particles.
@ -721,7 +737,7 @@ public:
* *
* @param hsv Use HSV color system. * @param hsv Use HSV color system.
*/ */
void useHSV(bool hsv) { _isHsv = hsv; }; void useHSV(bool hsv);
bool isHSV() { return _isHsv; }; bool isHSV() { return _isHsv; };
/** Gets the hue of each particle. /** Gets the hue of each particle.
@ -861,28 +877,13 @@ 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) 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. */
void setEmitterAnimation(bool 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 */ /** Enables or disables tex coord animations that are used to make particles play a sequence forever until they die */
void setLoopAnimation(bool enabled) 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; }

View File

@ -507,7 +507,7 @@ void ParticleSystemQuad::updateParticleQuads()
// And wether if every property's memory of the particle system is continuous, // 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. // 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. // 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; V3F_C4B_T2F_Quad* quad = startQuad;
unsigned short* cellIndex = _particleData.animCellIndex; unsigned short* cellIndex = _particleData.animCellIndex;
@ -521,7 +521,7 @@ void ParticleSystemQuad::updateParticleQuads()
auto iter = _animationIndices.find(*cellIndex); auto iter = _animationIndices.find(*cellIndex);
if (iter == _animationIndices.end()) if (iter == _animationIndices.end())
index.rect = _undefinedIndexRect; index.rect = {0, 0, float(_texture->getPixelsWide()), float(_texture->getPixelsHigh())};
else else
index = iter->second; index = iter->second;