mirror of https://github.com/axmolengine/axmol.git
1581 lines
47 KiB
C++
1581 lines
47 KiB
C++
/****************************************************************************
|
|
Copyright (C) 2013 Henry van Merode. All rights reserved.
|
|
Copyright (c) 2015-2016 Chukong Technologies Inc.
|
|
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
|
|
|
https://axys1.github.io/
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
****************************************************************************/
|
|
|
|
#include "extensions/Particle3D/PU/CCPUParticleSystem3D.h"
|
|
#include "extensions/Particle3D/PU/CCPUEmitter.h"
|
|
#include "extensions/Particle3D/PU/CCPUEmitterManager.h"
|
|
#include "extensions/Particle3D/PU/CCPUAffector.h"
|
|
#include "extensions/Particle3D/PU/CCPUAffectorManager.h"
|
|
#include "extensions/Particle3D/CCParticle3DRender.h"
|
|
#include "extensions/Particle3D/PU/CCPUScriptCompiler.h"
|
|
#include "extensions/Particle3D/PU/CCPUMaterialManager.h"
|
|
#include "extensions/Particle3D/PU/CCPUTranslateManager.h"
|
|
#include "extensions/Particle3D/PU/CCPUListener.h"
|
|
#include "extensions/Particle3D/PU/CCPUObserver.h"
|
|
#include "extensions/Particle3D/PU/CCPUObserverManager.h"
|
|
#include "extensions/Particle3D/PU/CCPUBehaviour.h"
|
|
#include "platform/CCFileUtils.h"
|
|
|
|
NS_AX_BEGIN
|
|
|
|
float PUParticle3D::DEFAULT_TTL = 10.0f;
|
|
float PUParticle3D::DEFAULT_MASS = 1.0f;
|
|
|
|
float PUParticle3D::calculateVelocity() const
|
|
{
|
|
if (originalScaledDirectionLength != 0)
|
|
{
|
|
return originalVelocity * (direction.length() / originalScaledDirectionLength);
|
|
}
|
|
else
|
|
{
|
|
// Assume originalScaledDirectionLength to be 1.0 (unit vector)
|
|
return originalVelocity * direction.length();
|
|
}
|
|
}
|
|
|
|
void PUParticle3D::setOwnDimensions(float newWidth, float newHeight, float newDepth)
|
|
{
|
|
ownDimensions = true;
|
|
if (newWidth)
|
|
width = newWidth;
|
|
if (newHeight)
|
|
height = newHeight;
|
|
if (newDepth)
|
|
depth = newDepth;
|
|
calculateBoundingSphereRadius();
|
|
// parentEmitter->getParentTechnique()->_notifyParticleResized();
|
|
}
|
|
|
|
void PUParticle3D::calculateBoundingSphereRadius()
|
|
{
|
|
// radius = 0.5 * Math::Sqrt(width*width + height*height + depth*depth);
|
|
radius = 0.5f * std::max(depth, std::max(width, height)); // approximation
|
|
}
|
|
|
|
void PUParticle3D::initForEmission()
|
|
{
|
|
eventFlags = 0;
|
|
timeFraction = 0.0f;
|
|
/* Note, that this flag must only be set as soon as the particle is emitted. As soon as the particle has
|
|
been moved once, the flag must be removed again.
|
|
*/
|
|
addEventFlags(PUParticle3D::PEF_EMITTED);
|
|
|
|
// Reset freeze flag
|
|
freezed = false;
|
|
|
|
if (!behaviours.empty())
|
|
{
|
|
for (auto&& it : behaviours)
|
|
{
|
|
it->initParticleForEmission(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PUParticle3D::initForExpiration(float timeElapsed)
|
|
{
|
|
if (!behaviours.empty())
|
|
{
|
|
for (auto&& it : behaviours)
|
|
{
|
|
it->initParticleForExpiration(this, timeElapsed);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PUParticle3D::process(float timeElapsed)
|
|
{
|
|
timeFraction = (totalTimeToLive - timeToLive) / totalTimeToLive;
|
|
|
|
if (!behaviours.empty())
|
|
{
|
|
for (auto&& it : behaviours)
|
|
{
|
|
it->updateBehaviour(this, timeElapsed);
|
|
}
|
|
}
|
|
}
|
|
|
|
PUParticle3D::PUParticle3D()
|
|
: particleEntityPtr(nullptr)
|
|
, parentEmitter(nullptr)
|
|
, visualData(nullptr)
|
|
, particleType(PT_VISUAL)
|
|
, originalDirectionLength(0.0f)
|
|
, originalVelocity(0.0f)
|
|
, originalScaledDirectionLength(0.0f)
|
|
, rotationAxis(Vec3::UNIT_Z)
|
|
,
|
|
// color(Vec4::ONE),
|
|
originalColor(Vec4::ONE)
|
|
,
|
|
// zRotation(0.0f),
|
|
zRotationSpeed(0.0f)
|
|
, rotationSpeed(0.0f)
|
|
, radius(0.87f)
|
|
, ownDimensions(false)
|
|
, eventFlags(0)
|
|
, freezed(false)
|
|
, timeToLive(DEFAULT_TTL)
|
|
, totalTimeToLive(DEFAULT_TTL)
|
|
, timeFraction(0.0f)
|
|
, mass(DEFAULT_MASS)
|
|
, textureAnimationTimeStep(0.1f)
|
|
, textureAnimationTimeStepCount(0.0f)
|
|
, textureCoordsCurrent(0)
|
|
, textureAnimationDirectionUp(true)
|
|
, depthInView(0.0f)
|
|
, zRotation(0.0f)
|
|
// widthInWorld(width),
|
|
// heightInWorld(height),
|
|
// depthInWorld(depth)
|
|
{}
|
|
|
|
PUParticle3D::~PUParticle3D()
|
|
{
|
|
for (auto&& it : behaviours)
|
|
{
|
|
it->release();
|
|
}
|
|
|
|
// AX_SAFE_RELEASE(particleEntityPtr);
|
|
}
|
|
|
|
void PUParticle3D::copyBehaviours(const ParticleBehaviourList& list)
|
|
{
|
|
for (auto&& it : list)
|
|
{
|
|
auto behaviour = it->clone();
|
|
behaviour->retain();
|
|
behaviours.emplace_back(behaviour);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
const float PUParticleSystem3D::DEFAULT_WIDTH = 50;
|
|
const float PUParticleSystem3D::DEFAULT_HEIGHT = 50;
|
|
const float PUParticleSystem3D::DEFAULT_DEPTH = 50;
|
|
const unsigned int PUParticleSystem3D::DEFAULT_PARTICLE_QUOTA = 500;
|
|
const unsigned int PUParticleSystem3D::DEFAULT_EMITTED_EMITTER_QUOTA = 50;
|
|
const unsigned int PUParticleSystem3D::DEFAULT_EMITTED_SYSTEM_QUOTA = 10;
|
|
const float PUParticleSystem3D::DEFAULT_MAX_VELOCITY = 9999.0f;
|
|
|
|
PUParticleSystem3D::PUParticleSystem3D()
|
|
: _emittedEmitterQuota(DEFAULT_EMITTED_EMITTER_QUOTA)
|
|
, _emittedSystemQuota(DEFAULT_EMITTED_SYSTEM_QUOTA)
|
|
, _prepared(false)
|
|
, _poolPrepared(false)
|
|
, _particleSystemScaleVelocity(1.0f)
|
|
, _timeElapsedSinceStart(0.0f)
|
|
, _defaultWidth(DEFAULT_WIDTH)
|
|
, _defaultHeight(DEFAULT_HEIGHT)
|
|
, _defaultDepth(DEFAULT_DEPTH)
|
|
, _maxVelocity(DEFAULT_MAX_VELOCITY)
|
|
, _maxVelocitySet(false)
|
|
, _isMarkedForEmission(false)
|
|
, _parentParticleSystem(nullptr)
|
|
{
|
|
_particleQuota = DEFAULT_PARTICLE_QUOTA;
|
|
}
|
|
PUParticleSystem3D::~PUParticleSystem3D()
|
|
{
|
|
stopParticleSystem();
|
|
unPrepared();
|
|
|
|
_particlePool.removeAllDatas();
|
|
|
|
for (auto&& iter : _emittedEmitterParticlePool)
|
|
{
|
|
auto pool = iter.second;
|
|
auto lockedList = pool.getUnActiveDataList();
|
|
for (auto&& iter2 : lockedList)
|
|
{
|
|
static_cast<PUParticle3D*>(iter2)->particleEntityPtr->release();
|
|
}
|
|
iter.second.removeAllDatas();
|
|
}
|
|
|
|
for (auto&& iter : _emittedSystemParticlePool)
|
|
{
|
|
auto pool = iter.second;
|
|
auto lockedList = pool.getUnActiveDataList();
|
|
for (auto&& iter2 : lockedList)
|
|
{
|
|
static_cast<PUParticle3D*>(iter2)->particleEntityPtr->release();
|
|
}
|
|
iter.second.removeAllDatas();
|
|
}
|
|
|
|
// release all emitters
|
|
for (auto&& it : _emitters)
|
|
{
|
|
it->release();
|
|
}
|
|
_emitters.clear();
|
|
|
|
for (auto&& it : _observers)
|
|
{
|
|
it->release();
|
|
}
|
|
|
|
for (auto&& it : _behaviourTemplates)
|
|
{
|
|
it->release();
|
|
}
|
|
|
|
_observers.clear();
|
|
}
|
|
|
|
PUParticleSystem3D* PUParticleSystem3D::create()
|
|
{
|
|
auto pups = new PUParticleSystem3D();
|
|
pups->autorelease();
|
|
return pups;
|
|
}
|
|
|
|
PUParticleSystem3D* PUParticleSystem3D::create(std::string_view filePath, std::string_view materialPath)
|
|
{
|
|
PUParticleSystem3D* ret = new PUParticleSystem3D();
|
|
if (ret->initWithFilePathAndMaterialPath(filePath, materialPath))
|
|
{
|
|
ret->autorelease();
|
|
return ret;
|
|
}
|
|
else
|
|
{
|
|
AX_SAFE_DELETE(ret);
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
PUParticleSystem3D* PUParticleSystem3D::create(std::string_view filePath)
|
|
{
|
|
PUParticleSystem3D* ret = new PUParticleSystem3D();
|
|
if (ret->initWithFilePath(filePath))
|
|
{
|
|
ret->autorelease();
|
|
return ret;
|
|
}
|
|
else
|
|
{
|
|
AX_SAFE_DELETE(ret);
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
bool PUParticleSystem3D::initWithFilePath(std::string_view filePath)
|
|
{
|
|
std::string fullPath = FileUtils::getInstance()->fullPathForFilename(filePath);
|
|
convertToUnixStylePath(fullPath);
|
|
std::string::size_type pos = fullPath.find_last_of('/');
|
|
std::string materialFolder = "materials";
|
|
if (pos != std::string::npos)
|
|
{
|
|
std::string temp = fullPath.substr(0, pos);
|
|
pos = temp.find_last_of('/');
|
|
if (pos != std::string::npos)
|
|
{
|
|
materialFolder = temp.substr(0, pos + 1) + materialFolder;
|
|
}
|
|
}
|
|
static std::vector<std::string> loadedFolder;
|
|
if (std::find(loadedFolder.begin(), loadedFolder.end(), materialFolder) == loadedFolder.end())
|
|
{
|
|
PUMaterialCache::Instance()->loadMaterialsFromSearchPaths(materialFolder);
|
|
loadedFolder.emplace_back(materialFolder);
|
|
}
|
|
|
|
if (!initSystem(fullPath))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool PUParticleSystem3D::initWithFilePathAndMaterialPath(std::string_view filePath, std::string_view materialPath)
|
|
{
|
|
std::string matfullPath = FileUtils::getInstance()->fullPathForFilename(materialPath);
|
|
convertToUnixStylePath(matfullPath);
|
|
PUMaterialCache::Instance()->loadMaterials(matfullPath);
|
|
std::string fullPath = FileUtils::getInstance()->fullPathForFilename(filePath);
|
|
convertToUnixStylePath(fullPath);
|
|
if (!initSystem(fullPath))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void PUParticleSystem3D::startParticleSystem()
|
|
{
|
|
stopParticleSystem();
|
|
|
|
if (_state != State::RUNNING)
|
|
{
|
|
forceStopParticleSystem();
|
|
if (_render)
|
|
_render->notifyStart();
|
|
|
|
for (auto&& it : _observers)
|
|
{
|
|
it->notifyStart();
|
|
}
|
|
|
|
for (auto&& it : _emitters)
|
|
{
|
|
auto emitter = static_cast<PUEmitter*>(it);
|
|
emitter->notifyStart();
|
|
}
|
|
|
|
for (auto&& it : _affectors)
|
|
{
|
|
auto affector = static_cast<PUAffector*>(it);
|
|
affector->notifyStart();
|
|
}
|
|
|
|
scheduleUpdate();
|
|
_state = State::RUNNING;
|
|
}
|
|
|
|
for (auto&& iter : _children)
|
|
{
|
|
PUParticleSystem3D* system = dynamic_cast<PUParticleSystem3D*>(iter);
|
|
if (system)
|
|
{
|
|
system->_parentParticleSystem = this;
|
|
system->startParticleSystem();
|
|
}
|
|
}
|
|
}
|
|
|
|
void PUParticleSystem3D::stopParticleSystem()
|
|
{
|
|
if (_state != State::STOP)
|
|
{
|
|
_state = State::STOP;
|
|
}
|
|
|
|
for (auto&& iter : _children)
|
|
{
|
|
PUParticleSystem3D* system = dynamic_cast<PUParticleSystem3D*>(iter);
|
|
if (system)
|
|
system->stopParticleSystem();
|
|
}
|
|
}
|
|
|
|
void PUParticleSystem3D::pauseParticleSystem()
|
|
{
|
|
if (_state == State::RUNNING)
|
|
{
|
|
// if (_emitter)
|
|
//{
|
|
// auto emitter = static_cast<PUEmitter*>(_emitter);
|
|
// emitter->notifyPause();
|
|
// }
|
|
|
|
for (auto&& it : _emitters)
|
|
{
|
|
auto emitter = static_cast<PUEmitter*>(it);
|
|
emitter->notifyPause();
|
|
}
|
|
|
|
for (auto&& it : _affectors)
|
|
{
|
|
auto affector = static_cast<PUAffector*>(it);
|
|
affector->notifyPause();
|
|
}
|
|
|
|
_state = State::PAUSE;
|
|
}
|
|
|
|
for (auto&& iter : _children)
|
|
{
|
|
PUParticleSystem3D* system = dynamic_cast<PUParticleSystem3D*>(iter);
|
|
if (system)
|
|
system->pauseParticleSystem();
|
|
}
|
|
}
|
|
|
|
void PUParticleSystem3D::resumeParticleSystem()
|
|
{
|
|
if (_state == State::PAUSE)
|
|
{
|
|
// if (_emitter)
|
|
//{
|
|
// auto emitter = static_cast<PUEmitter*>(_emitter);
|
|
// emitter->notifyResume();
|
|
// }
|
|
|
|
for (auto&& it : _emitters)
|
|
{
|
|
auto emitter = static_cast<PUEmitter*>(it);
|
|
emitter->notifyResume();
|
|
}
|
|
|
|
for (auto&& it : _affectors)
|
|
{
|
|
auto affector = static_cast<PUAffector*>(it);
|
|
affector->notifyResume();
|
|
}
|
|
|
|
_state = State::RUNNING;
|
|
}
|
|
|
|
for (auto&& iter : _children)
|
|
{
|
|
PUParticleSystem3D* system = dynamic_cast<PUParticleSystem3D*>(iter);
|
|
if (system)
|
|
system->resumeParticleSystem();
|
|
}
|
|
}
|
|
|
|
void PUParticleSystem3D::update(float delta)
|
|
{
|
|
if (!_isEnabled || _isMarkedForEmission)
|
|
return;
|
|
if (_state != State::RUNNING)
|
|
{
|
|
if (_state == State::PAUSE)
|
|
return;
|
|
else if (_state == State::STOP && getAliveParticleCount() <= 0)
|
|
{
|
|
forceStopParticleSystem();
|
|
return;
|
|
}
|
|
}
|
|
|
|
forceUpdate(delta);
|
|
}
|
|
|
|
void PUParticleSystem3D::forceUpdate(float delta)
|
|
{
|
|
if (!_emitters.empty())
|
|
calulateRotationOffset();
|
|
|
|
prepared();
|
|
|
|
Vec3 currentPos = getDerivedPosition();
|
|
_latestPositionDiff = currentPos - _latestPosition;
|
|
_latestPosition = currentPos;
|
|
_latestOrientation = getDerivedOrientation();
|
|
|
|
if (!_emitters.empty())
|
|
{
|
|
emitParticles(delta);
|
|
preUpdator(delta);
|
|
updator(delta);
|
|
postUpdator(delta);
|
|
}
|
|
|
|
_timeElapsedSinceStart += delta;
|
|
}
|
|
|
|
float PUParticleSystem3D::getParticleSystemScaleVelocity() const
|
|
{
|
|
return _particleSystemScaleVelocity;
|
|
}
|
|
|
|
void PUParticleSystem3D::rotationOffset(Vec3& pos)
|
|
{
|
|
Mat4 rotMat;
|
|
Mat4::createRotation(_rotationOffset, &rotMat);
|
|
pos = _rotationCentre + rotMat * (pos - _rotationCentre);
|
|
}
|
|
|
|
void PUParticleSystem3D::prepared()
|
|
{
|
|
if (!_prepared)
|
|
{
|
|
// if (_emitter && _emitter->isEnabled())
|
|
//{
|
|
// auto emitter = static_cast<PUEmitter*>(_emitter);
|
|
// emitter->prepare();
|
|
// }
|
|
|
|
if (_render)
|
|
static_cast<PURender*>(_render)->prepare();
|
|
|
|
for (auto&& it : _behaviourTemplates)
|
|
{
|
|
it->prepare();
|
|
}
|
|
|
|
for (auto&& it : _emitters)
|
|
{
|
|
// if (it->isEnabled())
|
|
(static_cast<PUEmitter*>(it))->prepare();
|
|
}
|
|
|
|
for (auto&& it : _affectors)
|
|
{
|
|
// if (it->isEnabled())
|
|
(static_cast<PUAffector*>(it))->prepare();
|
|
}
|
|
|
|
if (!_poolPrepared)
|
|
{
|
|
for (auto&& it : _emitters)
|
|
{
|
|
// if (it->isEnabled())
|
|
PUEmitter* emitter = static_cast<PUEmitter*>(it);
|
|
if (emitter->getEmitsType() == PUParticle3D::PT_EMITTER)
|
|
{
|
|
PUEmitter* emitted = static_cast<PUEmitter*>(emitter->getEmitsEntityPtr());
|
|
for (unsigned int i = 0; i < _emittedEmitterQuota; ++i)
|
|
{
|
|
auto p = new PUParticle3D();
|
|
p->particleType = PUParticle3D::PT_EMITTER;
|
|
p->particleEntityPtr = emitted->clone();
|
|
p->particleEntityPtr->retain();
|
|
p->copyBehaviours(_behaviourTemplates);
|
|
_emittedEmitterParticlePool[emitted->getName()].addData(p);
|
|
}
|
|
}
|
|
else if (emitter->getEmitsType() == PUParticle3D::PT_TECHNIQUE)
|
|
{
|
|
PUParticleSystem3D* emitted = static_cast<PUParticleSystem3D*>(emitter->getEmitsEntityPtr());
|
|
for (unsigned int i = 0; i < _emittedSystemQuota; ++i)
|
|
{
|
|
PUParticleSystem3D* clonePS = emitted->clone();
|
|
auto p = new PUParticle3D();
|
|
p->particleType = PUParticle3D::PT_TECHNIQUE;
|
|
p->particleEntityPtr = clonePS;
|
|
p->particleEntityPtr->retain();
|
|
p->copyBehaviours(_behaviourTemplates);
|
|
_emittedSystemParticlePool[emitted->getName()].addData(p);
|
|
clonePS->prepared();
|
|
}
|
|
// emitted->stopParticle();
|
|
}
|
|
}
|
|
|
|
for (unsigned int i = 0; i < _particleQuota; ++i)
|
|
{
|
|
auto p = new PUParticle3D();
|
|
p->copyBehaviours(_behaviourTemplates);
|
|
_particlePool.addData(p);
|
|
}
|
|
_poolPrepared = true;
|
|
}
|
|
|
|
_prepared = true;
|
|
_timeElapsedSinceStart = 0.0f;
|
|
_latestPosition = getDerivedPosition(); // V1.3.1
|
|
if (_parentParticleSystem)
|
|
{
|
|
_particleSystemScaleVelocity = _parentParticleSystem->getParticleSystemScaleVelocity();
|
|
}
|
|
}
|
|
|
|
if (!_emitters.empty())
|
|
notifyRescaled(getDerivedScale());
|
|
}
|
|
|
|
void PUParticleSystem3D::unPrepared()
|
|
{
|
|
// if (_emitter && _emitter->isEnabled())
|
|
//{
|
|
// auto emitter = static_cast<PUEmitter*>(_emitter);
|
|
// emitter->unPrepare();
|
|
// }
|
|
if (_prepared)
|
|
{
|
|
if (_render)
|
|
static_cast<PURender*>(_render)->unPrepare();
|
|
|
|
for (auto&& it : _behaviourTemplates)
|
|
{
|
|
it->unPrepare();
|
|
}
|
|
|
|
for (auto&& it : _emitters)
|
|
{
|
|
if (it->isEnabled())
|
|
(static_cast<PUEmitter*>(it))->unPrepare();
|
|
}
|
|
|
|
for (auto&& it : _affectors)
|
|
{
|
|
if (it->isEnabled())
|
|
(static_cast<PUAffector*>(it))->unPrepare();
|
|
}
|
|
|
|
_particlePool.lockAllDatas();
|
|
for (auto&& iter : _emittedEmitterParticlePool)
|
|
{
|
|
PUParticle3D* particle = static_cast<PUParticle3D*>(const_cast<ParticlePool&>(iter.second).getFirst());
|
|
while (particle)
|
|
{
|
|
static_cast<PUEmitter*>(particle->particleEntityPtr)->unPrepare();
|
|
particle = static_cast<PUParticle3D*>(const_cast<ParticlePool&>(iter.second).getNext());
|
|
}
|
|
const_cast<ParticlePool&>(iter.second).lockAllDatas();
|
|
}
|
|
|
|
for (auto&& iter : _emittedSystemParticlePool)
|
|
{
|
|
PUParticle3D* particle = static_cast<PUParticle3D*>(const_cast<ParticlePool&>(iter.second).getFirst());
|
|
while (particle)
|
|
{
|
|
static_cast<PUParticleSystem3D*>(particle->particleEntityPtr)->unPrepared();
|
|
particle = static_cast<PUParticle3D*>(const_cast<ParticlePool&>(iter.second).getNext());
|
|
}
|
|
const_cast<ParticlePool&>(iter.second).lockAllDatas();
|
|
}
|
|
_prepared = false;
|
|
}
|
|
}
|
|
|
|
void PUParticleSystem3D::preUpdator(float elapsedTime)
|
|
{
|
|
// if (_emitter && _emitter->isEnabled())
|
|
//{
|
|
// auto emitter = static_cast<PUEmitter*>(_emitter);
|
|
// emitter->preUpdateEmitter(elapsedTime);
|
|
// }
|
|
// bool hasNoEmitted = true;
|
|
for (auto&& it : _emitters)
|
|
{
|
|
if (!it->isEmitterDone())
|
|
{
|
|
(static_cast<PUEmitter*>(it))->preUpdateEmitter(elapsedTime);
|
|
// hasNoEmitted = false;
|
|
}
|
|
}
|
|
|
|
// if (hasNoEmitted){
|
|
// if (_particlePool.getActiveParticleList().empty())
|
|
// stopParticle();
|
|
// }
|
|
|
|
for (auto&& it : _affectors)
|
|
{
|
|
if (it->isEnabled())
|
|
{
|
|
(static_cast<PUAffector*>(it))->preUpdateAffector(elapsedTime);
|
|
}
|
|
}
|
|
|
|
for (auto&& it : _observers)
|
|
{
|
|
if (it->isEnabled())
|
|
{
|
|
it->preUpdateObserver(elapsedTime);
|
|
}
|
|
}
|
|
|
|
for (auto&& iter : _emittedEmitterParticlePool)
|
|
{
|
|
PUParticle3D* particle = static_cast<PUParticle3D*>(const_cast<ParticlePool&>(iter.second).getFirst());
|
|
while (particle)
|
|
{
|
|
static_cast<PUEmitter*>(particle->particleEntityPtr)->preUpdateEmitter(elapsedTime);
|
|
particle = static_cast<PUParticle3D*>(const_cast<ParticlePool&>(iter.second).getNext());
|
|
}
|
|
}
|
|
|
|
for (auto&& iter : _emittedSystemParticlePool)
|
|
{
|
|
PUParticle3D* particle = static_cast<PUParticle3D*>(const_cast<ParticlePool&>(iter.second).getFirst());
|
|
while (particle)
|
|
{
|
|
static_cast<PUParticleSystem3D*>(particle->particleEntityPtr)->preUpdator(elapsedTime);
|
|
particle = static_cast<PUParticle3D*>(const_cast<ParticlePool&>(iter.second).getNext());
|
|
}
|
|
}
|
|
}
|
|
|
|
void PUParticleSystem3D::updator(float elapsedTime)
|
|
{
|
|
bool firstActiveParticle = true;
|
|
bool firstParticle = true;
|
|
processParticle(_particlePool, firstActiveParticle, firstParticle, elapsedTime);
|
|
|
|
for (auto&& iter : _emittedEmitterParticlePool)
|
|
{
|
|
processParticle(const_cast<ParticlePool&>(iter.second), firstActiveParticle, firstParticle, elapsedTime);
|
|
}
|
|
|
|
for (auto&& iter : _emittedSystemParticlePool)
|
|
{
|
|
processParticle(const_cast<ParticlePool&>(iter.second), firstActiveParticle, firstParticle, elapsedTime);
|
|
}
|
|
}
|
|
|
|
void PUParticleSystem3D::postUpdator(float elapsedTime)
|
|
{
|
|
// if (_emitter && _emitter->isEnabled())
|
|
//{
|
|
// auto emitter = static_cast<PUEmitter*>(_emitter);
|
|
// emitter->postUpdateEmitter(elapsedTime);
|
|
// }
|
|
|
|
for (auto&& it : _emitters)
|
|
{
|
|
if (it->isEnabled())
|
|
{
|
|
(static_cast<PUEmitter*>(it))->postUpdateEmitter(elapsedTime);
|
|
}
|
|
}
|
|
|
|
for (auto&& it : _affectors)
|
|
{
|
|
if (it->isEnabled())
|
|
{
|
|
auto affector = static_cast<PUAffector*>(it);
|
|
affector->postUpdateAffector(elapsedTime);
|
|
}
|
|
}
|
|
|
|
for (auto&& it : _observers)
|
|
{
|
|
if (it->isEnabled())
|
|
{
|
|
it->postUpdateObserver(elapsedTime);
|
|
}
|
|
}
|
|
|
|
for (auto&& iter : _emittedEmitterParticlePool)
|
|
{
|
|
PUParticle3D* particle = static_cast<PUParticle3D*>(const_cast<ParticlePool&>(iter.second).getFirst());
|
|
while (particle)
|
|
{
|
|
static_cast<PUEmitter*>(particle->particleEntityPtr)->postUpdateEmitter(elapsedTime);
|
|
particle = static_cast<PUParticle3D*>(const_cast<ParticlePool&>(iter.second).getNext());
|
|
}
|
|
}
|
|
|
|
for (auto&& iter : _emittedSystemParticlePool)
|
|
{
|
|
PUParticle3D* particle = static_cast<PUParticle3D*>(const_cast<ParticlePool&>(iter.second).getFirst());
|
|
while (particle)
|
|
{
|
|
static_cast<PUParticleSystem3D*>(particle->particleEntityPtr)->postUpdator(elapsedTime);
|
|
particle = static_cast<PUParticle3D*>(const_cast<ParticlePool&>(iter.second).getNext());
|
|
}
|
|
}
|
|
}
|
|
|
|
void PUParticleSystem3D::emitParticles(float elapsedTime)
|
|
{
|
|
// Vec3 scale = getDerivedScale();
|
|
for (auto&& iter : _emitters)
|
|
{
|
|
// if (!_emitter) return;
|
|
// auto emitter = static_cast<PUEmitter*>(_emitter);
|
|
auto emitter = iter;
|
|
// emitter->notifyRescaled(scale);
|
|
if (!iter->isMarkedForEmission())
|
|
{
|
|
unsigned short requested = emitter->calculateRequestedParticles(elapsedTime);
|
|
executeEmitParticles(emitter, requested, elapsedTime);
|
|
}
|
|
}
|
|
}
|
|
|
|
float PUParticleSystem3D::getDefaultWidth() const
|
|
{
|
|
return _defaultWidth;
|
|
}
|
|
|
|
void PUParticleSystem3D::setDefaultWidth(const float width)
|
|
{
|
|
_defaultWidth = width;
|
|
}
|
|
|
|
float PUParticleSystem3D::getDefaultHeight() const
|
|
{
|
|
return _defaultHeight;
|
|
}
|
|
|
|
void PUParticleSystem3D::setDefaultHeight(const float height)
|
|
{
|
|
_defaultHeight = height;
|
|
}
|
|
|
|
float PUParticleSystem3D::getDefaultDepth() const
|
|
{
|
|
return _defaultDepth;
|
|
}
|
|
|
|
void PUParticleSystem3D::setDefaultDepth(const float depth)
|
|
{
|
|
_defaultDepth = depth;
|
|
}
|
|
|
|
bool PUParticleSystem3D::isExpired(PUParticle3D* particle, float timeElapsed)
|
|
{
|
|
bool expired = particle->timeToLive < timeElapsed;
|
|
if (expired)
|
|
{
|
|
// Set the flag to indicate that the particle has been expired
|
|
particle->addEventFlags(PUParticle3D::PEF_EXPIRED);
|
|
}
|
|
|
|
return expired;
|
|
}
|
|
|
|
ax::Vec3 PUParticleSystem3D::getDerivedPosition()
|
|
{
|
|
// if (_parentParticleSystem && _parentParticleSystem->isKeepLocal()) return Vec3::ZERO;
|
|
// if (_keepLocal) return Vec3::ZERO;
|
|
if (_isMarkedForEmission)
|
|
{
|
|
return Vec3(_position.x, _position.y, _positionZ);
|
|
}
|
|
else
|
|
{
|
|
Mat4 mat = getNodeToWorldTransform();
|
|
return Vec3(mat.m[12], mat.m[13], mat.m[14]);
|
|
}
|
|
}
|
|
|
|
ax::Quaternion PUParticleSystem3D::getDerivedOrientation()
|
|
{
|
|
// if (_parentParticleSystem && _parentParticleSystem->isKeepLocal()) return Quaternion();
|
|
// if (_keepLocal) return Quaternion();
|
|
if (_isMarkedForEmission)
|
|
{
|
|
return getRotationQuat();
|
|
}
|
|
else
|
|
{
|
|
Quaternion q;
|
|
Mat4 mat = getNodeToWorldTransform();
|
|
mat.decompose(nullptr, &q, nullptr);
|
|
return q;
|
|
}
|
|
}
|
|
|
|
ax::Vec3 PUParticleSystem3D::getDerivedScale()
|
|
{
|
|
// if (_parentParticleSystem && _parentParticleSystem->isKeepLocal()) return Vec3::ONE;
|
|
// if (_keepLocal) return Vec3::ONE;
|
|
if (_isMarkedForEmission)
|
|
{
|
|
return Vec3(_scaleX, _scaleY, _scaleZ);
|
|
}
|
|
else
|
|
{
|
|
Vec3 s;
|
|
Mat4 mat = getNodeToWorldTransform();
|
|
mat.decompose(&s, nullptr, nullptr);
|
|
return s;
|
|
}
|
|
}
|
|
|
|
float PUParticleSystem3D::getMaxVelocity() const
|
|
{
|
|
return _maxVelocity;
|
|
}
|
|
|
|
void PUParticleSystem3D::setMaxVelocity(float maxVelocity)
|
|
{
|
|
_maxVelocity = maxVelocity;
|
|
_maxVelocitySet = true;
|
|
}
|
|
|
|
bool PUParticleSystem3D::initSystem(std::string_view filePath)
|
|
{
|
|
bool isFirstCompile = true;
|
|
auto list = PUScriptCompiler::Instance()->compile(filePath, isFirstCompile);
|
|
if (list == nullptr || list->empty())
|
|
return false;
|
|
PUTranslateManager::Instance()->translateParticleSystem(this, list);
|
|
// std::string data = FileUtils::getInstance()->getStringFromFile(filePath);
|
|
return true;
|
|
}
|
|
|
|
void PUParticleSystem3D::addEmitter(PUEmitter* emitter)
|
|
{
|
|
if (emitter && std::find(_emitters.begin(), _emitters.end(), emitter) == _emitters.end())
|
|
{
|
|
emitter->_particleSystem = this;
|
|
emitter->retain();
|
|
_emitters.emplace_back(emitter);
|
|
}
|
|
}
|
|
|
|
PUAffector* PUParticleSystem3D::getAffector(std::string_view name)
|
|
{
|
|
for (auto&& iter : _affectors)
|
|
{
|
|
auto pa = static_cast<PUAffector*>(iter);
|
|
if (pa->getName() == name)
|
|
return pa;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
PUEmitter* PUParticleSystem3D::getEmitter(std::string_view name)
|
|
{
|
|
for (auto&& iter : _emitters)
|
|
{
|
|
auto pe = static_cast<PUEmitter*>(iter);
|
|
if (pe->getName() == name)
|
|
return pe;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void PUParticleSystem3D::addListener(PUListener* listener)
|
|
{
|
|
auto iter = std::find(_listeners.begin(), _listeners.end(), listener);
|
|
if (iter == _listeners.end())
|
|
{
|
|
_listeners.emplace_back(listener);
|
|
}
|
|
}
|
|
|
|
void PUParticleSystem3D::removeListener(PUListener* listener)
|
|
{
|
|
auto iter = std::find(_listeners.begin(), _listeners.end(), listener);
|
|
if (iter != _listeners.end())
|
|
{
|
|
_listeners.erase(iter);
|
|
}
|
|
}
|
|
|
|
void PUParticleSystem3D::forceEmission(PUEmitter* emitter, unsigned requested)
|
|
{
|
|
// Fast rejection: Don't emit if the technique is not enabled
|
|
if (!_isEnabled)
|
|
return;
|
|
|
|
executeEmitParticles(emitter, requested, 0);
|
|
}
|
|
|
|
void PUParticleSystem3D::executeEmitParticles(PUEmitter* emitter, unsigned requested, float elapsedTime)
|
|
{
|
|
if (_state == State::STOP)
|
|
return;
|
|
if (emitter->getEmitsType() == PUParticle3D::PT_VISUAL)
|
|
{
|
|
emitParticles(_particlePool, emitter, requested, elapsedTime);
|
|
}
|
|
else if (emitter->getEmitsType() == PUParticle3D::PT_EMITTER)
|
|
{
|
|
emitParticles(_emittedEmitterParticlePool[emitter->getEmitsName()], emitter, requested, elapsedTime);
|
|
}
|
|
else if (emitter->getEmitsType() == PUParticle3D::PT_TECHNIQUE)
|
|
{
|
|
emitParticles(_emittedSystemParticlePool[emitter->getEmitsName()], emitter, requested, elapsedTime);
|
|
}
|
|
}
|
|
|
|
void PUParticleSystem3D::emitParticles(ParticlePool& pool, PUEmitter* emitter, unsigned requested, float elapsedTime)
|
|
{
|
|
Vec3 scale = getDerivedScale();
|
|
Mat4 rotMat;
|
|
Mat4::createRotation(getDerivedOrientation(), &rotMat);
|
|
float timePoint = 0.0f;
|
|
float timeInc = elapsedTime / requested;
|
|
for (unsigned short i = 0; i < requested; ++i)
|
|
{
|
|
PUParticle3D* particle = static_cast<PUParticle3D*>(pool.createData());
|
|
if (!particle)
|
|
return;
|
|
|
|
particle->initForEmission();
|
|
emitter->initParticleForEmission(particle);
|
|
|
|
particle->direction = (rotMat * Vec3(particle->direction.x, particle->direction.y, particle->direction.z));
|
|
particle->originalDirection = (rotMat * Vec3(particle->originalDirection.x, particle->originalDirection.y,
|
|
particle->originalDirection.z));
|
|
|
|
for (auto&& it : _affectors)
|
|
{
|
|
if (it->isEnabled())
|
|
{
|
|
(static_cast<PUAffector*>(it))->initParticleForEmission(particle);
|
|
}
|
|
}
|
|
|
|
initParticleForEmission(particle);
|
|
|
|
particle->position.add(particle->direction.x * scale.x * _particleSystemScaleVelocity * timePoint,
|
|
particle->direction.y * scale.y * _particleSystemScaleVelocity * timePoint,
|
|
particle->direction.z * scale.z * _particleSystemScaleVelocity * timePoint);
|
|
// Increment time fragment
|
|
timePoint += timeInc;
|
|
}
|
|
}
|
|
|
|
void PUParticleSystem3D::addObserver(PUObserver* observer)
|
|
{
|
|
auto iter = std::find(_observers.begin(), _observers.end(), observer);
|
|
if (iter == _observers.end())
|
|
{
|
|
observer->retain();
|
|
observer->_particleSystem = this;
|
|
_observers.emplace_back(observer);
|
|
}
|
|
}
|
|
|
|
PUObserver* PUParticleSystem3D::getObserver(std::string_view name)
|
|
{
|
|
for (auto&& iter : _observers)
|
|
{
|
|
auto po = static_cast<PUObserver*>(iter);
|
|
if (po->getName() == name)
|
|
return po;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void PUParticleSystem3D::notifyRescaled(const Vec3& scl)
|
|
{
|
|
if (_render)
|
|
_render->notifyRescaled(scl);
|
|
|
|
for (auto&& it : _emitters)
|
|
{
|
|
(static_cast<PUEmitter*>(it))->notifyRescaled(scl);
|
|
}
|
|
|
|
for (auto&& it : _affectors)
|
|
{
|
|
(static_cast<PUAffector*>(it))->notifyRescaled(scl);
|
|
}
|
|
|
|
for (auto&& it : _observers)
|
|
{
|
|
it->notifyRescaled(scl);
|
|
}
|
|
|
|
for (auto&& iter : _emittedEmitterParticlePool)
|
|
{
|
|
PUParticle3D* particle = static_cast<PUParticle3D*>(const_cast<ParticlePool&>(iter.second).getFirst());
|
|
while (particle)
|
|
{
|
|
static_cast<PUEmitter*>(particle->particleEntityPtr)->notifyRescaled(scl);
|
|
particle = static_cast<PUParticle3D*>(const_cast<ParticlePool&>(iter.second).getNext());
|
|
}
|
|
}
|
|
|
|
for (auto&& iter : _emittedSystemParticlePool)
|
|
{
|
|
PUParticle3D* particle = static_cast<PUParticle3D*>(const_cast<ParticlePool&>(iter.second).getFirst());
|
|
while (particle)
|
|
{
|
|
static_cast<PUParticleSystem3D*>(particle->particleEntityPtr)->notifyRescaled(scl);
|
|
particle = static_cast<PUParticle3D*>(const_cast<ParticlePool&>(iter.second).getNext());
|
|
}
|
|
}
|
|
}
|
|
|
|
void PUParticleSystem3D::initParticleForExpiration(PUParticle3D* particle, float timeElapsed)
|
|
{
|
|
if (particle->particleType == PUParticle3D::PT_EMITTER)
|
|
{
|
|
PUEmitter* emitter = static_cast<PUEmitter*>(particle->particleEntityPtr);
|
|
emitter->unPrepare();
|
|
}
|
|
else if (particle->particleType == PUParticle3D::PT_TECHNIQUE)
|
|
{
|
|
PUParticleSystem3D* system = static_cast<PUParticleSystem3D*>(particle->particleEntityPtr);
|
|
system->unPrepared();
|
|
}
|
|
|
|
particle->initForExpiration(timeElapsed);
|
|
|
|
for (auto&& it : _listeners)
|
|
{
|
|
it->particleExpired(this, particle);
|
|
}
|
|
///** Externs are also called to perform expiration activities. If needed, affectors and emitters may be added, but
|
|
/// at the moment
|
|
// there is no reason for (and we don't want to waste cpu resources).
|
|
//*/
|
|
// if (!mExterns.empty())
|
|
//{
|
|
// ExternIterator itExtern;
|
|
// ExternIterator itExternEnd = mExterns.end();
|
|
// for (itExtern = mExterns.begin(); itExtern != itExternEnd; ++itExtern)
|
|
// {
|
|
// (*itExtern)->_initParticleForExpiration(particle);
|
|
// }
|
|
//}
|
|
}
|
|
|
|
void PUParticleSystem3D::initParticleForEmission(PUParticle3D* particle)
|
|
{
|
|
for (auto&& it : _listeners)
|
|
{
|
|
it->particleEmitted(this, particle);
|
|
}
|
|
}
|
|
|
|
void PUParticleSystem3D::addBehaviourTemplate(PUBehaviour* behaviour)
|
|
{
|
|
auto iter = std::find(_behaviourTemplates.begin(), _behaviourTemplates.end(), behaviour);
|
|
if (iter == _behaviourTemplates.end())
|
|
{
|
|
behaviour->retain();
|
|
behaviour->_particleSystem = this;
|
|
_behaviourTemplates.emplace_back(behaviour);
|
|
}
|
|
}
|
|
|
|
void PUParticleSystem3D::convertToUnixStylePath(std::string& path)
|
|
{
|
|
#if (AX_TARGET_PLATFORM == AX_PLATFORM_WIN32)
|
|
for (auto&& iter : path)
|
|
{
|
|
if (iter == '\\')
|
|
iter = '/';
|
|
}
|
|
#else
|
|
AX_UNUSED_PARAM(path);
|
|
#endif
|
|
}
|
|
|
|
void PUParticleSystem3D::clearAllParticles()
|
|
{
|
|
_particlePool.lockAllDatas();
|
|
for (auto&& iter : _emittedEmitterParticlePool)
|
|
{
|
|
const_cast<ParticlePool&>(iter.second).lockAllDatas();
|
|
}
|
|
|
|
for (auto&& iter : _emittedSystemParticlePool)
|
|
{
|
|
const_cast<ParticlePool&>(iter.second).lockAllDatas();
|
|
}
|
|
}
|
|
|
|
void PUParticleSystem3D::copyAttributesTo(PUParticleSystem3D* system)
|
|
{
|
|
system->removeAllEmitter();
|
|
system->removeAllAffector();
|
|
system->removerAllObserver();
|
|
system->removeAllBehaviourTemplate();
|
|
system->removeAllListener();
|
|
system->_particlePool.removeAllDatas();
|
|
for (auto&& iter : system->_emittedEmitterParticlePool)
|
|
{
|
|
iter.second.removeAllDatas();
|
|
}
|
|
|
|
for (auto&& iter : system->_emittedSystemParticlePool)
|
|
{
|
|
iter.second.removeAllDatas();
|
|
}
|
|
|
|
system->setName(_name);
|
|
system->_state = _state;
|
|
if (_render)
|
|
system->setRender(static_cast<PURender*>(_render)->clone());
|
|
system->_particleQuota = _particleQuota;
|
|
system->_blend = _blend;
|
|
system->_keepLocal = _keepLocal;
|
|
system->_isEnabled = _isEnabled;
|
|
|
|
for (auto&& iter : _affectors)
|
|
{
|
|
PUAffector* affector = static_cast<PUAffector*>(iter);
|
|
PUAffector* copy = PUAffectorManager::Instance()->createAffector(affector->getAffectorType());
|
|
affector->copyAttributesTo(copy);
|
|
system->addAffector(copy);
|
|
}
|
|
|
|
for (auto&& iter : _emitters)
|
|
{
|
|
PUEmitter* emitter = static_cast<PUEmitter*>(iter);
|
|
PUEmitter* copy = PUEmitterManager::Instance()->createEmitter(emitter->getEmitterType());
|
|
emitter->copyAttributesTo(copy);
|
|
system->addEmitter(copy);
|
|
}
|
|
|
|
for (auto&& iter : _observers)
|
|
{
|
|
PUObserver* observer = static_cast<PUObserver*>(iter);
|
|
PUObserver* copy = PUObserverManager::Instance()->createObserver(observer->getObserverType());
|
|
observer->copyAttributesTo(copy);
|
|
system->addObserver(copy);
|
|
}
|
|
|
|
for (auto&& iter : _behaviourTemplates)
|
|
{
|
|
PUBehaviour* behaviour = static_cast<PUBehaviour*>(iter);
|
|
PUBehaviour* copy = behaviour->clone();
|
|
system->addBehaviourTemplate(copy);
|
|
}
|
|
|
|
system->_emittedEmitterQuota = _emittedEmitterQuota;
|
|
system->_emittedSystemQuota = _emittedSystemQuota;
|
|
system->_prepared = false;
|
|
system->_particleSystemScaleVelocity = _particleSystemScaleVelocity;
|
|
system->_defaultWidth = _defaultWidth;
|
|
system->_defaultHeight = _defaultHeight;
|
|
system->_defaultDepth = _defaultDepth;
|
|
system->_maxVelocity = _maxVelocity;
|
|
system->_maxVelocitySet = _maxVelocitySet;
|
|
system->_matName = _matName;
|
|
system->_isMarkedForEmission = _isMarkedForEmission;
|
|
system->_parentParticleSystem = _parentParticleSystem;
|
|
}
|
|
|
|
PUParticleSystem3D* PUParticleSystem3D::clone()
|
|
{
|
|
auto ps = PUParticleSystem3D::create();
|
|
copyAttributesTo(ps);
|
|
for (auto&& iter : _children)
|
|
{
|
|
PUParticleSystem3D* child = dynamic_cast<PUParticleSystem3D*>(iter);
|
|
if (child)
|
|
ps->addChild(child->clone());
|
|
}
|
|
return ps;
|
|
}
|
|
|
|
void PUParticleSystem3D::removeAllEmitter()
|
|
{
|
|
for (auto&& iter : _emitters)
|
|
{
|
|
iter->release();
|
|
}
|
|
_emitters.clear();
|
|
}
|
|
|
|
void PUParticleSystem3D::removerAllObserver()
|
|
{
|
|
for (auto&& iter : _observers)
|
|
{
|
|
iter->release();
|
|
}
|
|
_observers.clear();
|
|
}
|
|
|
|
void PUParticleSystem3D::removeAllBehaviourTemplate()
|
|
{
|
|
for (auto&& iter : _behaviourTemplates)
|
|
{
|
|
iter->release();
|
|
}
|
|
_behaviourTemplates.clear();
|
|
}
|
|
|
|
void PUParticleSystem3D::removeAllListener()
|
|
{
|
|
_listeners.clear();
|
|
}
|
|
|
|
void PUParticleSystem3D::draw(Renderer* renderer, const Mat4& transform, uint32_t flags)
|
|
{
|
|
if (!_isEnabled)
|
|
return;
|
|
if (getAliveParticleCount() <= 0)
|
|
return;
|
|
if (_render)
|
|
_render->render(renderer, transform, this);
|
|
|
|
if (!_emittedSystemParticlePool.empty())
|
|
{
|
|
for (auto&& iter : _emittedSystemParticlePool)
|
|
{
|
|
PUParticle3D* particle = static_cast<PUParticle3D*>(const_cast<ParticlePool&>(iter.second).getFirst());
|
|
while (particle)
|
|
{
|
|
static_cast<PUParticleSystem3D*>(particle->particleEntityPtr)->draw(renderer, transform, flags);
|
|
particle = static_cast<PUParticle3D*>(const_cast<ParticlePool&>(iter.second).getNext());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void PUParticleSystem3D::processParticle(ParticlePool& pool,
|
|
bool& firstActiveParticle,
|
|
bool& firstParticle,
|
|
float elapsedTime)
|
|
{
|
|
Vec3 scale = getDerivedScale();
|
|
PUParticle3D* particle = static_cast<PUParticle3D*>(pool.getFirst());
|
|
// Mat4 ltow = getNodeToWorldTransform();
|
|
// Vec3 scl;
|
|
// Quaternion rot;
|
|
// ltow.decompose(&scl, &rot, nullptr);
|
|
while (particle)
|
|
{
|
|
|
|
if (!isExpired(particle, elapsedTime))
|
|
{
|
|
particle->process(elapsedTime);
|
|
|
|
// if (_emitter && _emitter->isEnabled())
|
|
// _emitter->updateEmitter(particle, elapsedTime);
|
|
|
|
for (auto&& it : _emitters)
|
|
{
|
|
if (it->isEnabled() && !it->isMarkedForEmission())
|
|
{
|
|
(static_cast<PUEmitter*>(it))->updateEmitter(particle, elapsedTime);
|
|
}
|
|
}
|
|
|
|
for (auto&& it : _affectors)
|
|
{
|
|
if (it->isEnabled())
|
|
{
|
|
(static_cast<PUAffector*>(it))->process(particle, elapsedTime, firstActiveParticle);
|
|
}
|
|
}
|
|
|
|
if (_render)
|
|
static_cast<PURender*>(_render)->updateRender(particle, elapsedTime, firstActiveParticle);
|
|
|
|
if (_isEnabled && particle->particleType != PUParticle3D::PT_VISUAL)
|
|
{
|
|
if (particle->particleType == PUParticle3D::PT_EMITTER)
|
|
{
|
|
auto emitter = static_cast<PUEmitter*>(particle->particleEntityPtr);
|
|
emitter->setLocalPosition(particle->position);
|
|
executeEmitParticles(emitter, emitter->calculateRequestedParticles(elapsedTime), elapsedTime);
|
|
}
|
|
else if (particle->particleType == PUParticle3D::PT_TECHNIQUE)
|
|
{
|
|
auto system = static_cast<PUParticleSystem3D*>(particle->particleEntityPtr);
|
|
system->setPosition3D(particle->position);
|
|
system->setRotationQuat(particle->orientation);
|
|
// system->setScaleX(scl.x);system->setScaleY(scl.y);system->setScaleZ(scl.z);
|
|
system->forceUpdate(elapsedTime);
|
|
}
|
|
}
|
|
|
|
firstActiveParticle = false;
|
|
// Keep latest position
|
|
particle->latestPosition = particle->position;
|
|
|
|
// if (_maxVelocitySet && particle->calculateVelocity() > _maxVelocity)
|
|
//{
|
|
// particle->direction *= (_maxVelocity / particle->direction.length());
|
|
// }
|
|
|
|
//// Update the position with the direction.
|
|
// particle->position += (particle->direction * _particleSystemScaleVelocity * elapsedTime);
|
|
// particle->positionInWorld = particle->position;
|
|
// particle->orientationInWorld = particle->orientation;
|
|
// particle->widthInWorld = particle->width;
|
|
// particle->heightInWorld = particle->height;
|
|
// particle->depthInWorld = particle->depth;
|
|
|
|
// bool keepLocal = _keepLocal;
|
|
// PUParticleSystem3D *parent = dynamic_cast<PUParticleSystem3D *>(getParent());
|
|
// if (parent) keepLocal = keepLocal || parent->isKeepLocal();
|
|
|
|
// if (keepLocal){
|
|
// ltow.transformPoint(particle->positionInWorld, &particle->positionInWorld);
|
|
// Vec3 ori;
|
|
// ltow.transformVector(Vec3(particle->orientation.x, particle->orientation.y, particle->orientation.z),
|
|
// &ori); particle->orientationInWorld.x = ori.x; particle->orientationInWorld.y = ori.y;
|
|
// particle->orientationInWorld.z = ori.z; particle->widthInWorld = scl.x * particle->width;
|
|
// particle->heightInWorld = scl.y * particle->height;
|
|
// particle->depthInWorld = scl.z * particle->depth;
|
|
// }
|
|
processMotion(particle, elapsedTime, scale, firstActiveParticle);
|
|
}
|
|
else
|
|
{
|
|
initParticleForExpiration(particle, elapsedTime);
|
|
pool.lockLatestData();
|
|
}
|
|
|
|
for (auto&& it : _observers)
|
|
{
|
|
if (it->isEnabled())
|
|
{
|
|
it->updateObserver(particle, elapsedTime, firstParticle);
|
|
}
|
|
}
|
|
|
|
if (particle->hasEventFlags(PUParticle3D::PEF_EXPIRED))
|
|
{
|
|
particle->setEventFlags(0);
|
|
particle->addEventFlags(PUParticle3D::PEF_EXPIRED);
|
|
}
|
|
else
|
|
{
|
|
particle->setEventFlags(0);
|
|
}
|
|
|
|
particle->timeToLive -= elapsedTime;
|
|
firstParticle = false;
|
|
particle = static_cast<PUParticle3D*>(pool.getNext());
|
|
}
|
|
}
|
|
|
|
bool PUParticleSystem3D::makeParticleLocal(PUParticle3D* particle)
|
|
{
|
|
if (!particle)
|
|
return true;
|
|
|
|
if (!_keepLocal)
|
|
return false;
|
|
|
|
particle->position += _latestPositionDiff;
|
|
return true;
|
|
}
|
|
|
|
void PUParticleSystem3D::processMotion(PUParticle3D* particle,
|
|
float timeElapsed,
|
|
const Vec3& scl,
|
|
bool /*firstParticle*/)
|
|
{
|
|
if (particle->isFreezed())
|
|
return;
|
|
|
|
/** Because everything is calculated in worldspace we recalculate it back to the techniques' origin (the result is
|
|
still worldspace) just by adding a relative offset of the particle system, technique, emitter or visual particle.
|
|
Change in V1.4:
|
|
The additional PEF_EMITTED check fixes the problem with scenenodese moving forward at extremely fast speeds
|
|
The bug is due to how PU code processes keep_local, and the calculation shouldn't be applied to newly emitted
|
|
particles.
|
|
*/
|
|
if (!particle->hasEventFlags(PUParticle3D::PEF_EMITTED))
|
|
{
|
|
if (!particle->parentEmitter->makeParticleLocal(particle))
|
|
{
|
|
if (!makeParticleLocal(particle))
|
|
{
|
|
_parentParticleSystem->makeParticleLocal(particle);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Adjust position of the particle if the parent has rotated (only in case of particle system with 'keep local').
|
|
PU 1.4: Added check that technique may not be local, otherwise particles are rotated twice as fast.
|
|
*/
|
|
if (_parentParticleSystem->isKeepLocal() && !_keepLocal)
|
|
{
|
|
/** Ignore some rendersystems, because they are rotated by Ogre itself.
|
|
Entities for example are always rotated (even if not local), based on the node orientation. A Billboard not.
|
|
*/
|
|
if (_render && !static_cast<PURender*>(_render)->autoRotate)
|
|
{
|
|
_parentParticleSystem->rotationOffset(particle->position);
|
|
}
|
|
}
|
|
|
|
// Added for 1.3
|
|
if (particle->hasEventFlags(PUParticle3D::PEF_EMITTED))
|
|
return;
|
|
|
|
// Adjust the velocity to the allowed maximum.
|
|
if (_maxVelocitySet && particle->calculateVelocity() > _maxVelocity)
|
|
{
|
|
particle->direction *= (_maxVelocity / particle->direction.length());
|
|
}
|
|
|
|
// Update the position with the direction.
|
|
particle->position.add(particle->direction.x * scl.x * _particleSystemScaleVelocity * timeElapsed,
|
|
particle->direction.y * scl.y * _particleSystemScaleVelocity * timeElapsed,
|
|
particle->direction.z * scl.z * _particleSystemScaleVelocity * timeElapsed);
|
|
}
|
|
|
|
void PUParticleSystem3D::calulateRotationOffset(void)
|
|
{
|
|
if (_isMarkedForEmission)
|
|
{
|
|
// Use the uber particle system as centre of rotation and not the particle systems' own position.
|
|
_rotationCentre = _parentParticleSystem->getDerivedPosition();
|
|
}
|
|
else
|
|
{
|
|
// Use its own position
|
|
_rotationCentre = getDerivedPosition();
|
|
}
|
|
|
|
/** Use the derived orientation, which is the particle systems' own scenenode orientation,
|
|
or the orientation of the uber particle system, if this particle system is emitted itself.
|
|
*/
|
|
Quaternion latestOrientationInverse = _latestOrientation;
|
|
latestOrientationInverse.inverse();
|
|
_rotationOffset = getDerivedOrientation() * latestOrientationInverse;
|
|
}
|
|
|
|
int PUParticleSystem3D::getAliveParticleCount() const
|
|
{
|
|
int sz = 0;
|
|
sz += _particlePool.getActiveDataList().size();
|
|
|
|
if (!_emittedEmitterParticlePool.empty())
|
|
{
|
|
for (auto&& iter : _emittedEmitterParticlePool)
|
|
{
|
|
sz += iter.second.getActiveDataList().size();
|
|
}
|
|
}
|
|
|
|
if (_emittedSystemParticlePool.empty())
|
|
return sz;
|
|
|
|
for (auto&& iter : _emittedSystemParticlePool)
|
|
{
|
|
auto pool = iter.second;
|
|
sz += pool.getActiveDataList().size();
|
|
PUParticle3D* particle = static_cast<PUParticle3D*>(pool.getFirst());
|
|
while (particle)
|
|
{
|
|
sz += static_cast<PUParticleSystem3D*>(particle->particleEntityPtr)->getAliveParticleCount();
|
|
particle = static_cast<PUParticle3D*>(pool.getNext());
|
|
}
|
|
}
|
|
return sz;
|
|
}
|
|
|
|
void PUParticleSystem3D::forceStopParticleSystem()
|
|
{
|
|
if (_render)
|
|
_render->notifyStop();
|
|
|
|
for (auto&& it : _observers)
|
|
{
|
|
it->notifyStop();
|
|
}
|
|
|
|
for (auto&& it : _emitters)
|
|
{
|
|
auto emitter = static_cast<PUEmitter*>(it);
|
|
emitter->notifyStop();
|
|
}
|
|
|
|
for (auto&& it : _affectors)
|
|
{
|
|
auto affector = static_cast<PUAffector*>(it);
|
|
affector->notifyStop();
|
|
}
|
|
unscheduleUpdate();
|
|
unPrepared();
|
|
}
|
|
|
|
NS_AX_END
|