// // RParticleSystem.cpp // cocos2d_libs // // Created by 徐俊杰 on 2020/4/25. // #include "rparticle/RParticleSystem.h" #include "rparticle/Utilities/Transform.h" #include "rparticle/ParticleSystemRenderer.h" #include "rparticle/Modules/CollisionModule.h" #include "rparticle/Modules/RotationModule.h" #include "rparticle/Modules/RotationByVelocityModule.h" #include "rparticle/Modules/SubModule.h" #include "rparticle/Modules/SubEmitterModule.h" #include "rparticle/Modules/ExternalForcesModule.h" #include "rparticle/Modules/EmissionModule.h" #include "rparticle/Modules/ForceModule.h" #include "rparticle/Modules/VelocityModule.h" #include "rparticle/Modules/ClampVelocityModule.h" #include "rparticle/Modules/SizeModule.h" #include "rparticle/Modules/ColorModule.h" #include "rparticle/Modules/UVModule.h" #include "rparticle/Modules/SizeByVelocityModule.h" #include "rparticle/Modules/ColorByVelocityModule.h" #include "rparticle/Modules/CollisionModule.h" #include "rparticle/Macros/RParticleGlobalStuff.h" #include "rparticle/Serialize/TransferFunctions/JsonRead.h" #include "platform/CCFileUtils.h" #include "base/ccUTF8.h" #include "rparticle/Math/Gradient.h" #include "renderer/CCRenderer.h" #include "renderer/CCGLProgramState.h" #include "renderer/ccGLStateCache.h" #include "rparticle/Serialize/TransferFunctions/SerializeTransfer.h" #include "2d/CCSpriteFrame.h" #include "2d/CCSpriteFrameCache.h" #if REDREAM_EDITOR #include "2d/CCDrawNode3D.h" #endif using namespace cocos2d; NS_RRP_BEGIN struct ParticleSystemManager { ParticleSystemManager() :needSync(false) { activeEmitters.reserve(32); Director::getInstance()->getScheduler()->schedule([](float dt) { RParticleSystem::BeginUpdateAll(); RParticleSystem::EndUpdateAll(); }, this, 0, false, "ParticleSystemManager_update"); } dynamic_array activeEmitters; bool needSync; }; ParticleSystemManager gParticleSystemManager; #define MAX_TIME_STEP (0.03f) static float GetTimeStep(float dt, bool fixedTimeStep) { if(fixedTimeStep){ return Director::getInstance()->getDeltaTime(); } else if(dt > MAX_TIME_STEP){ return dt / Ceilf(dt / MAX_TIME_STEP); } else return dt; } static void ApplyStartDelay (float& delayT, float& accumulatedDt) { if(delayT > 0.0f) { delayT -= accumulatedDt; accumulatedDt = MAX(-delayT, 0.0f); delayT = MAX(delayT, 0.0f); } DebugAssert(delayT >= 0.0f); } RParticleSystem* RParticleSystem::create() { RParticleSystem * ret = new (std::nothrow) RParticleSystem(); if (ret && ret->init()) { ret->autorelease(); } else { CC_SAFE_DELETE(ret); } return ret; } RParticleSystem::RParticleSystem() : _useMaterialFile(false) , _quads(nullptr) , _quadCount(0) , _opacityModifyRGB(false) { m_EmittersIndex = -1; m_State = new ParticleSystemState (this); m_ReadOnlyState = new ParticleSystemReadOnlyState (); m_SizeModule = new SizeModule (); m_RotationModule = new RotationModule (); m_ColorModule = new ColorModule (); m_UVModule = new UVModule (); m_VelocityModule = new VelocityModule (); m_ForceModule = new ForceModule (); m_ExternalForcesModule = new ExternalForcesModule (); m_ClampVelocityModule = new ClampVelocityModule (); m_SizeBySpeedModule = new SizeBySpeedModule (); m_RotationBySpeedModule = new RotationBySpeedModule (); m_ColorBySpeedModule = new ColorBySpeedModule(); m_CollisionModule = new CollisionModule (); m_SubModule = new SubModule (); m_SubEmitterModule = new SubEmitterModule (); m_renderer = new ParticleSystemRenderer(); } RParticleSystem::~RParticleSystem() { delete m_State; delete m_ReadOnlyState; delete m_SizeModule; delete m_RotationModule; delete m_ColorModule; delete m_UVModule; delete m_VelocityModule; delete m_ForceModule; delete m_ExternalForcesModule; delete m_ClampVelocityModule; delete m_SizeBySpeedModule; delete m_RotationBySpeedModule; delete m_ColorBySpeedModule; delete m_CollisionModule; delete m_SubModule; delete m_SubEmitterModule; delete m_renderer; CC_SAFE_FREE(_quads); } float RParticleSystem::GetLengthInSec () const { Assert (m_State); return m_ReadOnlyState->lengthInSec; } bool RParticleSystem::CheckSupportsProcedural(const RParticleSystem& system) { ParticleSystemRenderer* renderer = (ParticleSystemRenderer*)const_cast(system).getComponent(COMPONENT_PS_RENDERER); if(renderer && (renderer->GetRenderMode() == kSRMStretch3D)) return false; return system.m_State->supportsProcedural && !system.m_State->invalidateProcedural; } void RParticleSystem::Stop () { Assert (m_State); m_State->needRestart = true; m_State->stopEmitting = true; } bool RParticleSystem::init() { if (!Node::init()) return false; m_renderer->Reset(); return true; } void RParticleSystem::AwakeFromLoad() { m_InitialModule.AwakeFromLoad(this, *m_ReadOnlyState); m_ShapeModule.AwakeFromLoad(this, *m_ReadOnlyState); // if (!isVisible() () || (kDefaultAwakeFromLoad == awakeMode)) if (!IsActive()) return; // m_State->localToWorld = GetComponent (Transform).GetLocalToWorldMatrixNoScale(); m_State->localToWorld = Transform::GetLocalToWorldMatrixNoScale(this); Matrix4x4f::Invert_General3D(m_State->localToWorld, m_State->worldToLocal); m_State->maxSize = 0.0f; m_State->invalidateProcedural = false; // if (IsWorldPlaying () && m_ReadOnlyState->playOnAwake) if (m_ReadOnlyState->playOnAwake) Play (); // Does this even happen? if(GetParticleCount() || IsPlaying()) AddToManager(); } RParticleSystem* RParticleSystem::FindGroupRoot() { auto root = this; while (RParticleSystem *p = dynamic_cast(root->getParent())) { root = p; } return root; } void RParticleSystem::AwakeFromLoadTree() { if (!isVisible()) { return; } AwakeFromLoad(); for (auto child : getChildren()) { auto childParticle = dynamic_cast(child); if (childParticle) { childParticle->AwakeFromLoad(); } } } void RParticleSystem::PlayTree() { Play(); for (auto child : getChildren()) { auto childParticle = dynamic_cast(child); if (childParticle) { childParticle->PlayTree(); } } } void RParticleSystem::StopTree() { Stop(); for (auto child : getChildren()) { auto childParticle = dynamic_cast(child); if (childParticle) { childParticle->StopTree(); } } } void RParticleSystem::ClearTree() { Clear(); for (auto child : getChildren()) { auto childParticle = dynamic_cast(child); if (childParticle) { childParticle->ClearTree(); } } } void RParticleSystem::StopAndClearTree() { Stop(); Clear(); for (auto child : getChildren()) { auto childParticle = dynamic_cast(child); if (childParticle) { childParticle->StopAndClearTree(); } } } //void RParticleSystem::WalkTree(std::function func) //{ // func(this); // for (auto child : getChildren()) { // auto childParticle = dynamic_cast(child); // if (childParticle) { // childParticle->WalkTree(func); // } // } //} void RParticleSystem::BeginUpdateAll(){ //cocos2dx update 传进来一个dt 赋值deltaTime float deltaTime = Director::getInstance()->getDeltaTime(); // 活跃状态监测 for(int i = 0; i < gParticleSystemManager.activeEmitters.size(); i++) { RParticleSystem& system = *gParticleSystemManager.activeEmitters[i]; if (!system.IsActive ()) { //AssertStringObject( "UpdateParticle system should not happen on disabled vGO", &system); system.RemoveFromManager(); continue; } #if ENABLE_MULTITHREADED_PARTICLES system.m_State->recordSubEmits = true; #else system.m_State->recordSubEmits = false; #endif // 更新部分粒子属性,子发射器属性 Update0 (system, *system.m_ReadOnlyState, *system.m_State, deltaTime, false); } gParticleSystemManager.needSync = true; // make sure ray budgets are assigned for the frame // 将光线预算分配给将进行光线投射的每个系统 //ParticleSystem::AssignRayBudgets(); #if ENABLE_MULTITHREADED_PARTICLES //多线程先留白 #else for(int i = 0; i < gParticleSystemManager.activeEmitters.size(); i++) { //printf_console("BeginUpdateAll [%d]:\n",i); RParticleSystem& system = *gParticleSystemManager.activeEmitters[i]; // 发射粒子等 system.Update1 (system, system.GetParticles((int)RParticleSystem::kParticleBuffer0), deltaTime, false, false); } #endif } void RParticleSystem::SyncJobs() { if(gParticleSystemManager.needSync) { #if ENABLE_MULTITHREADED_PARTICLES #endif const float deltaTimeEpsilon = 0.0001f; //TODO ? 需要传进来一个时间 float deltaTime = Director::getInstance()->getDeltaTime(); if(deltaTime < deltaTimeEpsilon) return; for(int i = 0; i < gParticleSystemManager.activeEmitters.size(); ++i) { RParticleSystem& system = *gParticleSystemManager.activeEmitters[i]; ParticleSystemState& state = *system.m_State; system.Update2 (system, *system.m_ReadOnlyState, state, false); } gParticleSystemManager.needSync = false; } } void RParticleSystem::EndUpdateAll(){ SyncJobs(); // messages // 发送事件 for (int i = 0; i < gParticleSystemManager.activeEmitters.size(); ++i) { RParticleSystem& system = *gParticleSystemManager.activeEmitters[i]; if (!system.IsActive ()) continue; // if (!system.m_CollisionModule->GetUsesCollisionMessages ()) // continue; ParticleSystemParticles& ps = system.GetParticles((int)RParticleSystem::kParticleBuffer0); //TODO ??物理碰撞暂缺 //ps.collisionEvents.SwapCollisionEventArrays (); //ps.collisionEvents.SendCollisionEvents (system); } // Remove emitters that are finished (no longer emitting) // 清理粒子 for(int i = 0; i < gParticleSystemManager.activeEmitters.size();) { RParticleSystem& system = *gParticleSystemManager.activeEmitters[i]; ParticleSystemState& state = *system.m_State; const size_t particleCount = system.GetParticleCount(); if ((particleCount == 0) && state.playing && state.stopEmitting) { // collision subemitters may not have needRestart==true when being restarted // from a paused state //Assert (state.needRestart); state.playing = false; system.RemoveFromManager(); continue; } i++; } } void RParticleSystem::AddToManager() { // 不可重复加入 if(m_EmittersIndex >= 0) return; size_t index = gParticleSystemManager.activeEmitters.size(); gParticleSystemManager.activeEmitters.push_back(this); m_EmittersIndex = (int)index; } void RParticleSystem::RemoveFromManager() { if(m_EmittersIndex < 0) return; const int index = m_EmittersIndex; gParticleSystemManager.activeEmitters[index]->m_EmittersIndex = -1; gParticleSystemManager.activeEmitters[index] = gParticleSystemManager.activeEmitters.back(); if(gParticleSystemManager.activeEmitters[index] != this) // corner case gParticleSystemManager.activeEmitters[index]->m_EmittersIndex = index; gParticleSystemManager.activeEmitters.resize_uninitialized(gParticleSystemManager.activeEmitters.size() - 1); } ParticleSystemParticles& RParticleSystem::GetParticles (int index) { return m_Particles[kParticleBuffer0]; } size_t RParticleSystem::GetParticleCount () const { return m_Particles[kParticleBuffer0].array_size(); } void RParticleSystem::AddStagingBuffer(RParticleSystem& system) { if(0 == system.m_ParticlesStaging.array_size()) return; bool needsAxisOfRotation = system.m_Particles[kParticleBuffer0].usesAxisOfRotation; bool needsEmitAccumulator = system.m_Particles[kParticleBuffer0].numEmitAccumulators > 0; //ASSERT_RUNNING_ON_MAIN_THREAD; const int numParticles = (int)system.m_Particles[kParticleBuffer0].array_size(); const int numStaging = (int)system.m_ParticlesStaging.array_size(); system.m_Particles->array_resize(numParticles + numStaging); system.m_Particles->array_merge_preallocated(system.m_ParticlesStaging, numParticles, needsAxisOfRotation, needsEmitAccumulator); system.m_ParticlesStaging.array_resize(0); } void RParticleSystem::SetUsesRotationalSpeed() { ParticleSystemParticles& ps0 = m_Particles[kParticleBuffer0]; if(!ps0.usesRotationalSpeed) ps0.SetUsesRotationalSpeed (); ParticleSystemParticles& pss = m_ParticlesStaging; if(!pss.usesRotationalSpeed) pss.SetUsesRotationalSpeed (); } void RParticleSystem::SetUsesEmitAccumulator(int numAccumulators) { m_Particles[kParticleBuffer0].SetUsesEmitAccumulator (numAccumulators); m_ParticlesStaging.SetUsesEmitAccumulator (numAccumulators); } // pointRect should be in Texture coordinates, not pixel coordinates void RParticleSystem::initTexCoordsWithRect(const Rect& pointRect, bool isRotaed, const Vec2& offset, const Vec2& originalSize) { _vertexInfo = RRP_PARTICLEQUAD_VERTEX_INFO::Create(_texture, pointRect, isRotaed, offset, originalSize); } void RParticleSystem::setTextureInternal(cocos2d::Texture2D* texture) { if (_texture != texture) { _texture = texture; if(_texture && _glProgramState == nullptr) { setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP, texture)); } updateBlendFunc(); m_UVModule->SetFrameDirty(); } } void RParticleSystem::setTextureWithRect(Texture2D *texture, const Rect& rect, bool isRotaed, const Vec2& offset, const Vec2& originalSize) { if( !_texture || texture->getName() != _texture->getName() ) { setTextureInternal(texture); } if (_useMaterialFile) return; _isSpriteFrame = (isRotaed || !rect.origin.isZero() || !offset.isZero() || !CompareApproximately(originalSize.x, originalSize.y) || !(CompareApproximately(rect.size.width, originalSize.x) && CompareApproximately(rect.size.height, originalSize.y)) ); this->initTexCoordsWithRect(rect, isRotaed, offset, originalSize); } bool RParticleSystem::GetLoop () const { Assert (m_State); return m_ReadOnlyState->looping; } int RParticleSystem::SetupSubEmitters(RParticleSystem& shuriken, ParticleSystemState& state) { Assert(!state.cachedSubDataBirth && !state.numCachedSubDataBirth); Assert(!state.cachedSubDataCollision && !state.numCachedSubDataCollision); Assert(!state.cachedSubDataDeath && !state.numCachedSubDataDeath); int subEmitterCount = 0; std::vector subEmittersBirth; std::vector subEmittersCollision; std::vector subEmittersDeath; shuriken.m_SubModule->SetEnabled(false); auto children = shuriken.getChildren(); for (auto child : children) { if (!child->isVisible()) continue; auto childEmitter = dynamic_cast(child); if (childEmitter != nullptr && childEmitter->m_SubEmitterModule->GetEnabled()) { shuriken.m_SubModule->SetEnabled(true); switch (childEmitter->m_SubEmitterModule->GetSubEmitterType()) { case kParticleSystemSubTypeBirth: subEmittersBirth.push_back(childEmitter); break; case kParticleSystemSubTypeCollision: subEmittersCollision.push_back(childEmitter); break; case kParticleSystemSubTypeDeath: subEmittersDeath.push_back(childEmitter); break; } } } if(shuriken.m_SubModule->GetEnabled()) { //RParticleSystem* subEmittersBirth[kParticleSystemMaxSubBirth]; //state.numCachedSubDataBirth = shuriken.m_SubModule->GetSubEmitterPtrsBirth(&subEmittersBirth[0]); state.numCachedSubDataBirth = subEmittersBirth.size(); state.cachedSubDataBirth = ALLOC_TEMP_MANUAL(ParticleSystemSubEmitterData, state.numCachedSubDataBirth); std::uninitialized_fill (state.cachedSubDataBirth, state.cachedSubDataBirth + state.numCachedSubDataBirth, ParticleSystemSubEmitterData()); for(int i = 0; i < state.numCachedSubDataBirth; i++) { RParticleSystem* subEmitter = subEmittersBirth[i]; ParticleSystemSubEmitterData& subData = state.cachedSubDataBirth[i]; subData.startDelayInSec = subEmitter->m_ReadOnlyState->startDelay; subData.lengthInSec = subEmitter->GetLoop() ? std::numeric_limits::max() : subEmitter->GetLengthInSec(); subData.maxLifetime = subEmitter->m_InitialModule.GetLifeTimeCurve().GetScalar(); subData.properties = subEmitter->m_SubEmitterModule->GetProperties(); subData.emitter = subEmitter; subEmitter->m_EmissionModule.GetEmissionDataCopy(&subData.emissionData); subEmitter->m_State->SetIsSubEmitter(true); subEmitterCount++; } //RParticleSystem* subEmittersCollision[kParticleSystemMaxSubCollision]; //state.numCachedSubDataCollision = shuriken.m_SubModule->GetSubEmitterPtrsCollision(&subEmittersCollision[0]); state.numCachedSubDataCollision = subEmittersCollision.size(); state.cachedSubDataCollision = ALLOC_TEMP_MANUAL(ParticleSystemSubEmitterData, state.numCachedSubDataCollision); std::uninitialized_fill (state.cachedSubDataCollision, state.cachedSubDataCollision + state.numCachedSubDataCollision, ParticleSystemSubEmitterData()); for(int i = 0; i < state.numCachedSubDataCollision; i++) { RParticleSystem* subEmitter = subEmittersCollision[i]; ParticleSystemSubEmitterData& subData = state.cachedSubDataCollision[i]; subData.properties = subEmitter->m_SubEmitterModule->GetProperties(); subData.emitter = subEmitter; subEmitter->m_EmissionModule.GetEmissionDataCopy(&subData.emissionData); subEmitter->m_State->SetIsSubEmitter(true); subEmitterCount++; } //RParticleSystem* subEmittersDeath[kParticleSystemMaxSubDeath]; //state.numCachedSubDataDeath = shuriken.m_SubModule->GetSubEmitterPtrsDeath(&subEmittersDeath[0]); state.numCachedSubDataDeath = subEmittersDeath.size(); state.cachedSubDataDeath = ALLOC_TEMP_MANUAL(ParticleSystemSubEmitterData, state.numCachedSubDataDeath); std::uninitialized_fill (state.cachedSubDataDeath, state.cachedSubDataDeath + state.numCachedSubDataDeath, ParticleSystemSubEmitterData()); for(int i = 0; i < state.numCachedSubDataDeath; i++) { RParticleSystem* subEmitter = subEmittersDeath[i]; ParticleSystemSubEmitterData& subData = state.cachedSubDataDeath[i]; subData.properties = subEmitter->m_SubEmitterModule->GetProperties(); subData.emitter = subEmitter; subEmitter->m_EmissionModule.GetEmissionDataCopy(&subData.emissionData); subEmitter->m_State->SetIsSubEmitter(true); subEmitterCount++; } } return subEmitterCount; } void RParticleSystem::SetUsesAxisOfRotation(){ } bool RParticleSystem::GetIsDistanceEmitter() const { return (EmissionModule::kEmissionTypeDistance == m_EmissionModule.GetEmissionDataRef().type); } void RParticleSystem::Update0 (RParticleSystem& system, const ParticleSystemReadOnlyState& roState, ParticleSystemState& state, float dt, bool fixedTimeStep){ //system.scale //const Transform& transform = system.GetComponent (Transform); Vector3f oldPosition = state.localToWorld.GetPosition(); // 设置位置 state.localToWorld = Transform::GetLocalToWorldMatrixNoScale(&system); Matrix4x4f::Invert_General3D(state.localToWorld, state.worldToLocal); //此处unity会根据版本判断是worldScale or LocalScale state.emitterScale = Transform::GetWorldScaleLossy(&system) * (roState.GetRenderScale()); // 设置速度 if (state.playing && (dt > 0.0001f)) { const Vector3f position = Transform::GetPosition(&system); // 速度计算,根据节点的信息 if (roState.useLocalSpace) state.emitterVelocity = Vec3(0, 0, 0); else state.emitterVelocity = (position - oldPosition) / dt; } // 内存管理? AddStagingBuffer(system); //ParticleSystemRenderer* renderer = (ParticleSystemRenderer*)system.getComponent(COMPONENT_PS_RENDERER); //todo : renderer fun //if(renderer && !renderer->GetScreenSpaceRotation()) //ParticleSystemRenderer::SetUsesAxisOfRotationRec(system, true); // 旋转速度 if(system.m_RotationModule->GetEnabled() || system.m_RotationBySpeedModule->GetEnabled()) system.SetUsesRotationalSpeed(); /* int subEmitterBirthTypeCount = system.m_SubModule->GetSubEmitterTypeCount(kParticleSystemSubTypeBirth); // 设置子发射器累加器 if(system.m_SubModule->GetEnabled() && subEmitterBirthTypeCount) system.SetUsesEmitAccumulator (subEmitterBirthTypeCount); */ // 子发射器设置 int subEmitterCount = SetupSubEmitters(system, *system.m_State); // 设置子发射器累加器 size_t subEmitterBirthTypeCount = system.m_State->numCachedSubDataBirth; if(system.m_SubModule->GetEnabled() && subEmitterBirthTypeCount) system.SetUsesEmitAccumulator (subEmitterBirthTypeCount); #if ENABLE_MULTITHREADED_PARTICLES //todo 多线程 #endif // 碰撞处理 if(system.m_CollisionModule->GetEnabled()) system.m_CollisionModule->AllocateAndCache(roState, state); // 外部力处理 if(system.m_ExternalForcesModule->GetEnabled()) system.m_ExternalForcesModule->AllocateAndCache(roState, state); } void RParticleSystem::Update1 (RParticleSystem& system, ParticleSystemParticles& ps, float dt, bool fixedTimeStep, bool useProcedural, int rayBudget){ //todo : what's gParticleSystemJobProfile ? //PROFILER_AUTO(gParticleSystemJobProfile, NULL) const ParticleSystemReadOnlyState& roState = *system.m_ReadOnlyState; ParticleSystemState& state = *system.m_State; state.rayBudget = rayBudget; // Exposed through script dt *= std::max (roState.speed, 0.0f); float timeStep = GetTimeStep(dt, fixedTimeStep); if(timeStep < 0.00001f){ return; } if (state.playing) { state.accumulatedDt += dt; if(system.GetIsDistanceEmitter()) { float t = state.t + state.accumulatedDt; const float length = roState.lengthInSec; t = roState.looping ? fmodf(t, length) : MIN(t, length); size_t numContinuous = 0; size_t amountOfParticlesToEmit = system.EmitFromModules (system, roState, state.emissionState, numContinuous, state.emitterVelocity, state.t, t, dt); // 发射粒子 StartParticles(system, ps, state.t, t, dt, numContinuous, amountOfParticlesToEmit, 0.0f); } // 更新新增的粒子 Update1Incremental(system, roState, state, ps, 0, timeStep, useProcedural); if (useProcedural)// 更新回放粒子 UpdateProcedural(system, roState, state, ps); } // 更新边界 UpdateBounds(system, ps, state); } void RParticleSystem::Update2 (RParticleSystem& system, const ParticleSystemReadOnlyState& roState, ParticleSystemState& state, bool fixedTimeStep){ if(state.subEmitterCommandBuffer.commandCount > 0){ PlaybackSubEmitterCommandBuffer(system, state, fixedTimeStep); } state.ClearSubEmitterCommandBuffer(); CollisionModule::FreeCache(state); ExternalForcesModule::FreeCache(state); AddStagingBuffer(system); // // Update renderer ParticleSystemRenderer* renderer = (ParticleSystemRenderer*)system.getComponent(COMPONENT_PS_RENDERER); if (renderer) { MinMaxAABB result; //ParticleSystemRenderer::CombineBoundsRec(system, result, true); //renderer->Update (result); } } void RParticleSystem::PlaybackSubEmitterCommandBuffer(const RParticleSystem& parent, ParticleSystemState& state, bool fixedTimeStep) { /* RParticleSystem* subEmittersBirth[kParticleSystemMaxSubBirth]; RParticleSystem* subEmittersCollision[kParticleSystemMaxSubCollision]; RParticleSystem* subEmittersDeath[kParticleSystemMaxSubDeath]; int numBirth = parent.m_SubModule->GetSubEmitterPtrsBirth(&subEmittersBirth[0]); int numCollision = parent.m_SubModule->GetSubEmitterPtrsCollision(&subEmittersCollision[0]); int numDeath = parent.m_SubModule->GetSubEmitterPtrsDeath(&subEmittersDeath[0]); */ std::vector subEmittersBirth; std::vector subEmittersCollision; std::vector subEmittersDeath; auto children = parent.getChildren(); for (auto child : children) { auto childEmitter = dynamic_cast(child); if (childEmitter != nullptr && childEmitter->m_SubEmitterModule->GetEnabled()) { switch (childEmitter->m_SubEmitterModule->GetSubEmitterType()) { case kParticleSystemSubTypeBirth: subEmittersBirth.push_back(childEmitter); break; case kParticleSystemSubTypeCollision: subEmittersCollision.push_back(childEmitter); break; case kParticleSystemSubTypeDeath: subEmittersDeath.push_back(childEmitter); break; } } } auto numBirth = subEmittersBirth.size(); auto numCollision = subEmittersCollision.size(); auto numDeath = subEmittersDeath.size(); const int numCommands = state.subEmitterCommandBuffer.commandCount; const SubEmitterEmitCommand* commands = state.subEmitterCommandBuffer.commands; for(int i = 0; i < numCommands; i++) { const SubEmitterEmitCommand& command = commands[i]; RParticleSystem* shuriken = NULL; if(command.subEmitterType == kParticleSystemSubTypeBirth){ shuriken = (command.subEmitterIndex < numBirth) ? subEmittersBirth[command.subEmitterIndex] : NULL; } else if(command.subEmitterType == kParticleSystemSubTypeCollision){ shuriken = (command.subEmitterIndex < numCollision) ? subEmittersCollision[command.subEmitterIndex] : NULL; } else if(command.subEmitterType == kParticleSystemSubTypeDeath){ shuriken = (command.subEmitterIndex < numDeath) ? subEmittersDeath[command.subEmitterIndex] : NULL; } else{ Assert(!"PlaybackSubEmitterCommandBuffer: Sub emitter type not implemented"); } DebugAssert(shuriken && "Y U NO HERE ANYMORE?"); if(!shuriken){ continue; } RParticleSystem::Emit(*shuriken, command, kParticleSystemEMDirect); } state.subEmitterCommandBuffer.commandCount = 0; } // Returns true if update loop is executed at least once // 更新粒子 void RParticleSystem::Update1Incremental(RParticleSystem& system, const ParticleSystemReadOnlyState& roState, ParticleSystemState& state, ParticleSystemParticles& ps, size_t fromIndex, float dt, bool useProcedural) { ApplyStartDelay (state.delayT, state.accumulatedDt); int numTimeSteps = 0; const int numTimeStepsTotal = int(state.accumulatedDt / dt); while (state.accumulatedDt >= dt) { const float prevT = state.t; state.Tick (roState, dt); const float t = state.t; const bool timePassedDuration = t >= (roState.lengthInSec); const float frameOffset = float(numTimeStepsTotal - 1 - numTimeSteps); if(!roState.looping && timePassedDuration){ system.Stop(); } // Update simulation if (!useProcedural){ // 更新粒子的模块 UpdateModulesIncremental(system, roState, state, ps, fromIndex, dt); } else{ for (int i=0;i= dt) && system.m_ExternalForcesModule->GetEnabled()){ UpdateBounds(system, ps, state); } numTimeSteps++; } } size_t RParticleSystem::EmitFromData (const ParticleSystemReadOnlyState& roState, ParticleSystemEmissionState& emissionState, size_t& numContinuous, const ParticleSystemEmissionData& emissionData, const Vector3f velocity, float fromT, float toT, float dt, float length) { size_t amountOfParticlesToEmit = 0; EmissionModule::Emit(roState, emissionState, amountOfParticlesToEmit, numContinuous, emissionData, velocity, fromT, toT, dt, length); return amountOfParticlesToEmit; } size_t RParticleSystem::EmitFromModules (const RParticleSystem& system, const ParticleSystemReadOnlyState& roState, ParticleSystemEmissionState& emissionState, size_t& numContinuous, const Vector3f velocity, float fromT, float toT, float dt) { if(system.m_EmissionModule.GetEnabled()) return EmitFromData(roState, emissionState, numContinuous, system.m_EmissionModule.GetEmissionDataRef(), velocity, fromT, toT, dt, roState.lengthInSec); return 0; } void RParticleSystem::KeepUpdating() { if (IsActive()) { // Ensure added particles will update, but stop emission m_State->playing = true; m_State->stopEmitting = true; AddToManager(); } } inline Vector3f LerpV(const Vector3f& from, const Vector3f& to, float t) { return to * t + from * (1.0F - t); } void RParticleSystem::Emit(RParticleSystem& system, const SubEmitterEmitCommand& command, ParticleSystemEmitMode emitMode) { int amountOfParticlesToEmit = command.particlesToEmit; if (amountOfParticlesToEmit > 0) { ParticleSystemState& state = *system.m_State; const ParticleSystemReadOnlyState& roState = *system.m_ReadOnlyState; const int numContinuous = command.particlesToEmitContinuous; const float deltaTime = command.deltaTime; float parentT = command.parentT; Vector3f position = command.position; Vector3f initialVelocity = command.velocity; Matrix3x3f rotMat; Vector3f normalizedVelocity = NormalizeSafe(initialVelocity); float angle = Abs(Dot(normalizedVelocity, Vector3f::UNIT_Z)); Vector3f up = LerpV(Vector3f::UNIT_Z, Vector3f::UNIT_Y, angle); if (!LookRotationToMatrix(normalizedVelocity, up, &rotMat)){ rotMat.SetIdentity(); } Matrix4x4f parentParticleMatrix; converterMatrix(parentParticleMatrix,rotMat); parentParticleMatrix.SetPosition(position); // Transform into local space of sub emitter Matrix4x4f concatMatrix; if(roState.useLocalSpace){ MultiplyMatrices3x4(state.worldToLocal, parentParticleMatrix, concatMatrix); }else{ concatMatrix = parentParticleMatrix; } if(roState.useLocalSpace){ initialVelocity = state.worldToLocal.MultiplyVector3(initialVelocity); } DebugAssert(state.GetIsSubEmitter()); DebugAssert(state.stopEmitting); const float commandAliveTime = command.timeAlive; const float timeStep = GetTimeStep(commandAliveTime, true); // @TODO: Perform culling: if max lifetime < timeAlive, then just skip emit // Perform sub emitter loop if(roState.looping){ parentT = fmodf(parentT, roState.lengthInSec); } ParticleSystemParticles& particles = (kParticleSystemEMDirect == emitMode) ? system.m_Particles[kParticleBuffer0] : system.m_ParticlesStaging; system.m_InitialModule.SetInheritedParams(command.inheritValues); size_t fromIndex = system.AddNewParticles(particles, amountOfParticlesToEmit); StartModules (system, roState, state, command.emissionState, initialVelocity, concatMatrix, particles, fromIndex, deltaTime, parentT, numContinuous, 0.0f); system.m_InitialModule.SetInheritedParams(SubEmitterInheritValues()); // Make sure particles get updated if(0 == fromIndex){ system.KeepUpdating(); } // Update incremental if(timeStep > 0.0001f) { float accumulatedDt = commandAliveTime; while (accumulatedDt >= timeStep) { accumulatedDt -= timeStep; UpdateModulesIncremental(system, roState, state, particles, fromIndex, timeStep); } } } } // 发射粒子 void RParticleSystem::StartParticles(RParticleSystem& system, ParticleSystemParticles& ps, const float prevT, const float t, const float dt, const size_t numContinuous, size_t amountOfParticlesToEmit, float frameOffset) { if (amountOfParticlesToEmit <= 0) return; const ParticleSystemReadOnlyState& roState = *system.m_ReadOnlyState; ParticleSystemState& state = *system.m_State; size_t fromIndex = system.AddNewParticles(ps, amountOfParticlesToEmit); const Matrix4x4f localToWorld = !roState.useLocalSpace ? state.localToWorld : Matrix4x4f::IDENTITY; StartModules (system, roState, state, state.emissionState, state.emitterVelocity, localToWorld, ps, fromIndex, dt, t, numContinuous, frameOffset); } // 启动所有模块 void RParticleSystem::StartModules (RParticleSystem& system, const ParticleSystemReadOnlyState& roState, ParticleSystemState& state, const ParticleSystemEmissionState& emissionState, Vector3f initialVelocity, const Matrix4x4f& matrix, ParticleSystemParticles& ps, size_t fromIndex, float dt, float t, size_t numContinuous, float frameOffset) { system.m_InitialModule.Start (roState, state, ps, matrix, fromIndex, t); if(system.m_ShapeModule.GetEnabled()) system.m_ShapeModule.Start (roState, state, ps, matrix, fromIndex, t); DebugAssert(roState.lengthInSec > 0.0001f); const float normalizedT = t / roState.lengthInSec; DebugAssert (normalizedT >= 0.0f); DebugAssert (normalizedT <= 1.0f); size_t count = ps.array_size(); const Vector3f velocityOffset = system.m_InitialModule.GetInheritVelocity() * initialVelocity; for(size_t q = fromIndex; q < count; q++) { const float randomValue = GenerateRandom(ps.randomSeed[q] + kParticleSystemStartSpeedCurveId); ps.velocity[q] *= Evaluate (system.m_InitialModule.GetSpeedCurve(), normalizedT, randomValue) * roState.GetRenderScale(); ps.velocity[q] += velocityOffset; } // 单个粒子的属性 for(size_t q = fromIndex; q < count; ) // array size changes { // subFrameOffset allows particles to be spawned at increasing times, thus spacing particles within a single frame. // For example if you spawn particles with high velocity you will get a continous streaming instead of a clump of particles. const int particleIndex = q - fromIndex; float subFrameOffset = (particleIndex < numContinuous) ? (float(particleIndex) + emissionState.m_ToEmitAccumulator) * emissionState.m_ParticleSpacing : 0.0f; DebugAssert(subFrameOffset >= -0.01f); DebugAssert(subFrameOffset <= 1.5f); // Not 1 due to possibly really bad precision subFrameOffset = clamp01(subFrameOffset); // Update from curves and apply forces etc. UpdateModulesPreSimulationIncremental (system, roState, state, ps, q, q+1, subFrameOffset * dt); // Position change due to where the emitter was at time of emission ps.position[q] -= initialVelocity * (frameOffset + subFrameOffset) * dt; // Position, rotation and energy change due to how much the particle has travelled since time of emission // @TODO: Call Simulate instead? ps.lifetime[q] -= subFrameOffset * dt; if((ps.lifetime[q] < 0.0f) && (count > 0)) { KillParticle(roState, state, ps, q, count); continue; } ps.position[q] += (ps.velocity[q] + ps.animatedVelocity[q]) * subFrameOffset * dt; if(ps.usesRotationalSpeed){ ps.rotation[q] += ps.rotationalSpeed[q] * subFrameOffset * dt; } if(system.m_SubModule->GetEnabled()){ system.m_SubModule->Update (roState, state, ps, q, q+1, subFrameOffset * dt); } ++q; } ps.array_resize(count); } // 更新所有带曲线的属性和外部力 void RParticleSystem::UpdateModulesPreSimulationIncremental (const RParticleSystem& system, const ParticleSystemReadOnlyState& roState, const ParticleSystemState& state, ParticleSystemParticles& particles, const size_t fromIndex, const size_t toIndex, float dt) { const size_t count = particles.array_size(); system.m_InitialModule.Update (roState, state, particles, fromIndex, toIndex, dt); if(system.m_RotationModule->GetEnabled()) system.m_RotationModule->Update (roState, state, particles, fromIndex, toIndex); if(system.m_VelocityModule->GetEnabled()) system.m_VelocityModule->Update (roState, state, particles, fromIndex, toIndex); if(system.m_ForceModule->GetEnabled()) system.m_ForceModule->Update (roState, state, particles, fromIndex, toIndex, dt); if(system.m_ExternalForcesModule->GetEnabled()) system.m_ExternalForcesModule->Update (roState, state, particles, fromIndex, toIndex, dt); if(system.m_ClampVelocityModule->GetEnabled()) system.m_ClampVelocityModule->Update (roState, state, particles, fromIndex, toIndex, dt); if(system.m_RotationBySpeedModule->GetEnabled()) system.m_RotationBySpeedModule->Update (roState, state, particles, fromIndex, toIndex); Assert(count >= toIndex); Assert(particles.array_size() == count); } void RParticleSystem::UpdateModulesIncremental (const RParticleSystem& system, const ParticleSystemReadOnlyState& roState, ParticleSystemState& state, ParticleSystemParticles& particles, size_t fromIndex, float dt) { // 更新曲线和外部力 UpdateModulesPreSimulationIncremental (system, roState, state, particles, fromIndex, particles.array_size(), dt); // 更新位置和旋转 SimulateParticles(roState, state, particles, fromIndex, dt); // 更新子模块和外部力 UpdateModulesPostSimulationIncremental (system, roState, state, particles, fromIndex, dt); } // 更新位置和旋转 void RParticleSystem::SimulateParticles (const ParticleSystemReadOnlyState& roState, ParticleSystemState& state, ParticleSystemParticles& ps, const size_t fromIndex, float dt) { size_t particleCount = ps.array_size(); for (size_t q = fromIndex; q < particleCount; ) { ps.lifetime[q] -= dt; #if UNITY_EDITOR if(ParticleSystemEditor::GetIsExtraInterpolationStep()) { ps.lifetime[q] = max(ps.lifetime[q], 0.0f); } else #endif if (ps.lifetime[q] < 0) { KillParticle(roState, state, ps, q, particleCount); continue; } ++q; } ps.array_resize(particleCount); for (size_t q = fromIndex; q < particleCount; ++q) ps.position[q] += (ps.velocity[q] + ps.animatedVelocity[q]) * dt; if(ps.usesRotationalSpeed) for (size_t q = fromIndex; q < particleCount; ++q) ps.rotation[q] += ps.rotationalSpeed[q] * dt; } // 更新子模块和外部力 void RParticleSystem::UpdateModulesPostSimulationIncremental (const RParticleSystem& system, const ParticleSystemReadOnlyState& roState, ParticleSystemState& state, ParticleSystemParticles& particles, const size_t fromIndex, float dt) { const size_t count = particles.array_size(); if(system.m_SubModule->GetEnabled()){ system.m_SubModule->Update (roState, state, particles, fromIndex, particles.array_size(), dt); } Assert(count == particles.array_size()); if(system.m_CollisionModule->GetEnabled()) { //#if !ENABLE_MULTITHREADED_PARTICLES // PROFILER_AUTO(gParticleSystemUpdateCollisions, NULL) //#endif //system.m_CollisionModule->Update (roState, state, particles, fromIndex, dt); } } void RParticleSystem::StartParticlesProcedural(RParticleSystem& system, ParticleSystemParticles& ps, const float prevT, const float t, const float dt, const size_t numContinuous, size_t amountOfParticlesToEmit, float frameOffset) { //DebugAssert(CheckSupportsProcedural(system)); ParticleSystemState& state = *system.m_State; int numParticlesRecorded = 0; for (int i=0;i 0) { UInt32 randomSeed = 0; #if UNITY_EDITOR ParticleSystemEditor::UpdateRandomSeed(system); randomSeed = ParticleSystemEditor::GetRandomSeed(system); #endif state.emitReplay.push_back(ParticleSystemEmitReplay(t, amountOfParticlesToEmit, emissionOffset, emissionGap, numContinuous, randomSeed)); } } void RParticleSystem::UpdateProcedural (RParticleSystem& system, const ParticleSystemReadOnlyState& roState, ParticleSystemState& state, ParticleSystemParticles& ps) { DebugAssert(CheckSupportsProcedural(system)); // Clear all particles ps.array_resize(0); const Matrix4x4f localToWorld = !roState.useLocalSpace ? state.localToWorld : Matrix4x4f::IDENTITY; // Emit all particles for (int i=0; iGetEnabled()){ system.m_RotationModule->UpdateProcedural (state, ps); } if (system.m_VelocityModule->GetEnabled()){ system.m_VelocityModule->UpdateProcedural (roState, state, ps); } if (system.m_ForceModule->GetEnabled()){ system.m_ForceModule->UpdateProcedural (roState, state, ps); } // Modules that are not supported by procedural DebugAssert(!system.m_RotationBySpeedModule->GetEnabled()); // find out if possible to support it DebugAssert(!system.m_ClampVelocityModule->GetEnabled()); // unsupported: (Need to compute velocity by deriving position curves...), possible to support? DebugAssert(!system.m_CollisionModule->GetEnabled()); DebugAssert(!system.m_SubModule->GetEnabled()); // find out if possible to support it DebugAssert(!system.m_ExternalForcesModule->GetEnabled()); } void RParticleSystem::UpdateBounds(const RParticleSystem& system, const ParticleSystemParticles& ps, ParticleSystemState& state) { const size_t particleCount = ps.array_size(); if (particleCount == 0) { state.minMaxAABB = MinMaxAABB (Vec3::ZERO, Vec3::ZERO); return; } state.minMaxAABB.Init(); if(CheckSupportsProcedural(system)) { Matrix4x4f localToWorld = Transform::GetLocalToWorldMatrixNoScale (&system); // Lifetime and max speed const Vector2f minMaxLifeTime = system.m_InitialModule.GetLifeTimeCurve().FindMinMax(); const float maxLifeTime = minMaxLifeTime.y; const Vector2f minMaxStartSpeed = system.m_InitialModule.GetSpeedCurve().FindMinMax() * (maxLifeTime * (system.getRendererScale() * CC_CONTENT_SCALE_FACTOR())); state.minMaxAABB = MinMaxAABB(Vec3::ZERO, Vec3::ZERO); state.minMaxAABB.Encapsulate(Vec3::UNIT_Z * minMaxStartSpeed.x); state.minMaxAABB.Encapsulate(Vec3::UNIT_Z * minMaxStartSpeed.y); if(system.m_ShapeModule.GetEnabled()) system.m_ShapeModule.CalculateProceduralBounds(state.minMaxAABB, state.emitterScale, minMaxStartSpeed); // Gravity // @TODO: Do what we do for force and velocity here, i.e. transform bounds properly const Vector3f gravityBounds = system.m_InitialModule.GetGravity(*system.m_ReadOnlyState, *system.m_State) * maxLifeTime * maxLifeTime * 0.5f; state.minMaxAABB._max += MAX(gravityBounds, Vec3::ZERO); state.minMaxAABB._min += MIN(gravityBounds, Vec3::ZERO); MinMaxAABB velocityBounds (Vec3::ZERO, Vec3::ZERO); if(system.m_VelocityModule->GetEnabled()) system.m_VelocityModule->CalculateProceduralBounds(velocityBounds, localToWorld, maxLifeTime); state.minMaxAABB._max += velocityBounds._max; state.minMaxAABB._min += velocityBounds._min; MinMaxAABB forceBounds (Vec3::ZERO, Vec3::ZERO); if(system.m_ForceModule->GetEnabled()) system.m_ForceModule->CalculateProceduralBounds(forceBounds, localToWorld, maxLifeTime); state.minMaxAABB._max += forceBounds._max; state.minMaxAABB._min += forceBounds._min; // Modules that are not supported by procedural DebugAssert(!system.m_RotationBySpeedModule->GetEnabled()); // find out if possible to support it DebugAssert(!system.m_ClampVelocityModule->GetEnabled()); // unsupported: (Need to compute velocity by deriving position curves...), possible to support? DebugAssert(!system.m_CollisionModule->GetEnabled()); DebugAssert(!system.m_SubModule->GetEnabled()); // find out if possible to support it DebugAssert(!system.m_ExternalForcesModule->GetEnabled()); } else { for (size_t q = 0; q < particleCount; ++q) state.minMaxAABB.Encapsulate (ps.position[q]); ParticleSystemRenderer* renderer = (ParticleSystemRenderer*)const_cast(system).getComponent(COMPONENT_PS_RENDERER); if(renderer && (renderer->GetRenderMode() == kSRMStretch3D)) { // const float velocityScale = renderer->GetVelocityScale(); // const float lengthScale = renderer->GetLengthScale(); // for(size_t q = 0; q < particleCount; ++q ) // { // float sqrVelocity = SqrMagnitude (ps.velocity[q]+ps.animatedVelocity[q]); // if (sqrVelocity > Vector3f::epsilon) // { // float scale = velocityScale + FastInvSqrt (sqrVelocity) * lengthScale * ps.size[q]; // state.minMaxAABB.Encapsulate(ps.position[q] - ps.velocity[q] * scale); // } } } } template void RParticleSystem::Transfer (TransferFunction& transfer) { // Super::Transfer (transfer); m_ReadOnlyState->Transfer (transfer); m_ReadOnlyState->CheckConsistency(); m_State->Transfer (transfer); transfer.Transfer(m_InitialModule, m_InitialModule.GetName ()); m_InitialModule.CheckConsistency (); transfer.Transfer(m_ShapeModule, m_ShapeModule.GetName ()); m_ShapeModule.CheckConsistency (); transfer.Transfer(m_EmissionModule, m_EmissionModule.GetName ()); m_EmissionModule.CheckConsistency (); transfer.Transfer(*m_SizeModule, m_SizeModule->GetName ()); m_SizeModule->CheckConsistency (); transfer.Transfer(*m_RotationModule, m_RotationModule->GetName ()); m_RotationModule->CheckConsistency (); transfer.Transfer(*m_ColorModule, m_ColorModule->GetName ()); m_ColorModule->CheckConsistency (); transfer.Transfer(*m_UVModule, m_UVModule->GetName ()); m_UVModule->CheckConsistency (); transfer.Transfer(*m_VelocityModule, m_VelocityModule->GetName ()); m_VelocityModule->CheckConsistency (); transfer.Transfer(*m_ForceModule, m_ForceModule->GetName ()); m_ForceModule->CheckConsistency (); transfer.Transfer(*m_ExternalForcesModule, m_ExternalForcesModule->GetName ()); m_ExternalForcesModule->CheckConsistency (); transfer.Transfer(*m_ClampVelocityModule, m_ClampVelocityModule->GetName ()); m_ClampVelocityModule->CheckConsistency (); transfer.Transfer(*m_SizeBySpeedModule, m_SizeBySpeedModule->GetName ()); m_SizeBySpeedModule->CheckConsistency (); transfer.Transfer(*m_RotationBySpeedModule, m_RotationBySpeedModule->GetName ()); m_RotationBySpeedModule->CheckConsistency (); transfer.Transfer(*m_ColorBySpeedModule, m_ColorBySpeedModule->GetName ()); m_ColorBySpeedModule->CheckConsistency (); transfer.Transfer(*m_CollisionModule, m_CollisionModule->GetName ()); m_CollisionModule->CheckConsistency (); //transfer.Transfer(*m_SubModule, m_SubModule->GetName ()); m_SubModule->CheckConsistency (); transfer.Transfer(*m_SubEmitterModule, m_SubEmitterModule->GetName ()); m_SubEmitterModule->CheckConsistency (); transfer.Transfer(*m_renderer, m_renderer->GetName()); m_ReadOnlyState->scale = m_renderer->GetScale(); if(transfer.IsReading()) { //TODO: DetermineSupportsProcedural /* m_State->supportsProcedural = DetermineSupportsProcedural(*this); */ m_State->invalidateProcedural = true; // Stuff might have changed which we can't support (example: start speed has become smaller) } } INSTANTIATE_TEMPLATE_TRANSFER(RParticleSystem) size_t RParticleSystem::LimitParticleCount(size_t requestSize) const { const size_t maxNumParticles = m_InitialModule.GetMaxNumParticles(); return MIN(requestSize, maxNumParticles); } size_t RParticleSystem::AddNewParticles(ParticleSystemParticles& particles, size_t newParticles) const { const size_t fromIndex = particles.array_size(); const size_t newSize = LimitParticleCount(fromIndex + newParticles); particles.array_resize(newSize); return MIN(fromIndex, newSize); } void RParticleSystem::UpdateModulesNonIncremental (const RParticleSystem& system, const ParticleSystemParticles& particles, ParticleSystemParticlesTempData& psTemp, int fromIndex, int toIndex) { Assert(particles.array_size() == psTemp.particleCount); const ParticleSystemReadOnlyState& roState = *system.m_ReadOnlyState; for(int i = fromIndex; i < toIndex; i++){ psTemp.color[i] = particles.color[i]; } for(int i = fromIndex; i < toIndex; i++){ psTemp.size[i] = particles.size[i]; } // const Matrix4x4f& mat = system.getNodeToWorldTransform(); const Matrix4x4f& mat = Transform::GetLocalToWorldMatrixNoScale(&system); for(int i = fromIndex; i < toIndex; i++){ psTemp.particleSysytemWorldPos[i] = mat.GetPosition(); } if(system.m_ColorModule->GetEnabled()){ system.m_ColorModule->Update (particles, psTemp.color, fromIndex, toIndex); } if(system.m_ColorBySpeedModule->GetEnabled()){ system.m_ColorBySpeedModule->Update (roState, particles, psTemp.color, fromIndex, toIndex); } if(system.m_SizeModule->GetEnabled()){ system.m_SizeModule->Update (particles, psTemp.size, fromIndex, toIndex); } if(system.m_SizeBySpeedModule->GetEnabled()){ system.m_SizeBySpeedModule->Update (roState, particles, psTemp.size, fromIndex, toIndex); } //if (gGraphicsCaps.needsToSwizzleVertexColors) //std::transform(&psTemp.color[fromIndex], &psTemp.color[toIndex], &psTemp.color[fromIndex], SwizzleColorForPlatform); if(system.m_UVModule->GetEnabled()) { // No other systems used sheet index yet, allocate! if(!psTemp.sheetIndex) { psTemp.sheetIndex = ALLOC_TEMP_MANUAL(float, psTemp.particleCount); for(int i = 0; i < fromIndex; i++){ psTemp.sheetIndex[i] = 0.0f; } } system.m_UVModule->Update (particles, psTemp.sheetIndex, fromIndex, toIndex); system.m_UVModule->RefreshFrames(system.m_renderer->GetCachedVertexInfos()); } else if(psTemp.sheetIndex){ // if this is present with disabled module, that means we have a combined buffer with one system not using UV module, just initislize to 0.0f for(int i = fromIndex; i < toIndex; i++){ psTemp.sheetIndex[i] = 0.0f; } } } void RParticleSystem::Clear (bool updateBounds) { for(int i = 0; i < kNumParticleBuffers; i++){ m_Particles[i].array_resize(0); } m_ParticlesStaging.array_resize(0); m_State->emitReplay.resize_uninitialized(0); if (m_State->stopEmitting) { // This triggers sometimes, why? (case 491684) DebugAssert (m_State->needRestart); m_State->playing = false; RemoveFromManager(); } if(updateBounds) { UpdateBounds(*this, m_Particles[kParticleBuffer0], *m_State); Update2(*this, *m_ReadOnlyState, *m_State, false); } } void RParticleSystem::GetNumTiles(int& uvTilesX, int& uvTilesY) const { uvTilesX = uvTilesY = 1; if(m_UVModule->GetEnabled()) m_UVModule->GetNumTiles(uvTilesX, uvTilesY); } void RParticleSystem::Cull() { // if(!IsWorldPlaying()) // return; m_State->culled = true; Clear(false); //m_State->cullTime = GetCurTime (); RemoveFromManager(); } void RParticleSystem::AwakeFromLoadGroup () { auto root = FindGroupRoot(); root->AwakeFromLoadTree(); } void RParticleSystem::PlayGroup () { auto root = FindGroupRoot(); root->PlayTree(); } void RParticleSystem::StopGroup () { auto root = FindGroupRoot(); root->StopTree(); } void RParticleSystem::ClearGroup () { auto root = FindGroupRoot(); root->ClearTree(); } void RParticleSystem::StopAndClearGroup () { auto root = FindGroupRoot(); root->StopAndClearTree(); } void RParticleSystem::Play (bool autoPrewarm) { Assert (m_State); if(!IsActive () || m_State->GetIsSubEmitter()) return; m_State->stopEmitting = false; m_State->playing = true; if (m_State->needRestart) { if(m_ReadOnlyState->prewarm) { if (autoPrewarm) // 往前走0.0秒 //AutoPrewarm(); ; } else { m_State->delayT = m_ReadOnlyState->startDelay; } m_State->playing = true; m_State->t = 0.0f; m_State->numLoops = 0; m_State->invalidateProcedural = false; m_State->accumulatedDt = 0.0f; #if UNITY_EDITOR m_EditorRandomSeedIndex = 0; #endif m_State->emissionState.Clear(); } if(m_State->culled && CheckSupportsProcedural(*this)){ Cull(); } else{ AddToManager(); } } bool RParticleSystem::IsPlaying () const { Assert (m_State); return m_State->playing; } void RParticleSystem::onEnter() { Node::onEnter(); //TODO: AwakeFromLoad 需要改成在 CCB 加载完成后调用 AwakeFromLoad(); } void RParticleSystem::onExit() { RemoveFromManager(); Node::onExit(); #if REDREAM_EDITOR if (drawNode != nullptr) { drawNode->removeFromParent(); drawNode = nullptr; } #endif } void RParticleSystem::setVisible(bool visible) { if (visible != _visible && m_ReadOnlyState->playOnAwake) { Node::setVisible(visible); if (visible) { this->AwakeFromLoadTree(); this->PlayTree(); } else { this->StopAndClearTree(); } return; } Node::setVisible(visible); } void RParticleSystem::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags){ if (_useMaterialFile) { _command.init(_globalZOrder); _command.func = CC_CALLBACK_0(RParticleSystem::onDraw, this); renderer->addCommand(&_command); } else { if (_texture) { auto particleCount = GetParticles().array_size(); if (particleCount) { allocMemory(particleCount); #if REDREAM_EDITOR m_renderer->Render(this, _quads, Director::getInstance()->getRunningScene()->getNodeToWorldTransform() * Transform::GetLocalToWorldMatrix(this)); #else m_renderer->Render(this, _quads, transform); #endif _quadCommand.init(_globalZOrder, _texture.get(), _glProgramState, _blendFunc, _quads, particleCount, Mat4::IDENTITY, flags); renderer->addCommand(&_quadCommand); } } } } void RParticleSystem::onDraw(){ if (m_Material) { auto pass = m_Material->getTechnique()->getPassByIndex(0); auto glProgram = pass->getGLProgramState()->getGLProgram(); glProgram->use(); glProgram->setUniformsForBuiltins(); pass->getGLProgramState()->applyUniforms(); pass->getStateBlock()->bind(); #if REDREAM_EDITOR m_renderer->Render(this, nullptr, Director::getInstance()->getRunningScene()->getNodeToWorldTransform() * Transform::GetLocalToWorldMatrix(this)); #else m_renderer->Render(this, nullptr, _modelViewTransform); #endif } } #if REDREAM_EDITOR void RParticleSystem::OnDrawGizmosSelected() { Node* node = this; while (node != nullptr) { if (!node->isVisible()) return; node = node->getParent(); } float scale = m_ReadOnlyState->GetRenderScale(); int shapeType = m_ShapeModule.GetType(); float radius = m_ShapeModule.GetRadius() * scale; float angle = m_ShapeModule.GetAngle(); angle = std::min(angle, 89.99f); float radians = CC_DEGREES_TO_RADIANS(angle); float length = m_ShapeModule.GetLength() * scale; float arc = m_ShapeModule.GetArc(); float arcRadians = CC_DEGREES_TO_RADIANS(arc); float speed = m_InitialModule.GetSpeedCurve().GetScalar() * scale; if (m_InitialModule.GetSpeedCurve().minMaxState == kMMCTwoConstants) { speed = m_InitialModule.GetSpeedCurve().editorCurves.max.GetKey(0).value * scale; } float boxX = m_ShapeModule.GetBoxX() * scale; float boxY = m_ShapeModule.GetBoxY() * scale; float boxZ = m_ShapeModule.GetBoxZ() * scale; if (drawNode == nullptr) { drawNode = cocos2d::DrawNode3D::create(1.0f, true); auto drawNodeLayer = Director::getInstance()->getRunningScene()->getChildByName("m_drawNodeLayer"); if (drawNodeLayer == nullptr) { drawNodeLayer = Node::create(); drawNodeLayer->setName("m_drawNodeLayer"); Director::getInstance()->getRunningScene()->addChild(drawNodeLayer); } drawNodeLayer->addChild(drawNode); } Color4F cyan(0, 1, 1, 1); auto worldTrans = Transform::GetContentToWorldMatrix() * Transform::GetLocalToWorldMatrix(this); drawNode->setScaleZ(m_renderer->GetOrthographic() ? 0 : 1); switch (shapeType) { case ShapeModule::kBox: drawNode->drawWireCube(Vec3::ZERO, Vec3(boxX, boxY, boxZ), false, cyan, worldTrans); break; case ShapeModule::kSphere: case ShapeModule::kSphereShell: drawNode->drawWireSphere(Vec3::ZERO, radius, cyan, worldTrans); break; case ShapeModule::kHemiSphere: case ShapeModule::kHemiSphereShell: drawNode->drawWireDisk (Vec3::ZERO, Vec3::UNIT_Z, radius, cyan, worldTrans); drawNode->drawWireArc (Vec3::ZERO, Vec3::UNIT_Y, -Vec3::UNIT_X, 180.0f, radius, cyan, worldTrans); drawNode->drawWireArc (Vec3::ZERO, Vec3::UNIT_X, Vec3::UNIT_Y, 180.0f, radius, cyan, worldTrans); break; case ShapeModule::kCone: case ShapeModule::kConeShell: length = speed; case ShapeModule::kConeVolume: case ShapeModule::kConeVolumeShell: { float bigRadius = radius + length * tan(radians); drawNode->drawWireArc (Vec3::ZERO, Vec3::UNIT_Z, Vec3::UNIT_X, 360.0f, radius, cyan, worldTrans); drawNode->drawWireArc (Vec3(0, 0, length), Vec3::UNIT_Z, Vec3::UNIT_X, 360.0f, bigRadius, cyan, worldTrans); drawNode->drawLine(Vec3(radius, 0, 0), Vec3(bigRadius, 0, length), cyan, worldTrans); drawNode->drawLine(Vec3(-radius, 0, 0), Vec3(-bigRadius, 0, length), cyan, worldTrans); drawNode->drawLine(Vec3(0, radius, 0), Vec3(0, bigRadius, length), cyan, worldTrans); drawNode->drawLine(Vec3(0, -radius, 0), Vec3(0, -bigRadius, length), cyan, worldTrans); } break; case ShapeModule::kCircle: case ShapeModule::kCircleEdge: drawNode->drawWireArc(Vec3::ZERO, Vec3::UNIT_Z, Vec3::UNIT_X, arc, radius, cyan, worldTrans); drawNode->drawLine(Vec3::ZERO, Vec3(radius, 0, 0), cyan, worldTrans); drawNode->drawLine(Vec3::ZERO, Quaternion(Vec3::UNIT_Z, arcRadians) * Vec3(radius, 0, 0), cyan, worldTrans); break; default: break; } } #endif void RParticleSystem::update(float dt){ Node::update(dt); return; #ifdef FOR_QY_TEST AddToManager(); // setActive(1); if (!m_State->playing){ Play(true); } RParticleSystem::BeginUpdateAll(); //m_renderer->Render(this); RParticleSystem::EndUpdateAll(); #endif } // Getters Setters for Editor // 曲线 void TransferKeyframeToData(const KeyframeTpl& curve, KeyframeData &data) { data.time = curve.time; data.value = curve.value; data.inSlope = curve.inSlope; data.outSlope = curve.outSlope; data.tangentMode = curve.tangentMode; } void TransferKeyframeFromData(KeyframeTpl& curve, const KeyframeData &data) { curve.time = data.time; curve.value = data.value; curve.inSlope = data.inSlope; curve.outSlope = data.outSlope; curve.tangentMode = data.tangentMode; } void TransferAnimationCurveToData(const AnimationCurve& curve, AnimationCurveData &data) { data.m_PreInfinity = curve.GetPreInfinity(); data.m_PostInfinity = curve.GetPostInfinity(); data.m_Curve.clear(); int count = curve.GetKeyCount(); for (int i = 0; i < count; i++) { const AnimationCurve::Keyframe& key = curve.GetKey(i); KeyframeData keyData; TransferKeyframeToData(key, keyData); data.m_Curve.push_back(keyData); } } void TransferAnimationCurveFromData(AnimationCurve& curve, const AnimationCurveData &data) { curve.SetPreInfinity(data.m_PreInfinity); curve.SetPostInfinity(data.m_PostInfinity); int count = (int)data.m_Curve.size(); curve.ResizeUninitialized(count); for (int i = 0; i < count; i++) { AnimationCurve::Keyframe& key = curve.GetKey(i); const KeyframeData& keyData = data.m_Curve[i]; TransferKeyframeFromData(key, keyData); } } void RParticleSystem::TransferMinMaxCurveToData(const MinMaxCurve& curve, MinMaxCurveData &data) const { data.scalar = curve.GetScalar(); data.minMaxState = (MinMaxCurveState)curve.minMaxState; TransferAnimationCurveToData(curve.editorCurves.max, data.maxCurve); TransferAnimationCurveToData(curve.editorCurves.min, data.minCurve); } void RParticleSystem::TransferMinMaxCurveFromData(MinMaxCurve& curve, const MinMaxCurveData &data) { curve.SetScalarNoBuild(data.scalar); curve.minMaxState = data.minMaxState; TransferAnimationCurveFromData(curve.editorCurves.max, data.maxCurve); TransferAnimationCurveFromData(curve.editorCurves.min, data.minCurve); if (data.minMaxState == kMMCTwoConstants) { curve.editorCurves.max.ResizeUninitialized(1); curve.editorCurves.min.ResizeUninitialized(1); } curve.OnSetDataEnd(); } // 渐变色 void TransferGradientNEWToData(const GradientNEW& gradient, GradientNEWData &data) { data.m_Color.clear(); int count = gradient.GetNumColorKeys(); for (int i = 0; i < count; i++) { const auto& color = gradient.GetKey(i); Color3BData colorData; colorData.color = Color3B(color); colorData.time = gradient.GetColorTime(i); data.m_Color.push_back(colorData); } data.m_Alpha.clear(); count = gradient.GetNumAlphaKeys(); for (int i = 0; i < count; i++) { const auto& color = gradient.GetKey(i); AlphaData alphaData; alphaData.alpha = color.a; alphaData.time = gradient.GetAlphaTime(i); data.m_Alpha.push_back(alphaData); } } void TransferGradientNEWFromData(GradientNEW& gradient, const GradientNEWData &data) { int count = MIN((int)data.m_Color.size(), kGradientMaxNumKeys); gradient.SetNumColorKeys(count); for (int i = 0; i < count; i++) { const Color3BData& colorData = data.m_Color.at(i); gradient.SetKey(i, Color4B(colorData.color, 0)); gradient.SetColorTime(i, colorData.time); } count = MIN((int)data.m_Alpha.size(), kGradientMaxNumKeys); gradient.SetNumAlphaKeys(count); for (int i = 0; i < count; i++) { const AlphaData& alphaData = data.m_Alpha.at(i); auto color = gradient.GetKey(i); color.a = alphaData.alpha; gradient.SetKey(i, color); gradient.SetAlphaTime(i, alphaData.time); } } void RParticleSystem::TransferMinMaxGradientToData(const MinMaxGradient& gradient, MinMaxGradientData &data) const { data.minMaxState = (MinMaxGradientState)gradient.minMaxState; data.minColor = gradient.minColor; data.maxColor = gradient.maxColor; TransferGradientNEWToData(gradient.minGradient, data.minGradient); TransferGradientNEWToData(gradient.maxGradient, data.maxGradient); } void RParticleSystem::TransferMinMaxGradientFromData(MinMaxGradient& gradient, const MinMaxGradientData &data) { gradient.minMaxState = data.minMaxState; gradient.minColor = data.minColor; gradient.maxColor = data.maxColor; TransferGradientNEWFromData(gradient.minGradient, data.minGradient); TransferGradientNEWFromData(gradient.maxGradient, data.maxGradient); } // EmissionBurst 信息 void RParticleSystem::TransferEmissionToData(const ParticleSystemEmissionData& emission, EmissionData &data) const { data.burstData.clear(); for (int i = 0; i < emission.burstCount; i++) { BurstData burstData; burstData.burstTime = emission.burstTime[i]; burstData.burstParticleCount = emission.burstParticleCount[i]; data.burstData.push_back(burstData); } } void RParticleSystem::TransferEmissionFromData(ParticleSystemEmissionData& emission, const EmissionData &data) { emission.burstCount = data.burstData.size(); for (int i = 0; i < emission.burstCount; i++) { const BurstData& burstData = data.burstData[i]; emission.burstTime[i] = burstData.burstTime; emission.burstParticleCount[i] = burstData.burstParticleCount; } } float CurveGetMaxValue(const MinMaxCurve& curve) { if (curve.minMaxState == kMMCTwoConstants) return MAX( curve.editorCurves.min.GetKey(0).value * curve.GetScalar (), curve.editorCurves.max.GetKey(0).value * curve.GetScalar ()); return curve.GetScalar (); } // m_EmissionModule void RParticleSystem::setEmissionModuleBurstData(const EmissionData& value) { TransferEmissionFromData(m_EmissionModule.GetEmissionData(), value); const auto& emissionData = m_EmissionModule.GetEmissionData(); int maxParticleCount = 0; float maxLifeTime = CurveGetMaxValue(m_InitialModule.GetLifeTimeCurve()); float maxEmissionRate = CurveGetMaxValue(emissionData.rate); maxParticleCount += maxLifeTime * maxEmissionRate; for (int i = 0; i < emissionData.burstCount; i++) { maxParticleCount += emissionData.burstParticleCount[i]; } maxParticleCount = MIN(maxParticleCount, m_InitialModule.GetMaxNumParticles()); allocMemory(maxParticleCount); } // m_RotationModule void RParticleSystem::setRotationModuleEnabled(bool value) { m_RotationModule->SetEnabled(value); } bool RParticleSystem::getRotationModuleEnabled() const { return m_RotationModule->GetEnabled(); } void RParticleSystem::setRotationModuleRate(const MinMaxCurveData& value) { TransferMinMaxCurveFromData(m_RotationModule->GetCurve(), value); } MinMaxCurveData RParticleSystem::getRotationModuleRate() const { MinMaxCurveData data; TransferMinMaxCurveToData(m_RotationModule->GetCurve(), data); return data; } // m_SubModule /* void RParticleSystem::setSubModuleEnabled(bool value) { m_SubModule->SetEnabled(value); } bool RParticleSystem::getSubModuleEnabled() const { return m_SubModule->GetEnabled(); } void RParticleSystem::setSubModuleEmittersBirthID0(int value) { m_SubModule->SetSubEmittersBirthID(0, value); } int RParticleSystem::getSubModuleEmittersBirthID0() const { return m_SubModule->GetSubEmittersBirthID(0); } void RParticleSystem::setSubModuleEmittersBirthID1(int value) { m_SubModule->SetSubEmittersBirthID(1, value); } int RParticleSystem::getSubModuleEmittersBirthID1() const { return m_SubModule->GetSubEmittersBirthID(1); } void RParticleSystem::setSubModuleEmittersCollisionID0(int value) { m_SubModule->SetSubEmittersCollisionID(0, value); } int RParticleSystem::getSubModuleEmittersCollisionID0() const { return m_SubModule->GetSubEmittersCollisionID(0); } void RParticleSystem::setSubModuleEmittersCollisionID1(int value) { m_SubModule->SetSubEmittersCollisionID(1, value); } int RParticleSystem::getSubModuleEmittersCollisionID1() const { return m_SubModule->GetSubEmittersCollisionID(1); } void RParticleSystem::setSubModuleEmittersDeathID0(int value) { m_SubModule->SetSubEmittersDeathID(0, value); } int RParticleSystem::getSubModuleEmittersDeathID0() const { return m_SubModule->GetSubEmittersDeathID(0); } void RParticleSystem::setSubModuleEmittersDeathID1(int value) { m_SubModule->SetSubEmittersDeathID(1, value); } int RParticleSystem::getSubModuleEmittersDeathID1() const { return m_SubModule->GetSubEmittersDeathID(1); } */ // m_SubEmitterModule void RParticleSystem::setSubEmitterModuleEnabled(bool value) { m_SubEmitterModule->SetEnabled(value); } bool RParticleSystem::getSubEmitterModuleEnabled() const { return m_SubEmitterModule->GetEnabled(); } void RParticleSystem::setSubEmitterModuleSubEmitterType(int value) { m_SubEmitterModule->SetSubEmitterType(value); } int RParticleSystem::getSubEmitterModuleSubEmitterType() const { return m_SubEmitterModule->GetSubEmitterType(); } bool RParticleSystem::getSubEmitterModuleInheritColor() const { return m_SubEmitterModule->GetInheritColor(); } void RParticleSystem::setSubEmitterModuleInheritColor(bool value) { m_SubEmitterModule->SetInheritColor(value); } bool RParticleSystem::getSubEmitterModuleInheritSize() const { return m_SubEmitterModule->GetInheritSize(); } void RParticleSystem::setSubEmitterModuleInheritSize(bool value) { m_SubEmitterModule->SetInheritSize(value); } bool RParticleSystem::getSubEmitterModuleInheritRotation() const { return m_SubEmitterModule->GetInheritRotation(); } void RParticleSystem::setSubEmitterModuleInheritRotation(bool value) { m_SubEmitterModule->SetInheritRotation(value); } bool RParticleSystem::getSubEmitterModuleInheritLifetime() const { return m_SubEmitterModule->GetInheritLifetime(); } void RParticleSystem::setSubEmitterModuleInheritLifetime(bool value) { m_SubEmitterModule->SetInheritLifetime(value); } bool RParticleSystem::getSubEmitterModuleInheritDuration() const { return m_SubEmitterModule->GetInheritDuration(); } void RParticleSystem::setSubEmitterModuleInheritDuration(bool value) { m_SubEmitterModule->SetInheritDuration(value); } // m_ExternalForcesModule void RParticleSystem::setExternalForcesModuleEnabled(bool value) { m_ExternalForcesModule->SetEnabled(value); } bool RParticleSystem::getExternalForcesModuleEnabled() const { return m_ExternalForcesModule->GetEnabled(); } void RParticleSystem::setExternalForcesModuleMultiplier(float value) { m_ExternalForcesModule->SetMultiplier(value); } float RParticleSystem::getExternalForcesModuleMultiplier() const { return m_ExternalForcesModule->GetMultiplier(); } // m_RotationBySpeedModule void RParticleSystem::setRotationBySpeedModuleEnabled(bool value) { m_RotationBySpeedModule->SetEnabled(value); } bool RParticleSystem::getRotationBySpeedModuleEnabled() const { return m_RotationBySpeedModule->GetEnabled(); } void RParticleSystem::setRotationBySpeedModuleCurve(const MinMaxCurveData& value) { TransferMinMaxCurveFromData(m_RotationBySpeedModule->GetCurve(), value); } MinMaxCurveData RParticleSystem::getRotationBySpeedModuleCurve() const { MinMaxCurveData data; TransferMinMaxCurveToData(m_RotationBySpeedModule->GetCurve(), data); return data; } void RParticleSystem::setRotationBySpeedModuleRange(const Vector2f& value) { m_RotationBySpeedModule->SetRange(value); } const Vector2f& RParticleSystem::getRotationBySpeedModuleRange() const { return m_RotationBySpeedModule->GetRange(); } // m_VelocityModule void RParticleSystem::setVelocityModuleEnabled(bool value) { m_VelocityModule->SetEnabled(value); } bool RParticleSystem::getVelocityModuleEnabled() const { return m_VelocityModule->GetEnabled(); } void RParticleSystem::setVelocityModuleXCurve(const MinMaxCurveData& value) { TransferMinMaxCurveFromData(m_VelocityModule->GetXCurve(), value); } MinMaxCurveData RParticleSystem::getVelocityModuleXCurve() const { MinMaxCurveData data; TransferMinMaxCurveToData(m_VelocityModule->GetXCurve(), data); return data; } void RParticleSystem::setVelocityModuleYCurve(const MinMaxCurveData& value) { TransferMinMaxCurveFromData(m_VelocityModule->GetYCurve(), value); } MinMaxCurveData RParticleSystem::getVelocityModuleYCurve() const { MinMaxCurveData data; TransferMinMaxCurveToData(m_VelocityModule->GetYCurve(), data); return data; } void RParticleSystem::setVelocityModuleZCurve(const MinMaxCurveData& value) { TransferMinMaxCurveFromData(m_VelocityModule->GetZCurve(), value); } MinMaxCurveData RParticleSystem::getVelocityModuleZCurve() const { MinMaxCurveData data; TransferMinMaxCurveToData(m_VelocityModule->GetZCurve(), data); return data; } void RParticleSystem::setVelocityModuleInWorldSpace(bool value) { m_VelocityModule->SetInWorldSpace(value); } bool RParticleSystem::getVelocityModuleInWorldSpace() const { return m_VelocityModule->GetInWorldSpace(); } // m_ForceModule void RParticleSystem::setForceModuleEnabled(bool value) { m_ForceModule->SetEnabled(value); } bool RParticleSystem::getForceModuleEnabled() const { return m_ForceModule->GetEnabled(); } void RParticleSystem::setForceModuleXCurve(const MinMaxCurveData& value) { TransferMinMaxCurveFromData(m_ForceModule->GetXCurve(), value); } MinMaxCurveData RParticleSystem::getForceModuleXCurve() const { MinMaxCurveData data; TransferMinMaxCurveToData(m_ForceModule->GetXCurve(), data); return data; } void RParticleSystem::setForceModuleYCurve(const MinMaxCurveData& value) { TransferMinMaxCurveFromData(m_ForceModule->GetYCurve(), value); } MinMaxCurveData RParticleSystem::getForceModuleYCurve() const { MinMaxCurveData data; TransferMinMaxCurveToData(m_ForceModule->GetYCurve(), data); return data; } void RParticleSystem::setForceModuleZCurve(const MinMaxCurveData& value) { TransferMinMaxCurveFromData(m_ForceModule->GetZCurve(), value); } MinMaxCurveData RParticleSystem::getForceModuleZCurve() const { MinMaxCurveData data; TransferMinMaxCurveToData(m_ForceModule->GetZCurve(), data); return data; } void RParticleSystem::setForceModuleInWorldSpace(bool value) { m_ForceModule->SetInWorldSpace(value); } bool RParticleSystem::getForceModuleInWorldSpace() const { return m_ForceModule->GetInWorldSpace(); } void RParticleSystem::setForceModuleRandomizePerFrame(bool value) { m_ForceModule->SetRandomizePerFrame(value); } bool RParticleSystem::getForceModuleRandomizePerFrame() const { return m_ForceModule->GetRandomizePerFrame(); } // m_ClampVelocityModule void RParticleSystem::setClampVelocityModuleEnabled(bool value) { m_ClampVelocityModule->SetEnabled(value); } bool RParticleSystem::getClampVelocityModuleEnabled() const { return m_ClampVelocityModule->GetEnabled(); } void RParticleSystem::setClampVelocityModuleXCurve(const MinMaxCurveData& value) { TransferMinMaxCurveFromData(m_ClampVelocityModule->GetXCurve(), value); } MinMaxCurveData RParticleSystem::getClampVelocityModuleXCurve() const { MinMaxCurveData data; TransferMinMaxCurveToData(m_ClampVelocityModule->GetXCurve(), data); return data; } void RParticleSystem::setClampVelocityModuleYCurve(const MinMaxCurveData& value) { TransferMinMaxCurveFromData(m_ClampVelocityModule->GetYCurve(), value); } MinMaxCurveData RParticleSystem::getClampVelocityModuleYCurve() const { MinMaxCurveData data; TransferMinMaxCurveToData(m_ClampVelocityModule->GetYCurve(), data); return data; } void RParticleSystem::setClampVelocityModuleZCurve(const MinMaxCurveData& value) { TransferMinMaxCurveFromData(m_ClampVelocityModule->GetZCurve(), value); } MinMaxCurveData RParticleSystem::getClampVelocityModuleZCurve() const { MinMaxCurveData data; TransferMinMaxCurveToData(m_ClampVelocityModule->GetZCurve(), data); return data; } void RParticleSystem::setClampVelocityModuleMagnitude(const MinMaxCurveData& value) { TransferMinMaxCurveFromData(m_ClampVelocityModule->GetMagnitude(), value); } MinMaxCurveData RParticleSystem::getClampVelocityModuleMagnitude() const { MinMaxCurveData data; TransferMinMaxCurveToData(m_ClampVelocityModule->GetMagnitude(), data); return data; } void RParticleSystem::setClampVelocityModuleDrag(const MinMaxCurveData& value) { TransferMinMaxCurveFromData(m_ClampVelocityModule->GetDrag(), value); } MinMaxCurveData RParticleSystem::getClampVelocityModuleDrag() const { MinMaxCurveData data; TransferMinMaxCurveToData(m_ClampVelocityModule->GetDrag(), data); return data; } void RParticleSystem::setClampVelocityModuleInWorldSpace(bool value) { m_ClampVelocityModule->SetInWorldSpace(value); } bool RParticleSystem::getClampVelocityModuleInWorldSpace() const { return m_ClampVelocityModule->GetInWorldSpace(); } void RParticleSystem::setClampVelocityModuleSeparateAxis(bool value) { m_ClampVelocityModule->SetSeparateAxis(value); } bool RParticleSystem::getClampVelocityModuleSeparateAxis() const { return m_ClampVelocityModule->GetSeparateAxis(); } void RParticleSystem::setClampVelocityModuleMultiplyDragByParticleSize(bool value) { m_ClampVelocityModule->SetMultiplyDragByParticleSize(value); } bool RParticleSystem::getClampVelocityModuleMultiplyDragByParticleSize() const { return m_ClampVelocityModule->GetMultiplyDragByParticleSize(); } void RParticleSystem::setClampVelocityModuleMultiplyDragByParticleVelocity(bool value) { m_ClampVelocityModule->SetMultiplyDragByParticleVelocity(value); } bool RParticleSystem::getClampVelocityModuleMultiplyDragByParticleVelocity() const { return m_ClampVelocityModule->GetMultiplyDragByParticleVelocity(); } void RParticleSystem::setClampVelocityModuleDampen(float value) { m_ClampVelocityModule->SetDampen(value); } float RParticleSystem::getClampVelocityModuleDampen() const { return m_ClampVelocityModule->GetDampen(); } // m_SizeModule void RParticleSystem::setSizeModuleEnabled(bool value) { m_SizeModule->SetEnabled(value); } bool RParticleSystem::getSizeModuleEnabled() const { return m_SizeModule->GetEnabled(); } void RParticleSystem::setSizeModuleCurve(const MinMaxCurveData& value) { TransferMinMaxCurveFromData(m_SizeModule->GetCurve(), value); } MinMaxCurveData RParticleSystem::getSizeModuleCurve() const { MinMaxCurveData data; TransferMinMaxCurveToData(m_SizeModule->GetCurve(), data); return data; } // m_ColorModule void RParticleSystem::setColorModuleEnabled(bool value) { m_ColorModule->SetEnabled(value); } bool RParticleSystem::getColorModuleEnabled() const { return m_ColorModule->GetEnabled(); } void RParticleSystem::setColorModuleGradient(const MinMaxGradientData& value) { TransferMinMaxGradientFromData(m_ColorModule->GetGradient(), value); } MinMaxGradientData RParticleSystem::getColorModuleGradient() const { MinMaxGradientData data; TransferMinMaxGradientToData(m_ColorModule->GetGradient(), data); return data; } // m_UVModule void RParticleSystem::setUVModuleEnabled(bool value) { m_UVModule->SetEnabled(value); } bool RParticleSystem::getUVModuleEnabled() const { return m_UVModule->GetEnabled(); } void RParticleSystem::setUVModuleCurve(const MinMaxCurveData& value) { TransferMinMaxCurveFromData(m_UVModule->GetCurve(), value); } MinMaxCurveData RParticleSystem::getUVModuleCurve() const { MinMaxCurveData data; TransferMinMaxCurveToData(m_UVModule->GetCurve(), data); return data; } void RParticleSystem::setUVModuleTilesX(int value) { m_UVModule->SetTilesX(value); } int RParticleSystem::getUVModuleTilesX() const { return m_UVModule->GetTilesX(); } void RParticleSystem::setUVModuleTilesY(int value) { m_UVModule->SetTilesY(value); } int RParticleSystem::getUVModuleTilesY() const { return m_UVModule->GetTilesY(); } void RParticleSystem::setUVModuleAnimationType(int value) { m_UVModule->SetAnimationType(value); } int RParticleSystem::getUVModuleAnimationType() const { return m_UVModule->GetAnimationType(); } void RParticleSystem::setUVModuleRowIndex(int value) { m_UVModule->SetRowIndex(value); } int RParticleSystem::getUVModuleRowIndex() const { return m_UVModule->GetRowIndex(); } void RParticleSystem::setUVModuleCycles(float value) { m_UVModule->SetCycles(value); } float RParticleSystem::getUVModuleCycles() const { return m_UVModule->GetCycles(); } void RParticleSystem::setUVModuleRandomRow(bool value) { m_UVModule->SetRandomRow(value); } bool RParticleSystem::getUVModuleRandomRow() const { return m_UVModule->GetRandomRow(); } void RParticleSystem::setUVModuleMode(int value) { m_UVModule->SetMode(value); } int RParticleSystem::getUVModuleMode() const { return m_UVModule->GetMode(); } void RParticleSystem::setUVModuleFrameNamePrefix(const std::string& value) { m_UVModule->SetFrameNamePrefix(value); } const std::string& RParticleSystem::getUVModuleFrameNamePrefix() const { return m_UVModule->GetFrameNamePrefix(); } void RParticleSystem::setUVModuleFrameStartIndex(int value) { m_UVModule->SetFrameStartIndex(value); } int RParticleSystem::getUVModuleFrameStartIndex() const { return m_UVModule->GetFrameStartIndex(); } void RParticleSystem::setUVModuleFrameEndIndex(int value) { m_UVModule->SetFrameEndIndex(value); } int RParticleSystem::getUVModuleFrameEndIndex() const { return m_UVModule->GetFrameEndIndex(); } void RParticleSystem::setUVModuleFrameCount(int value) { m_UVModule->SetFrameCount(value); } int RParticleSystem::getUVModuleFrameCount() const { return m_UVModule->GetFrameCount(); } // m_SizeBySpeedModule void RParticleSystem::setSizeBySpeedModuleEnabled(bool value) { m_SizeBySpeedModule->SetEnabled(value); } bool RParticleSystem::getSizeBySpeedModuleEnabled() const { return m_SizeBySpeedModule->GetEnabled(); } void RParticleSystem::setSizeBySpeedModuleCurve(const MinMaxCurveData& value) { TransferMinMaxCurveFromData(m_SizeBySpeedModule->GetCurve(), value); } MinMaxCurveData RParticleSystem::getSizeBySpeedModuleCurve() const { MinMaxCurveData data; TransferMinMaxCurveToData(m_SizeBySpeedModule->GetCurve(), data); return data; } void RParticleSystem::setSizeBySpeedModuleRange(const Vector2f& value) { m_SizeBySpeedModule->SetRange(value); } const Vector2f& RParticleSystem::getSizeBySpeedModuleRange() const { return m_SizeBySpeedModule->GetRange(); } // m_ColorBySpeedModule void RParticleSystem::setColorBySpeedModuleEnabled(bool value) { m_ColorBySpeedModule->SetEnabled(value); } bool RParticleSystem::getColorBySpeedModuleEnabled() const { return m_ColorBySpeedModule->GetEnabled(); } void RParticleSystem::setColorBySpeedModuleGradient(const MinMaxGradientData& value) { TransferMinMaxGradientFromData(m_ColorBySpeedModule->GetGradient(), value); } MinMaxGradientData RParticleSystem::getColorBySpeedModuleGradient() const { MinMaxGradientData data; TransferMinMaxGradientToData(m_ColorBySpeedModule->GetGradient(), data); return data; } void RParticleSystem::setColorBySpeedModuleRange(const Vector2f& value) { m_ColorBySpeedModule->SetRange(value); } const Vector2f& RParticleSystem::getColorBySpeedModuleRange() const { return m_ColorBySpeedModule->GetRange(); } // m_renderer void RParticleSystem::setRendererOrthographic(bool value) { m_renderer->SetOrthographic(value); } bool RParticleSystem::getRendererOrthographic() const { return m_renderer->GetOrthographic(); } void RParticleSystem::setRendererScale(float value) { m_ReadOnlyState->scale = value; m_renderer->SetScale(value); } float RParticleSystem::getRendererScale() const { return m_renderer->GetScale(); } void RParticleSystem::setRendererRenderMode(int value) { m_renderer->SetRenderMode(value); } int RParticleSystem::getRendererRenderMode() const { return m_renderer->GetRenderMode(); } void RParticleSystem::setRendererSortMode(int value) { m_renderer->SetSortMode(value); } int RParticleSystem::getRendererSortMode() const { return m_renderer->GetSortMode(); } void RParticleSystem::setRendererMaxParticleSize(float value) { m_renderer->SetMaxParticleSize(value); } float RParticleSystem::getRendererMaxParticleSize() const { return m_renderer->GetMaxParticleSize(); } void RParticleSystem::setRendererCameraVelocityScale(float value) { m_renderer->SetCameraVelocityScale(value); } float RParticleSystem::getRendererCameraVelocityScale() const { return m_renderer->GetCameraVelocityScale(); } void RParticleSystem::setRendererVelocityScale(float value) { m_renderer->SetVelocityScale(value); } float RParticleSystem::getRendererVelocityScale() const { return m_renderer->GetVelocityScale(); } void RParticleSystem::setRendererLengthScale(float value) { m_renderer->SetLengthScale(value); } float RParticleSystem::getRendererLengthScale() const { return m_renderer->GetLengthScale(); } void RParticleSystem::setRendererSortingFudge(float value) { m_renderer->SetSortingFudge(value); } float RParticleSystem::getRendererSortingFudge() const { return m_renderer->GetSortingFudge(); } void RParticleSystem::setRendererNormalDirection(float value) { m_renderer->SetNormalDirection(value); } float RParticleSystem::getRendererNormalDirection() const { return m_renderer->GetNormalDirection(); } void RParticleSystem::setBlendFunc(const BlendFunc &blendFunc) { if( _blendFunc.src != blendFunc.src || _blendFunc.dst != blendFunc.dst ) { _blendFunc = blendFunc; this->updateBlendFunc(); } } void RParticleSystem::setDisplayFrame(cocos2d::SpriteFrame* spriteFrame) { if (!spriteFrame) { _texture = nullptr; return; } this->setTextureWithRect(spriteFrame->getTexture(), spriteFrame->getRect(), spriteFrame->isRotated(), spriteFrame->getOffset(), spriteFrame->getOriginalSize()); } void RParticleSystem::setTexture(cocos2d::Texture2D *texture) { if (!texture) { _texture = nullptr; return; } const Size& s = texture->getContentSize(); this->setTextureWithRect(texture, Rect(0, 0, s.width, s.height), false, Vec2::ZERO, Vec2(s.width, s.height)); } void RParticleSystem::updateBlendFunc() { if(_texture) { bool premultiplied = _texture->hasPremultipliedAlpha(); _opacityModifyRGB = false; if( _texture && ( _blendFunc.src == CC_BLEND_SRC && _blendFunc.dst == CC_BLEND_DST ) ) { if( premultiplied ) { _opacityModifyRGB = true; } else { _blendFunc = BlendFunc::ALPHA_NON_PREMULTIPLIED; } } } } void RParticleSystem::allocMemory(int particleCount) { if (particleCount > _quadCount) { if (_quads == nullptr) { _quads = (V3F_C4B_T2F_Quad*)malloc(particleCount * sizeof(V3F_C4B_T2F_Quad)); _quadCount = particleCount; } else { _quads = (V3F_C4B_T2F_Quad*)realloc(_quads, particleCount * sizeof(V3F_C4B_T2F_Quad)); _quadCount = particleCount; } if( !_quads) { CCLOG("cocos2d: RParticle system: not enough memory"); CC_SAFE_FREE(_quads); _quadCount = 0; return; } memset(_quads, 0, particleCount * sizeof(V3F_C4B_T2F_Quad)); } } NS_RRP_END