初始化

This commit is contained in:
SmallMain
2022-06-25 00:23:03 +08:00
commit ef0589e8e5
2264 changed files with 617829 additions and 0 deletions

View File

@@ -0,0 +1,508 @@
/****************************************************************************
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos2d-x.org
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 "ParticleSimulator.h"
#include "base/ccRandom.h"
#include <algorithm>
#include "base/ccMacros.h"
#include "math/Mat4.h"
#include "MiddlewareManager.h"
#include "middleware-adapter.h"
#include "renderer/scene/assembler/CustomAssembler.hpp"
#include "math/Vec2.h"
USING_NS_MW;
NS_CC_BEGIN
// global particle pool
static ParticlePool _pool;
// particleSystem max step delta time
static const float _maxParticleDeltaTime = 0.0333f;
void Particle::reset()
{
pos = cocos2d::Vec3::ZERO;
startPos = cocos2d::Vec3::ZERO;
color = cocos2d::Color4F::BLACK;
deltaColor = cocos2d::Color4F::BLACK;
size = 0;
deltaSize = 0;
rotation = 0;
deltaRotation = 0;
timeToLive = 0;
drawPos = cocos2d::Vec3::ZERO;
// Mode A
dir = cocos2d::Vec3::ZERO;
radialAccel = 0;
tangentialAccel = 0;
// Mode B
angle = 0;
degreesPerSecond = 0;
radius = 0;
deltaRadius = 0;
}
ParticlePool::ParticlePool()
{
}
ParticlePool::~ParticlePool()
{
for (auto particle : _pool)
{
delete particle;
}
_pool.clear();
}
ParticleSimulator::ParticleSimulator()
{
}
ParticleSimulator::~ParticleSimulator()
{
onDisable();
CC_SAFE_RELEASE(_effect);
CC_SAFE_RELEASE(_nodeProxy);
for (auto particle : _particles)
{
delete particle;
}
_particles.clear();
}
void ParticleSimulator::stop()
{
_active = false;
_readyToPlay = false;
_elapsed = duration;
_emitCounter = 0;
}
void ParticleSimulator::reset()
{
_active = true;
_readyToPlay = true;
_elapsed = 0;
_emitCounter = 0;
_finished = false;
for (auto particle : _particles)
{
_pool.put(particle);
}
_particles.clear();
}
void ParticleSimulator::emitParticle(cocos2d::Vec3 &pos)
{
auto& particle = *_pool.get();
_particles.push_back(&particle);
// Init particle
// timeToLive
// no negative life. prevent division by 0
particle.timeToLive = life + lifeVar * random(-1.0f, 1.0f);
// avoid divide zero
float timeToLive = particle.timeToLive = std::max(0.001f, particle.timeToLive);
// position
particle.pos.x = _sourcePos.x + _posVar.x * random(-1.0f, 1.0f);
particle.pos.y = _sourcePos.y + _posVar.y * random(-1.0f, 1.0f);
// Color
GLubyte sr, sg, sb, sa;
particle.color.r = sr = clampf(_startColor.r + _startColorVar.r * random(-1.0f, 1.0f), 0, 255);
particle.color.g = sg = clampf(_startColor.g + _startColorVar.g * random(-1.0f, 1.0f), 0, 255);
particle.color.b = sb = clampf(_startColor.b + _startColorVar.b * random(-1.0f, 1.0f), 0, 255);
particle.color.a = sa = clampf(_startColor.a + _startColorVar.a * random(-1.0f, 1.0f), 0, 255);
particle.deltaColor.r = (clampf(_endColor.r + _endColorVar.r * random(-1.0f, 1.0f), 0, 255) - sr) / timeToLive;
particle.deltaColor.g = (clampf(_endColor.g + _endColorVar.g * random(-1.0f, 1.0f), 0, 255) - sg) / timeToLive;
particle.deltaColor.b = (clampf(_endColor.b + _endColorVar.b * random(-1.0f, 1.0f), 0, 255) - sb) / timeToLive;
particle.deltaColor.a = (clampf(_endColor.a + _endColorVar.a * random(-1.0f, 1.0f), 0, 255) - sa) / timeToLive;
// size
float startS = startSize + startSizeVar * random(-1.0f, 1.0f);
startS = std::max(0.0f, startS); // No negative value
particle.size = startS;
if (endSize == START_SIZE_EQUAL_TO_END_SIZE)
{
particle.deltaSize = 0;
}
else
{
float endS = endSize + endSizeVar * random(-1.0f, 1.0f);
endS = std::max(0.0f, endS); // No negative values
particle.deltaSize = (endS - startS) / timeToLive;
}
// rotation
float startA = startSpin + startSpinVar * random(-1.0f, 1.0f);
float endA = endSpin + endSpinVar * random(-1.0f, 1.0f);
particle.rotation = startA;
particle.deltaRotation = (endA - startA) / timeToLive;
// position
particle.startPos.x = pos.x;
particle.startPos.y = pos.y;
// direction
float a = CC_DEGREES_TO_RADIANS(angle + _worldRotation + angleVar * random(-1.0f, 1.0f));
// Mode Gravity: A
if (emitterMode == EmitterMode::GRAVITY)
{
float s = speed + speedVar * random(-1.0f, 1.0f);
// direction
particle.dir.x = cos(a);
particle.dir.y = sin(a);
particle.dir.scale(s);
// radial accel
particle.radialAccel = radialAccel + radialAccelVar * random(-1.0f, 1.0f);
// tangential accel
particle.tangentialAccel = tangentialAccel + tangentialAccelVar * random(-1.0f, 1.0f);
// rotation is dir
if (rotationIsDir)
{
particle.rotation = -CC_RADIANS_TO_DEGREES(atan2(particle.dir.y, particle.dir.x));
}
}
// Mode Radius: B
else
{
// Set the default diameter of the particle from the source position
float tempStartRadius = startRadius + startRadiusVar * random(-1.0f, 1.0f);
float tempEndRadius = endRadius + endRadiusVar * random(-1.0f, 1.0f);
particle.radius = tempStartRadius;
particle.deltaRadius = (endRadius == START_RADIUS_EQUAL_TO_END_RADIUS) ? 0 : (tempEndRadius - tempStartRadius) / timeToLive;
particle.angle = a;
particle.degreesPerSecond = CC_DEGREES_TO_RADIANS(rotatePerS + rotatePerSVar * random(-1.0f, 1.0f));
}
}
void ParticleSimulator::onEnable()
{
MiddlewareManager::getInstance()->addTimer(this);
}
void ParticleSimulator::onDisable()
{
MiddlewareManager::getInstance()->removeTimer(this);
}
void ParticleSimulator::render(float dt)
{
dt = dt > _maxParticleDeltaTime ? _maxParticleDeltaTime : dt;
if (_finished || _nodeProxy == nullptr || _effect == nullptr)
{
return;
}
// uv size must equal 8,because per particle has 4 vertex.
if (_uv.size() != 8)
{
return;
}
renderer::CustomAssembler* assembler = (renderer::CustomAssembler*)_nodeProxy->getAssembler();
if (assembler == nullptr)
{
return;
}
assembler->reset();
assembler->updateEffect(0, _effect);
// avoid other place call update.
auto mgr = MiddlewareManager::getInstance();
if (!mgr->isRendering) return;
middleware::MeshBuffer* mb = mgr->getMeshBuffer(VF_XYUVC);
middleware::IOBuffer& vb = mb->getVB();
middleware::IOBuffer& ib = mb->getIB();
cocos2d::Vec3 pos;
cocos2d::Vec3 tpa;
cocos2d::Vec3 tpb;
cocos2d::Vec3 tpc;
Quaternion tempQuat;
Vec3 tempEuler;
if (positionType == PositionType::FREE)
{
// FREE MODE's CC_USE_MODEL flag is false, so must manual calculate global rotation to get emit direction
_nodeProxy->getWorldRotation(&tempQuat);
tempQuat.toEuler(&tempEuler);
_worldRotation = tempEuler.z;
// 'pos' is used to move particle to node's current position
auto& worldMat = _nodeProxy->getWorldMatrix();
auto& wm = worldMat.m;
pos.x = wm[12];
pos.y = wm[13];
assembler->setUseModel(false);
}
// RELATIVE MODE is about 'parent node is group mode' but 'current node is free mode'
else if (positionType == PositionType::RELATIVE)
{
_nodeProxy->getRotation(&tempQuat);
tempQuat.toEuler(&tempEuler);
_worldRotation = tempEuler.z;
_nodeProxy->getPosition(&pos);
assembler->setUseModel(true);
auto parent = _nodeProxy->getParent();
if (parent)
{
auto& parentWorldMat = parent->getWorldMatrix();
assembler->setCustomWorldMatrix(parentWorldMat);
}
else
{
assembler->setCustomWorldMatrix(cocos2d::Mat4::IDENTITY);
}
}
// GROUP MODE
else
{
_worldRotation = 0;
assembler->setUseModel(true);
// use node world matrix instead
assembler->clearCustomWorldMatirx();
}
// Emission
if (_active && emissionRate)
{
float rate = 1.0 / emissionRate;
//issue #1201, prevent bursts of particles, due to too high emitCounter
if (_particles.size() < totalParticles)
_emitCounter += dt;
while ((_particles.size() < totalParticles) && (_emitCounter > rate))
{
emitParticle(pos);
_emitCounter -= rate;
}
_elapsed += dt;
if (duration != -1 && duration < _elapsed)
{
_stopCallback();
}
}
// Used to reduce memory allocation / creation within the loop
std::size_t particleIdx = 0;
std::size_t particleSize = _particles.size();
vb.checkSpace(particleSize * 4 * sizeof (middleware::V2F_T2F_C4B));
ib.checkSpace(particleSize * 6 * sizeof (unsigned short));
std::size_t vbOffset = vb.getCurPos() / sizeof (middleware::V2F_T2F_C4B);
uint32_t indexStart = (uint32_t)ib.getCurPos()/sizeof(unsigned short);
uint32_t indexCount = 0;
while (particleIdx < particleSize)
{
// Reset temporary vectors
tpa.x = tpa.y = tpb.x = tpb.y = tpc.x = tpc.y = 0;
auto& particle = *_particles[particleIdx];
// life
particle.timeToLive -= dt;
if (particle.timeToLive > 0)
{
// Mode A: gravity, direction, tangential accel & radial accel
if (emitterMode == EmitterMode::GRAVITY)
{
auto& tmp = tpc;
auto& radial = tpa;
auto& tangential = tpb;
// radial acceleration
if (particle.pos.x || particle.pos.y)
{
radial.set(particle.pos);
radial.normalize();
}
tangential.set(radial);
radial.scale(particle.radialAccel);
// tangential acceleration
auto newy = tangential.x;
tangential.x = -tangential.y;
tangential.y = newy;
tangential.scale(particle.tangentialAccel);
tmp.set(radial);
tmp.add(tangential);
tmp.add(_gravity.x, _gravity.y, _gravity.z);
tmp.scale(dt);
particle.dir.add(tmp);
tmp.set(particle.dir);
tmp.scale(dt);
particle.pos.add(tmp);
}
// Mode B: radius movement
else
{
// Update the angle and radius of the particle.
particle.angle += particle.degreesPerSecond * dt;
particle.radius += particle.deltaRadius * dt;
particle.pos.x = -cos(particle.angle) * particle.radius;
particle.pos.y = -sin(particle.angle) * particle.radius;
}
// color
auto& color = particle.color;
auto& deltaColor = particle.deltaColor;
color.r = clampf(color.r + deltaColor.r * dt, 0, 255);
color.g = clampf(color.g + deltaColor.g * dt, 0, 255);
color.b = clampf(color.b + deltaColor.b * dt, 0, 255);
color.a = clampf(color.a + deltaColor.a * dt, 0, 255);
// size
particle.size += particle.deltaSize * dt;
if (particle.size < 0)
{
particle.size = 0;
}
// angle
particle.rotation += particle.deltaRotation * dt;
// update values in quad buffer
auto& newPos = tpa;
newPos.set(particle.pos);
// free and relative mode need move particle to origin position by manual
if (positionType != PositionType::GROUPED)
{
newPos.add(particle.startPos);
}
auto x = newPos.x, y = newPos.y;
auto width = particle.size;
auto height = width;
if (aspectRatio > 1.0f)
{
height = width / aspectRatio;
}
else
{
width = height * aspectRatio;
}
auto halfW = width * 0.5;
auto halfH = height * 0.5;
auto x1 = -halfW, y1 = -halfH;
auto x2 = halfW, y2 = halfH;
auto rad = -CC_DEGREES_TO_RADIANS(particle.rotation);
auto cr = cos(rad), sr = sin(rad);
uint32_t tempColor = (((GLuint)particle.color.a << 24) & 0xff000000) +
(((GLuint)particle.color.b << 16) & 0x00ff0000) +
(((GLuint)particle.color.g << 8) & 0x0000ff00) +
(((GLuint)particle.color.r) & 0x000000ff);
// bl
vb.writeFloat32(x1 * cr - y1 * sr + x);
vb.writeFloat32(x1 * sr + y1 * cr + y);
vb.writeFloat32(_uv[0]);
vb.writeFloat32(_uv[1]);
vb.writeUint32(tempColor);
// br
vb.writeFloat32(x2 * cr - y1 * sr + x);
vb.writeFloat32(x2 * sr + y1 * cr + y);
vb.writeFloat32(_uv[2]);
vb.writeFloat32(_uv[3]);
vb.writeUint32(tempColor);
// tl
vb.writeFloat32(x1 * cr - y2 * sr + x);
vb.writeFloat32(x1 * sr + y2 * cr + y);
vb.writeFloat32(_uv[4]);
vb.writeFloat32(_uv[5]);
vb.writeUint32(tempColor);
// tr
vb.writeFloat32(x2 * cr - y2 * sr + x);
vb.writeFloat32(x2 * sr + y2 * cr + y);
vb.writeFloat32(_uv[6]);
vb.writeFloat32(_uv[7]);
vb.writeUint32(tempColor);
ib.writeUint16(vbOffset);
ib.writeUint16(vbOffset + 1);
ib.writeUint16(vbOffset + 2);
ib.writeUint16(vbOffset + 1);
ib.writeUint16(vbOffset + 3);
ib.writeUint16(vbOffset + 2);
vbOffset += 4;
indexCount += 6;
// update particle counter
++particleIdx;
}
else
{
// life < 0
auto deadParticle = _particles[particleIdx];
if (particleIdx != particleSize - 1)
{
_particles[particleIdx] = _particles[particleSize - 1];
}
_pool.put(deadParticle);
particleSize--;
_particles.resize(particleSize);
}
}
assembler->updateIABuffer(0, mb->getGLVB(), mb->getGLIB());
assembler->updateIARange(0, indexStart, indexCount);
if (_particles.size() == 0 && !_active && !_readyToPlay)
{
_finished = true;
if (_finishedCallback)
{
_finishedCallback();
}
}
}
uint32_t ParticleSimulator::getRenderOrder() const
{
if (!_nodeProxy) return 0;
return _nodeProxy->getRenderOrder();
}
NS_CC_END

View File

@@ -0,0 +1,287 @@
/****************************************************************************
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos2d-x.org
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.
****************************************************************************/
#pragma once
#include "MiddlewareMacro.h"
#include "math/Vec3.h"
#include "base/ccTypes.h"
#include <vector>
#include "IOBuffer.h"
#include "renderer/scene/NodeProxy.hpp"
#include "renderer/renderer/EffectVariant.hpp"
#include "MiddlewareManager.h"
#include "scripting/js-bindings/jswrapper/SeApi.h"
NS_CC_BEGIN
struct Particle {
public:
cocos2d::Vec3 pos;
cocos2d::Vec3 startPos;
cocos2d::Color4F color = cocos2d::Color4F::BLACK;
cocos2d::Color4F deltaColor = cocos2d::Color4F::BLACK;
float size = 0.0f;
float deltaSize = 0.0f;
float rotation = 0.0f;
float deltaRotation = 0.0f;
float timeToLive = 0.0f;
cocos2d::Vec3 drawPos;
// Mode A
cocos2d::Vec3 dir;
float radialAccel = 0.0f;
float tangentialAccel = 0.0f;
// Mode B
float angle = 0.0f;
float degreesPerSecond = 0.0f;
float radius = 0.0f;
float deltaRadius = 0.0f;
bool inPool = false;
void reset();
};
class ParticlePool {
public:
ParticlePool();
~ParticlePool();
void put(Particle* particle)
{
CCASSERT(!particle->inPool, "Particle is in pool already");
_pool.push_back(particle);
particle->inPool = true;
particle->reset();
}
Particle* get()
{
Particle* obj = nullptr;
if (_pool.size() > 0)
{
obj = _pool.back();
_pool.pop_back();
obj->inPool = false;
} else {
obj = new Particle();
}
return obj;
}
private:
std::vector<Particle*> _pool;
};
enum PositionType
{
FREE = 0,
RELATIVE = 1,
GROUPED = 2
};
enum EmitterMode
{
GRAVITY = 0,
RADIUS = 1
};
class ParticleSimulator : public cocos2d::middleware::IMiddleware, public cocos2d::Ref {
//* @enum
enum {
/** The Particle emitter lives forever. */
DURATION_INFINITY = -1,
/** The starting size of the particle is equal to the ending size. */
START_SIZE_EQUAL_TO_END_SIZE = -1,
/** The starting radius of the particle is equal to the ending radius. */
START_RADIUS_EQUAL_TO_END_RADIUS = -1,
};
public:
ParticleSimulator();
~ParticleSimulator();
virtual void update(float dt) override {}
virtual void render(float dt) override;
virtual uint32_t getRenderOrder() const override;
void stop();
void reset();
void emitParticle(cocos2d::Vec3& pos);
void onEnable();
void onDisable();
typedef std::function<void()> finishedCallback;
void setFinishedCallback(finishedCallback callback)
{
_finishedCallback = callback;
}
typedef std::function<void()> stopCallback;
void setStopCallback(stopCallback callback)
{
_stopCallback = callback;
}
void bindNodeProxy(cocos2d::renderer::NodeProxy* node)
{
CC_SAFE_RELEASE(_nodeProxy);
_nodeProxy = node;
CC_SAFE_RETAIN(_nodeProxy);
}
void setEffect(cocos2d::renderer::EffectVariant* effect)
{
CC_SAFE_RELEASE(_effect);
_effect = effect;
CC_SAFE_RETAIN(_effect);
}
void updateUVs(const std::vector<float>& uv)
{
_uv = uv;
}
std::size_t getParticleCount()
{
return _particles.size();
}
bool active()
{
return _active;
}
void setGravity(float x, float y, float z)
{
_gravity.x = x;
_gravity.y = y;
_gravity.z = z;
}
void setSourcePos(float x, float y, float z)
{
_sourcePos.x = x;
_sourcePos.y = y;
_sourcePos.z = z;
}
void setPosVar(float x, float y, float z)
{
_posVar.x = x;
_posVar.y = y;
_posVar.z = z;
}
void setStartColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a)
{
_startColor.r = r;
_startColor.g = g;
_startColor.b = b;
_startColor.a = a;
}
void setStartColorVar(GLubyte r, GLubyte g, GLubyte b, GLubyte a)
{
_startColorVar.r = r;
_startColorVar.g = g;
_startColorVar.b = b;
_startColorVar.a = a;
}
void setEndColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a)
{
_endColor.r = r;
_endColor.g = g;
_endColor.b = b;
_endColor.a = a;
}
void setEndColorVar(GLubyte r, GLubyte g, GLubyte b, GLubyte a)
{
_endColorVar.r = r;
_endColorVar.g = g;
_endColorVar.b = b;
_endColorVar.a = a;
}
private:
std::vector<Particle*> _particles;
bool _active = false;
bool _readyToPlay = true;
bool _finished = false;
float _elapsed = 0;
float _emitCounter = 0;
float _worldRotation = 0;
std::size_t _uvFilled = 0;
finishedCallback _finishedCallback = nullptr;
stopCallback _stopCallback = nullptr;
cocos2d::renderer::NodeProxy* _nodeProxy = nullptr;
std::vector<float> _uv;
cocos2d::renderer::EffectVariant* _effect = nullptr;
cocos2d::Vec3 _gravity;
cocos2d::Vec3 _sourcePos;
cocos2d::Vec3 _posVar;
cocos2d::Color4B _startColor = cocos2d::Color4B::BLACK;
cocos2d::Color4B _startColorVar = cocos2d::Color4B::WHITE;
cocos2d::Color4B _endColor = cocos2d::Color4B::BLACK;
cocos2d::Color4B _endColorVar = cocos2d::Color4B::WHITE;
public:
int positionType = PositionType::FREE;
float emissionRate = 0.0f;
std::size_t totalParticles = 0;
float duration = -1.0f;
int emitterMode = EmitterMode::GRAVITY;
float life = 0.0f;
float lifeVar = 0.0f;
float startSize = 0.0f;
float startSizeVar = 0.0f;
float endSize = 0.0f;
float endSizeVar = 0.0f;
float startSpin = 0.0f;
float startSpinVar = 0.0f;
float endSpin = 0.0f;
float endSpinVar = 0.0f;
float angle = 0.0f;
float angleVar = 0.0f;
float speed = 0.0f;
float speedVar = 0.0f;
float radialAccel = 0.0f;
float radialAccelVar = 0.0f;
float tangentialAccel = 0.0f;
float tangentialAccelVar = 0.0f;
bool rotationIsDir = false;
float startRadius = 0.0f;
float startRadiusVar = 0.0f;
float endRadius = 0.0f;
float endRadiusVar = 0.0f;
float rotatePerS = 0.0f;
float rotatePerSVar = 0.0f;
float aspectRatio = 1.0f;
};
NS_CC_END