2019-11-23 20:27:39 +08:00
/****************************************************************************
Copyright ( c ) 2008 - 2010 Ricardo Quesada
Copyright ( c ) 2009 Leonardo Kasperavičius
Copyright ( c ) 2010 - 2012 cocos2d - x . org
Copyright ( c ) 2011 Zynga Inc .
Copyright ( c ) 2013 - 2016 Chukong Technologies Inc .
Copyright ( c ) 2017 - 2018 Xiamen Yaji Software Co . , Ltd .
2022-01-04 12:36:20 +08:00
https : //adxeproject.github.io/
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
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 "2d/CCParticleSystemQuad.h"
# include <algorithm>
2021-12-25 10:04:45 +08:00
# include <stddef.h> // offsetof
2019-11-23 20:27:39 +08:00
# include "base/ccTypes.h"
# include "2d/CCSpriteFrame.h"
# include "2d/CCParticleBatchNode.h"
# include "renderer/CCTextureAtlas.h"
# include "renderer/CCRenderer.h"
# include "base/CCDirector.h"
# include "base/CCEventType.h"
# include "base/CCConfiguration.h"
# include "base/CCEventListenerCustom.h"
# include "base/CCEventDispatcher.h"
# include "base/ccUTF8.h"
# include "renderer/ccShaders.h"
# include "renderer/backend/ProgramState.h"
NS_CC_BEGIN
ParticleSystemQuad : : ParticleSystemQuad ( )
{
2020-10-26 14:49:14 +08:00
auto & pipelinePS = _quadCommand . getPipelineDescriptor ( ) . programState ;
2021-12-25 10:04:45 +08:00
auto * program = backend : : Program : : getBuiltinProgram ( backend : : ProgramType : : POSITION_TEXTURE_COLOR ) ;
2020-10-26 14:49:14 +08:00
//!!! support etc1 with alpha?
2021-12-08 00:11:53 +08:00
pipelinePS = ( new backend : : ProgramState ( program ) ) ;
2020-10-26 14:49:14 +08:00
_mvpMatrixLocaiton = pipelinePS - > getUniformLocation ( " u_MVPMatrix " ) ;
2021-12-25 10:04:45 +08:00
_textureLocation = pipelinePS - > getUniformLocation ( " u_texture " ) ;
auto vertexLayout = pipelinePS - > getVertexLayout ( ) ;
2020-10-26 14:49:14 +08:00
const auto & attributeInfo = pipelinePS - > getProgram ( ) - > getActiveAttributes ( ) ;
2021-12-25 10:04:45 +08:00
auto iter = attributeInfo . find ( " a_position " ) ;
if ( iter ! = attributeInfo . end ( ) )
2019-11-23 20:27:39 +08:00
{
vertexLayout - > setAttribute ( " a_position " , iter - > second . location , backend : : VertexFormat : : FLOAT3 , 0 , false ) ;
}
iter = attributeInfo . find ( " a_texCoord " ) ;
2021-12-25 10:04:45 +08:00
if ( iter ! = attributeInfo . end ( ) )
2019-11-23 20:27:39 +08:00
{
2021-12-25 10:04:45 +08:00
vertexLayout - > setAttribute ( " a_texCoord " , iter - > second . location , backend : : VertexFormat : : FLOAT2 ,
offsetof ( V3F_C4B_T2F , texCoords ) , false ) ;
2019-11-23 20:27:39 +08:00
}
iter = attributeInfo . find ( " a_color " ) ;
2021-12-25 10:04:45 +08:00
if ( iter ! = attributeInfo . end ( ) )
2019-11-23 20:27:39 +08:00
{
2021-12-25 10:04:45 +08:00
vertexLayout - > setAttribute ( " a_color " , iter - > second . location , backend : : VertexFormat : : UBYTE4 ,
offsetof ( V3F_C4B_T2F , colors ) , true ) ;
2019-11-23 20:27:39 +08:00
}
vertexLayout - > setLayout ( sizeof ( V3F_C4B_T2F ) ) ;
}
ParticleSystemQuad : : ~ ParticleSystemQuad ( )
{
if ( nullptr = = _batchNode )
{
CC_SAFE_FREE ( _quads ) ;
CC_SAFE_FREE ( _indices ) ;
}
2020-10-26 14:49:14 +08:00
CC_SAFE_RELEASE_NULL ( _quadCommand . getPipelineDescriptor ( ) . programState ) ;
2019-11-23 20:27:39 +08:00
}
// implementation ParticleSystemQuad
2021-12-31 12:12:40 +08:00
ParticleSystemQuad * ParticleSystemQuad : : create ( std : : string_view filename )
2019-11-23 20:27:39 +08:00
{
2021-12-25 10:04:45 +08:00
ParticleSystemQuad * ret = new ParticleSystemQuad ( ) ;
2021-12-08 00:11:53 +08:00
if ( ret - > initWithFile ( filename ) )
2019-11-23 20:27:39 +08:00
{
ret - > autorelease ( ) ;
return ret ;
}
CC_SAFE_DELETE ( ret ) ;
return ret ;
}
2021-12-25 10:04:45 +08:00
ParticleSystemQuad * ParticleSystemQuad : : createWithTotalParticles ( int numberOfParticles )
{
2022-05-26 20:56:56 +08:00
CCASSERT ( numberOfParticles < = 10000 , " Adding more than 10000 particles will crash the renderer, the mesh generated has an index format of U_SHORT (uint16_t) " ) ;
2021-12-25 10:04:45 +08:00
ParticleSystemQuad * ret = new ParticleSystemQuad ( ) ;
2021-12-08 00:11:53 +08:00
if ( ret - > initWithTotalParticles ( numberOfParticles ) )
2019-11-23 20:27:39 +08:00
{
ret - > autorelease ( ) ;
return ret ;
}
CC_SAFE_DELETE ( ret ) ;
return ret ;
}
2021-12-25 10:04:45 +08:00
ParticleSystemQuad * ParticleSystemQuad : : create ( ValueMap & dictionary )
2019-11-23 20:27:39 +08:00
{
2021-12-25 10:04:45 +08:00
ParticleSystemQuad * ret = new ParticleSystemQuad ( ) ;
2021-12-08 00:11:53 +08:00
if ( ret - > initWithDictionary ( dictionary ) )
2019-11-23 20:27:39 +08:00
{
ret - > autorelease ( ) ;
return ret ;
}
CC_SAFE_DELETE ( ret ) ;
return ret ;
}
2021-12-25 10:04:45 +08:00
// implementation ParticleSystemQuad
// overriding the init method
2019-11-23 20:27:39 +08:00
bool ParticleSystemQuad : : initWithTotalParticles ( int numberOfParticles )
{
// base initialization
2021-12-25 10:04:45 +08:00
if ( ParticleSystem : : initWithTotalParticles ( numberOfParticles ) )
2019-11-23 20:27:39 +08:00
{
// allocating data space
2021-12-25 10:04:45 +08:00
if ( ! this - > allocMemory ( ) )
{
2019-11-23 20:27:39 +08:00
this - > release ( ) ;
return false ;
}
initIndices ( ) ;
2021-12-25 10:04:45 +08:00
// setupVBO();
2019-11-23 20:27:39 +08:00
# if CC_ENABLE_CACHE_TEXTURE_DATA
// Need to listen the event only when not use batchnode, because it will use VBO
2021-12-25 10:04:45 +08:00
auto listener = EventListenerCustom : : create ( EVENT_RENDERER_RECREATED ,
CC_CALLBACK_1 ( ParticleSystemQuad : : listenRendererRecreated , this ) ) ;
2019-11-23 20:27:39 +08:00
_eventDispatcher - > addEventListenerWithSceneGraphPriority ( listener , this ) ;
# endif
return true ;
}
return false ;
}
// pointRect should be in Texture coordinates, not pixel coordinates
void ParticleSystemQuad : : initTexCoordsWithRect ( const Rect & pointRect )
{
// convert to Tex coords
2021-12-25 10:04:45 +08:00
Rect rect =
Rect ( pointRect . origin . x * CC_CONTENT_SCALE_FACTOR ( ) , pointRect . origin . y * CC_CONTENT_SCALE_FACTOR ( ) ,
pointRect . size . width * CC_CONTENT_SCALE_FACTOR ( ) , pointRect . size . height * CC_CONTENT_SCALE_FACTOR ( ) ) ;
2019-11-23 20:27:39 +08:00
2021-12-25 10:04:45 +08:00
float wide = ( float ) pointRect . size . width ;
float high = ( float ) pointRect . size . height ;
2019-11-23 20:27:39 +08:00
if ( _texture )
{
wide = ( float ) _texture - > getPixelsWide ( ) ;
high = ( float ) _texture - > getPixelsHigh ( ) ;
}
# if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
2021-12-25 10:04:45 +08:00
float left = ( rect . origin . x * 2 + 1 ) / ( wide * 2 ) ;
float bottom = ( rect . origin . y * 2 + 1 ) / ( high * 2 ) ;
float right = left + ( rect . size . width * 2 - 2 ) / ( wide * 2 ) ;
float top = bottom + ( rect . size . height * 2 - 2 ) / ( high * 2 ) ;
2019-11-23 20:27:39 +08:00
# else
2021-12-25 10:04:45 +08:00
float left = rect . origin . x / wide ;
2019-11-23 20:27:39 +08:00
float bottom = rect . origin . y / high ;
2021-12-25 10:04:45 +08:00
float right = left + rect . size . width / wide ;
float top = bottom + rect . size . height / high ;
# endif // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
2019-11-23 20:27:39 +08:00
// Important. Texture in cocos2d are inverted, so the Y component should be inverted
std : : swap ( top , bottom ) ;
2021-12-25 10:04:45 +08:00
V3F_C4B_T2F_Quad * quads = nullptr ;
2019-11-23 20:27:39 +08:00
unsigned int start = 0 , end = 0 ;
if ( _batchNode )
{
quads = _batchNode - > getTextureAtlas ( ) - > getQuads ( ) ;
start = _atlasIndex ;
2021-12-25 10:04:45 +08:00
end = _atlasIndex + _totalParticles ;
2019-11-23 20:27:39 +08:00
}
else
{
quads = _quads ;
start = 0 ;
2021-12-25 10:04:45 +08:00
end = _totalParticles ;
2019-11-23 20:27:39 +08:00
}
2021-12-25 10:04:45 +08:00
for ( unsigned int i = start ; i < end ; i + + )
2019-11-23 20:27:39 +08:00
{
// bottom-left vertex:
quads [ i ] . bl . texCoords . u = left ;
quads [ i ] . bl . texCoords . v = bottom ;
// bottom-right vertex:
quads [ i ] . br . texCoords . u = right ;
quads [ i ] . br . texCoords . v = bottom ;
// top-left vertex:
quads [ i ] . tl . texCoords . u = left ;
quads [ i ] . tl . texCoords . v = top ;
// top-right vertex:
quads [ i ] . tr . texCoords . u = right ;
quads [ i ] . tr . texCoords . v = top ;
}
}
void ParticleSystemQuad : : updateTexCoords ( )
{
if ( _texture )
{
2021-10-23 23:27:14 +08:00
const Vec2 & s = _texture - > getContentSize ( ) ;
2019-11-23 20:27:39 +08:00
initTexCoordsWithRect ( Rect ( 0 , 0 , s . width , s . height ) ) ;
}
}
2021-12-25 10:04:45 +08:00
void ParticleSystemQuad : : setTextureWithRect ( Texture2D * texture , const Rect & rect )
2019-11-23 20:27:39 +08:00
{
// Only update the texture if is different from the current one
2021-12-25 10:04:45 +08:00
if ( ! _texture | | texture - > getBackendTexture ( ) ! = _texture - > getBackendTexture ( ) )
2019-11-23 20:27:39 +08:00
{
ParticleSystem : : setTexture ( texture ) ;
auto programState = _quadCommand . getPipelineDescriptor ( ) . programState ;
programState - > setTexture ( _texture - > getBackendTexture ( ) ) ;
}
this - > initTexCoordsWithRect ( rect ) ;
}
void ParticleSystemQuad : : setTexture ( Texture2D * texture )
{
2021-10-23 23:27:14 +08:00
const Vec2 & s = texture - > getContentSize ( ) ;
2019-11-23 20:27:39 +08:00
this - > setTextureWithRect ( texture , Rect ( 0 , 0 , s . width , s . height ) ) ;
}
2021-12-25 10:04:45 +08:00
void ParticleSystemQuad : : setDisplayFrame ( SpriteFrame * spriteFrame )
2019-11-23 20:27:39 +08:00
{
2021-12-25 10:04:45 +08:00
CCASSERT ( spriteFrame - > getOffsetInPixels ( ) . isZero ( ) , " QuadParticle only supports SpriteFrames with no offsets " ) ;
2019-11-23 20:27:39 +08:00
this - > setTextureWithRect ( spriteFrame - > getTexture ( ) , spriteFrame - > getRect ( ) ) ;
}
void ParticleSystemQuad : : initIndices ( )
{
2021-12-25 10:04:45 +08:00
for ( int i = 0 ; i < _totalParticles ; + + i )
2019-11-23 20:27:39 +08:00
{
2021-12-25 10:04:45 +08:00
const unsigned int i6 = i * 6 ;
const unsigned int i4 = i * 4 ;
_indices [ i6 + 0 ] = ( unsigned short ) i4 + 0 ;
_indices [ i6 + 1 ] = ( unsigned short ) i4 + 1 ;
_indices [ i6 + 2 ] = ( unsigned short ) i4 + 2 ;
_indices [ i6 + 5 ] = ( unsigned short ) i4 + 1 ;
_indices [ i6 + 4 ] = ( unsigned short ) i4 + 2 ;
_indices [ i6 + 3 ] = ( unsigned short ) i4 + 3 ;
2019-11-23 20:27:39 +08:00
}
}
2022-05-26 20:56:56 +08:00
inline void updatePosWithParticle ( V3F_C4B_T2F_Quad * quad ,
const Vec2 & newPosition ,
float size ,
float rotation ,
float staticRotation )
2019-11-23 20:27:39 +08:00
{
// vertices
2021-12-25 10:04:45 +08:00
float size_2 = size / 2 ;
float x1 = - size_2 ;
float y1 = - size_2 ;
2019-11-23 20:27:39 +08:00
float x2 = size_2 ;
float y2 = size_2 ;
2021-12-25 10:04:45 +08:00
float x = newPosition . x ;
float y = newPosition . y ;
2022-05-26 20:56:56 +08:00
float r = ( float ) - CC_DEGREES_TO_RADIANS ( rotation + staticRotation ) ;
2019-11-23 20:27:39 +08:00
float cr = cosf ( r ) ;
float sr = sinf ( r ) ;
float ax = x1 * cr - y1 * sr + x ;
float ay = x1 * sr + y1 * cr + y ;
float bx = x2 * cr - y1 * sr + x ;
float by = x2 * sr + y1 * cr + y ;
float cx = x2 * cr - y2 * sr + x ;
float cy = x2 * sr + y2 * cr + y ;
float dx = x1 * cr - y2 * sr + x ;
float dy = x1 * sr + y2 * cr + y ;
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
// bottom-left
quad - > bl . vertices . x = ax ;
quad - > bl . vertices . y = ay ;
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
// bottom-right vertex:
quad - > br . vertices . x = bx ;
quad - > br . vertices . y = by ;
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
// top-left vertex:
quad - > tl . vertices . x = dx ;
quad - > tl . vertices . y = dy ;
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
// top-right vertex:
quad - > tr . vertices . x = cx ;
quad - > tr . vertices . y = cy ;
}
void ParticleSystemQuad : : updateParticleQuads ( )
{
2021-12-25 10:04:45 +08:00
if ( _particleCount < = 0 )
{
2019-11-23 20:27:39 +08:00
return ;
}
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
Vec2 currentPosition ;
if ( _positionType = = PositionType : : FREE )
{
currentPosition = this - > convertToWorldSpace ( Vec2 : : ZERO ) ;
}
else if ( _positionType = = PositionType : : RELATIVE )
{
currentPosition = _position ;
}
2021-12-25 10:04:45 +08:00
V3F_C4B_T2F_Quad * startQuad ;
2019-11-23 20:27:39 +08:00
Vec2 pos = Vec2 : : ZERO ;
if ( _batchNode )
{
2021-12-25 10:04:45 +08:00
V3F_C4B_T2F_Quad * batchQuads = _batchNode - > getTextureAtlas ( ) - > getQuads ( ) ;
startQuad = & ( batchQuads [ _atlasIndex ] ) ;
pos = _position ;
2019-11-23 20:27:39 +08:00
}
else
{
startQuad = & ( _quads [ 0 ] ) ;
}
2021-12-25 10:04:45 +08:00
if ( _positionType = = PositionType : : FREE )
2019-11-23 20:27:39 +08:00
{
Vec3 p1 ( currentPosition . x , currentPosition . y , 0 ) ;
Mat4 worldToNodeTM = getWorldToNodeTransform ( ) ;
worldToNodeTM . transformPoint ( & p1 ) ;
Vec3 p2 ;
Vec2 newPos ;
2022-05-26 20:56:56 +08:00
float * startX = _particleData . startPosX ;
float * startY = _particleData . startPosY ;
float * x = _particleData . posx ;
float * y = _particleData . posy ;
float * s = _particleData . size ;
float * r = _particleData . rotation ;
float * sr = _particleData . staticRotation ;
2019-11-23 20:27:39 +08:00
V3F_C4B_T2F_Quad * quadStart = startQuad ;
2022-05-26 20:56:56 +08:00
for ( int i = 0 ; i < _particleCount ; + + i , + + startX , + + startY , + + x , + + y , + + quadStart , + + s , + + r , + + sr )
2019-11-23 20:27:39 +08:00
{
p2 . set ( * startX , * startY , 0 ) ;
worldToNodeTM . transformPoint ( & p2 ) ;
2021-12-25 10:04:45 +08:00
newPos . set ( * x , * y ) ;
2019-11-23 20:27:39 +08:00
p2 = p1 - p2 ;
newPos . x - = p2 . x - pos . x ;
newPos . y - = p2 . y - pos . y ;
2022-05-26 20:56:56 +08:00
updatePosWithParticle ( quadStart , newPos , * s , * r , * sr ) ;
2019-11-23 20:27:39 +08:00
}
}
2021-12-25 10:04:45 +08:00
else if ( _positionType = = PositionType : : RELATIVE )
2019-11-23 20:27:39 +08:00
{
Vec2 newPos ;
2021-12-25 10:04:45 +08:00
float * startX = _particleData . startPosX ;
float * startY = _particleData . startPosY ;
float * x = _particleData . posx ;
float * y = _particleData . posy ;
float * s = _particleData . size ;
float * r = _particleData . rotation ;
2022-05-26 20:56:56 +08:00
float * sr = _particleData . staticRotation ;
2019-11-23 20:27:39 +08:00
V3F_C4B_T2F_Quad * quadStart = startQuad ;
2022-05-26 20:56:56 +08:00
for ( int i = 0 ; i < _particleCount ; + + i , + + startX , + + startY , + + x , + + y , + + quadStart , + + s , + + r , + + sr )
2019-11-23 20:27:39 +08:00
{
newPos . set ( * x , * y ) ;
newPos . x = * x - ( currentPosition . x - * startX ) ;
newPos . y = * y - ( currentPosition . y - * startY ) ;
newPos + = pos ;
2022-05-26 20:56:56 +08:00
updatePosWithParticle ( quadStart , newPos , * s , * r , * sr ) ;
2019-11-23 20:27:39 +08:00
}
}
else
{
Vec2 newPos ;
2021-12-25 10:04:45 +08:00
float * startX = _particleData . startPosX ;
float * startY = _particleData . startPosY ;
float * x = _particleData . posx ;
float * y = _particleData . posy ;
float * s = _particleData . size ;
float * r = _particleData . rotation ;
2022-05-26 20:56:56 +08:00
float * sr = _particleData . staticRotation ;
2019-11-23 20:27:39 +08:00
V3F_C4B_T2F_Quad * quadStart = startQuad ;
2022-05-26 20:56:56 +08:00
for ( int i = 0 ; i < _particleCount ; + + i , + + startX , + + startY , + + x , + + y , + + quadStart , + + s , + + r , + + sr )
2019-11-23 20:27:39 +08:00
{
newPos . set ( * x + pos . x , * y + pos . y ) ;
2022-05-26 20:56:56 +08:00
updatePosWithParticle ( quadStart , newPos , * s , * r , * sr ) ;
2019-11-23 20:27:39 +08:00
}
}
2021-12-25 10:04:45 +08:00
2022-05-26 20:56:56 +08:00
V3F_C4B_T2F_Quad * quad = startQuad ;
float * r = _particleData . colorR ;
float * g = _particleData . colorG ;
float * b = _particleData . colorB ;
float * a = _particleData . colorA ;
// HSV calculation is expensive, so we should skip it if it's not enabled.
if ( _isHsv )
2019-11-23 20:27:39 +08:00
{
2022-05-26 20:56:56 +08:00
float * hue = _particleData . hue ;
float * sat = _particleData . sat ;
float * val = _particleData . val ;
2022-05-21 21:56:56 +08:00
2022-05-26 20:56:56 +08:00
if ( _opacityModifyRGB )
{
auto hsv = HSV ( ) ;
for ( int i = 0 ; i < _particleCount ; + + i , + + quad , + + r , + + g , + + b , + + a , + + hue , + + sat , + + val )
{
float colorR = * r * * a ;
float colorG = * g * * a ;
float colorB = * b * * a ;
float colorA = * a ;
hsv . set ( colorR , colorG , colorB , colorA ) ;
hsv . h + = * hue ;
hsv . s = abs ( * sat ) ;
hsv . v = abs ( * val ) ;
auto col = hsv . toColor4B ( ) ;
quad - > bl . colors . set ( col . r , col . g , col . b , col . a ) ;
quad - > br . colors . set ( col . r , col . g , col . b , col . a ) ;
quad - > tl . colors . set ( col . r , col . g , col . b , col . a ) ;
quad - > tr . colors . set ( col . r , col . g , col . b , col . a ) ;
}
}
else
2019-11-23 20:27:39 +08:00
{
2022-05-26 20:56:56 +08:00
auto hsv = HSV ( ) ;
for ( int i = 0 ; i < _particleCount ; + + i , + + quad , + + r , + + g , + + b , + + a , + + hue , + + sat , + + val )
{
float colorR = * r ;
float colorG = * g ;
float colorB = * b ;
float colorA = * a ;
hsv . set ( colorR , colorG , colorB , colorA ) ;
hsv . h + = * hue ;
hsv . s = abs ( * sat ) ;
hsv . v = abs ( * val ) ;
auto col = hsv . toColor4B ( ) ;
quad - > bl . colors . set ( col . r , col . g , col . b , col . a ) ;
quad - > br . colors . set ( col . r , col . g , col . b , col . a ) ;
quad - > tl . colors . set ( col . r , col . g , col . b , col . a ) ;
quad - > tr . colors . set ( col . r , col . g , col . b , col . a ) ;
}
2019-11-23 20:27:39 +08:00
}
}
else
{
2022-05-26 20:56:56 +08:00
// set color
if ( _opacityModifyRGB )
{
for ( int i = 0 ; i < _particleCount ; + + i , + + quad , + + r , + + g , + + b , + + a )
{
uint8_t colorR = * r * * a * 255 ;
uint8_t colorG = * g * * a * 255 ;
uint8_t colorB = * b * * a * 255 ;
uint8_t colorA = * a * 255 ;
quad - > bl . colors . set ( colorR , colorG , colorB , colorA ) ;
quad - > br . colors . set ( colorR , colorG , colorB , colorA ) ;
quad - > tl . colors . set ( colorR , colorG , colorB , colorA ) ;
quad - > tr . colors . set ( colorR , colorG , colorB , colorA ) ;
}
}
else
{
for ( int i = 0 ; i < _particleCount ; + + i , + + quad , + + r , + + g , + + b , + + a )
{
uint8_t colorR = * r * 255 ;
uint8_t colorG = * g * 255 ;
uint8_t colorB = * b * 255 ;
uint8_t colorA = * a * 255 ;
quad - > bl . colors . set ( colorR , colorG , colorB , colorA ) ;
quad - > br . colors . set ( colorR , colorG , colorB , colorA ) ;
quad - > tl . colors . set ( colorR , colorG , colorB , colorA ) ;
quad - > tr . colors . set ( colorR , colorG , colorB , colorA ) ;
}
}
}
// The reason for using for-loops separately for every property is because
// When the processor needs to read from or write to a location in memory,
// it first checks whether a copy of that data is in the cpu's cache.
// And wether if every property's memory of the particle system is continuous,
// for the purpose of improving cache hit rate, we should process only one property in one for-loop.
// It was proved to be effective especially for low-end devices.
if ( _isLifeAnimated | | _isEmitterAnimated | | _isLoopAnimated | | _isAnimAllocated )
{
V3F_C4B_T2F_Quad * quad = startQuad ;
unsigned short * cellIndex = _particleData . animCellIndex ;
2022-05-25 15:46:54 +08:00
2022-05-26 20:56:56 +08:00
ParticleFrameDescriptor index ;
for ( int i = 0 ; i < _particleCount ; + + i , + + quad , + + cellIndex )
2022-05-25 15:20:35 +08:00
{
2022-05-26 20:56:56 +08:00
float left = 0.0F , bottom = 0.0F , top = 1.0F , right = 1.0F ;
// TODO: index.isRotated should be treated accordingly
auto iter = _animationIndices . find ( * cellIndex ) ;
if ( iter = = _animationIndices . end ( ) )
index . rect = { 0 , 0 , float ( _texture - > getPixelsWide ( ) ) , float ( _texture - > getPixelsHigh ( ) ) } ;
else
index = iter - > second ;
auto texWidth = _texture - > getPixelsWide ( ) ;
auto texHeight = _texture - > getPixelsHigh ( ) ;
left = index . rect . origin . x / texWidth ;
right = ( index . rect . origin . x + index . rect . size . x ) / texWidth ;
top = index . rect . origin . y / texHeight ;
bottom = ( index . rect . origin . y + index . rect . size . y ) / texHeight ;
quad - > bl . texCoords . u = left ;
quad - > bl . texCoords . v = bottom ;
quad - > br . texCoords . u = right ;
quad - > br . texCoords . v = bottom ;
quad - > tl . texCoords . u = left ;
quad - > tl . texCoords . v = top ;
quad - > tr . texCoords . u = right ;
quad - > tr . texCoords . v = top ;
2022-05-25 15:20:35 +08:00
}
}
2019-11-23 20:27:39 +08:00
}
// overriding draw method
2021-12-25 10:04:45 +08:00
void ParticleSystemQuad : : draw ( Renderer * renderer , const Mat4 & transform , uint32_t flags )
2019-11-23 20:27:39 +08:00
{
2021-12-25 10:04:45 +08:00
// quad command
if ( _particleCount > 0 )
2019-11-23 20:27:39 +08:00
{
auto programState = _quadCommand . getPipelineDescriptor ( ) . programState ;
2021-04-22 22:01:47 +08:00
cocos2d : : Mat4 projectionMat = _director - > getMatrix ( MATRIX_STACK_TYPE : : MATRIX_STACK_PROJECTION ) ;
2019-11-23 20:27:39 +08:00
programState - > setUniform ( _mvpMatrixLocaiton , projectionMat . m , sizeof ( projectionMat . m ) ) ;
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
_quadCommand . init ( _globalZOrder , _texture , _blendFunc , _quads , _particleCount , transform , flags ) ;
renderer - > addCommand ( & _quadCommand ) ;
}
}
void ParticleSystemQuad : : setTotalParticles ( int tp )
{
// If we are setting the total number of particles to a number higher
// than what is allocated, we need to allocate new arrays
2021-12-25 10:04:45 +08:00
if ( tp > _allocatedParticles )
2019-11-23 20:27:39 +08:00
{
// Allocate new memory
2021-12-25 10:04:45 +08:00
size_t quadsSize = sizeof ( _quads [ 0 ] ) * tp * 1 ;
2019-11-23 20:27:39 +08:00
size_t indicesSize = sizeof ( _indices [ 0 ] ) * tp * 6 * 1 ;
_particleData . release ( ) ;
if ( ! _particleData . init ( tp ) )
{
CCLOG ( " Particle system: not enough memory " ) ;
return ;
}
V3F_C4B_T2F_Quad * quadsNew = ( V3F_C4B_T2F_Quad * ) realloc ( _quads , quadsSize ) ;
unsigned short * indicesNew = ( unsigned short * ) realloc ( _indices , indicesSize ) ;
if ( quadsNew & & indicesNew )
{
// Assign pointers
2021-12-25 10:04:45 +08:00
_quads = quadsNew ;
2019-11-23 20:27:39 +08:00
_indices = indicesNew ;
// Clear the memory
memset ( _quads , 0 , quadsSize ) ;
memset ( _indices , 0 , indicesSize ) ;
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
_allocatedParticles = tp ;
}
else
{
// Out of memory, failed to resize some array
2021-12-25 10:04:45 +08:00
if ( quadsNew )
_quads = quadsNew ;
if ( indicesNew )
_indices = indicesNew ;
2019-11-23 20:27:39 +08:00
CCLOG ( " Particle system: out of memory " ) ;
return ;
}
_totalParticles = tp ;
// Init particles
if ( _batchNode )
{
for ( int i = 0 ; i < _totalParticles ; i + + )
{
_particleData . atlasIndex [ i ] = i ;
}
}
initIndices ( ) ;
2021-12-25 10:04:45 +08:00
// setupVBO();
2022-01-04 12:36:20 +08:00
// fixed https://adxeproject.github.io//issues/3990
2019-11-23 20:27:39 +08:00
// Updates texture coords.
updateTexCoords ( ) ;
}
else
{
_totalParticles = tp ;
}
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
// fixed issue #5762
// reset the emission rate
setEmissionRate ( _totalParticles / _life ) ;
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
resetSystem ( ) ;
}
void ParticleSystemQuad : : listenRendererRecreated ( EventCustom * /*event*/ )
{
2021-12-25 10:04:45 +08:00
// when comes to foreground in android, _buffersVBO and _VAOname is a wild handle
// before recreating, we need to reset them to 0
// memset(_buffersVBO, 0, sizeof(_buffersVBO));
// if (Configuration::getInstance()->supportsShareableVAO())
// {
// _VAOname = 0;
// setupVBOandVAO();
// }
// else
// {
// setupVBO();
// }
2019-11-23 20:27:39 +08:00
}
bool ParticleSystemQuad : : allocMemory ( )
{
2021-12-25 10:04:45 +08:00
CCASSERT ( ! _batchNode , " Memory should not be alloced when not using batchNode " ) ;
2019-11-23 20:27:39 +08:00
CC_SAFE_FREE ( _quads ) ;
CC_SAFE_FREE ( _indices ) ;
2021-12-25 10:04:45 +08:00
_quads = ( V3F_C4B_T2F_Quad * ) malloc ( _totalParticles * sizeof ( V3F_C4B_T2F_Quad ) ) ;
2019-11-23 20:27:39 +08:00
_indices = ( unsigned short * ) malloc ( _totalParticles * 6 * sizeof ( unsigned short ) ) ;
2021-12-25 10:04:45 +08:00
if ( ! _quads | | ! _indices )
2019-11-23 20:27:39 +08:00
{
CCLOG ( " cocos2d: Particle system: not enough memory " ) ;
CC_SAFE_FREE ( _quads ) ;
CC_SAFE_FREE ( _indices ) ;
return false ;
}
memset ( _quads , 0 , _totalParticles * sizeof ( V3F_C4B_T2F_Quad ) ) ;
memset ( _indices , 0 , _totalParticles * 6 * sizeof ( unsigned short ) ) ;
return true ;
}
2021-12-25 10:04:45 +08:00
void ParticleSystemQuad : : setBatchNode ( ParticleBatchNode * batchNode )
2019-11-23 20:27:39 +08:00
{
2021-12-25 10:04:45 +08:00
if ( _batchNode ! = batchNode )
2019-11-23 20:27:39 +08:00
{
ParticleBatchNode * oldBatch = _batchNode ;
ParticleSystem : : setBatchNode ( batchNode ) ;
// NEW: is self render ?
2021-12-25 10:04:45 +08:00
if ( ! batchNode )
2019-11-23 20:27:39 +08:00
{
allocMemory ( ) ;
initIndices ( ) ;
setTexture ( oldBatch - > getTexture ( ) ) ;
2021-12-25 10:04:45 +08:00
// setupVBO();
2019-11-23 20:27:39 +08:00
}
// OLD: was it self render ? cleanup
2021-12-25 10:04:45 +08:00
else if ( ! oldBatch )
2019-11-23 20:27:39 +08:00
{
// copy current state to batch
2021-12-25 10:04:45 +08:00
V3F_C4B_T2F_Quad * batchQuads = _batchNode - > getTextureAtlas ( ) - > getQuads ( ) ;
V3F_C4B_T2F_Quad * quad = & ( batchQuads [ _atlasIndex ] ) ;
memcpy ( quad , _quads , _totalParticles * sizeof ( _quads [ 0 ] ) ) ;
2019-11-23 20:27:39 +08:00
CC_SAFE_FREE ( _quads ) ;
CC_SAFE_FREE ( _indices ) ;
}
}
}
2021-12-25 10:04:45 +08:00
ParticleSystemQuad * ParticleSystemQuad : : create ( )
{
ParticleSystemQuad * particleSystemQuad = new ParticleSystemQuad ( ) ;
2021-12-08 00:11:53 +08:00
if ( particleSystemQuad - > init ( ) )
2019-11-23 20:27:39 +08:00
{
particleSystemQuad - > autorelease ( ) ;
return particleSystemQuad ;
}
CC_SAFE_DELETE ( particleSystemQuad ) ;
return nullptr ;
}
std : : string ParticleSystemQuad : : getDescription ( ) const
{
return StringUtils : : format ( " <ParticleSystemQuad | Tag = %d, Total Particles = %d> " , _tag , _totalParticles ) ;
}
NS_CC_END