上一节我们了解了粒子系统的原理,也学习了Cocos2d-x中的两个有关粒子系统的类:
(1) CCParticleSystem :粒子系统的基类,提供对粒子的创建和更新管理。
(2) CCParticleBatchNode:粒子系统的批次结点,用于将使用相同纹理的粒子系统进行同批次渲染优化处理。
在学习CCParticleSystem时,我们留下了一些疑问,什么时候调用setBatchNode?以及做为基类,CCParticleSystem提供了两个供子类重载的纯虚函数postStep()和updateQuadWithParticle,它们的具体用法是什么?我们仍然有一些迷茫。
我们今天来了解一下CCParticleSystemQuad,这个类是CCParticleSystem的子类。它将解开我们的这些疑惑。
打开CCParticleSystemQuad.h:
- class CC_DLL CCParticleSystemQuad : public CCParticleSystem
- {
- protected:
-
- ccV3F_C4B_T2F_Quad *m_pQuads;
- GLushort *m_pIndices;
-
- #if CC_TEXTURE_ATLAS_USE_VAO
- GLuint m_uVAOname;
- #endif
- GLuint m_pBuffersVBO[2];
- public:
-
- CCParticleSystemQuad();
-
- virtual ~CCParticleSystemQuad();
-
-
- CC_DEPRECATED_ATTRIBUTE static CCParticleSystemQuad * particleWithFile(const char *plistFile);
-
-
- static CCParticleSystemQuad * create(const char *plistFile);
-
-
- void setupIndices();
-
-
- void initTexCoordsWithRect(const CCRect& rect);
-
-
- void setDisplayFrame(CCSpriteFrame *spriteFrame);
-
-
- void setTextureWithRect(CCTexture2D *texture, const CCRect& rect);
-
-
- virtual bool initWithTotalParticles(unsigned int numberOfParticles);
-
- virtual void setTexture(CCTexture2D* texture);
-
- virtual void updateQuadWithParticle(tCCParticle* particle, const CCPoint& newPosition);
-
- virtual void postStep();
-
- virtual void draw();
-
- virtual void setBatchNode(CCParticleBatchNode* batchNode);
-
- virtual void setTotalParticles(unsigned int tp);
-
- void listenBackToForeground(CCObject *obj);
-
-
- CC_DEPRECATED_ATTRIBUTE static CCParticleSystemQuad * node();
-
- static CCParticleSystemQuad * create();
- private:
-
- #if CC_TEXTURE_ATLAS_USE_VAO
-
- void setupVBOandVAO();
- #else
-
- void setupVBO();
- #endif
-
- bool allocMemory();
- };
对应的实现:
-
- bool CCParticleSystemQuad::initWithTotalParticles(unsigned int numberOfParticles)
- {
-
- if( CCParticleSystem::initWithTotalParticles(numberOfParticles) )
- {
-
- if( ! this->allocMemory() ) {
- this->release();
- return false;
- }
-
- setupIndices();
-
- #if CC_TEXTURE_ATLAS_USE_VAO
- setupVBOandVAO();
- #else
- setupVBO();
- #endif
-
- setShaderProgram(CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionTextureColor));
-
-
-
- CCNotificationCenter::sharedNotificationCenter()->addObserver(this,
- callfuncO_selector(CCParticleSystemQuad::listenBackToForeground),
- EVNET_COME_TO_FOREGROUND,
- NULL);
-
- return true;
- }
- return false;
- }
-
- CCParticleSystemQuad::CCParticleSystemQuad()
- :m_pQuads(NULL)
- ,m_pIndices(NULL)
- #if CC_TEXTURE_ATLAS_USE_VAO
- ,m_uVAOname(0)
- #endif
- {
- memset(m_pBuffersVBO, 0, sizeof(m_pBuffersVBO));
- }
-
- CCParticleSystemQuad::~CCParticleSystemQuad()
- {
-
- if (NULL == m_pBatchNode)
- {
- CC_SAFE_FREE(m_pQuads);
- CC_SAFE_FREE(m_pIndices);
- glDeleteBuffers(2, &m_pBuffersVBO[0]);
- #if CC_TEXTURE_ATLAS_USE_VAO
- glDeleteVertexArrays(1, &m_uVAOname);
- #endif
- }
-
-
- CCNotificationCenter::sharedNotificationCenter()->removeObserver(this, EVNET_COME_TO_FOREGROUND);
- }
-
-
- CCParticleSystemQuad * CCParticleSystemQuad::particleWithFile(const char *plistFile)
- {
- return CCParticleSystemQuad::create(plistFile);
- }
-
- CCParticleSystemQuad * CCParticleSystemQuad::create(const char *plistFile)
- {
-
- CCParticleSystemQuad *pRet = new CCParticleSystemQuad();
- if (pRet && pRet->initWithFile(plistFile))
- {
- pRet->autorelease();
- return pRet;
- }
-
- CC_SAFE_DELETE(pRet);
- return pRet;
- }
-
-
- void CCParticleSystemQuad::initTexCoordsWithRect(const CCRect& pointRect)
- {
-
- CCRect rect = CCRectMake(
- 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());
-
- GLfloat wide = (GLfloat) pointRect.size.width;
- GLfloat high = (GLfloat) pointRect.size.height;
-
- if (m_pTexture)
- {
- wide = (GLfloat)m_pTexture->getPixelsWide();
- high = (GLfloat)m_pTexture->getPixelsHigh();
- }
-
- #if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
- GLfloat left = (rect.origin.x*2+1) / (wide*2);
- GLfloat bottom = (rect.origin.y*2+1) / (high*2);
- GLfloat right = left + (rect.size.width*2-2) / (wide*2);
- GLfloat top = bottom + (rect.size.height*2-2) / (high*2);
- #else
- GLfloat left = rect.origin.x / wide;
- GLfloat bottom = rect.origin.y / high;
- GLfloat right = left + rect.size.width / wide;
- GLfloat top = bottom + rect.size.height / high;
- #endif
-
-
- CC_SWAP( top, bottom, float);
-
- ccV3F_C4B_T2F_Quad *quads = NULL;
- unsigned int start = 0, end = 0;
- if (m_pBatchNode)
- {
- quads = m_pBatchNode->getTextureAtlas()->getQuads();
-
- start = m_uAtlasIndex;
- end = m_uAtlasIndex + m_uTotalParticles;
- }
- else
- {
- quads = m_pQuads;
- start = 0;
- end = m_uTotalParticles;
- }
-
- for(unsigned int i=start; i<end; i++)
- {
-
- quads[i].bl.texCoords.u = left;
- quads[i].bl.texCoords.v = bottom;
- quads[i].br.texCoords.u = right;
- quads[i].br.texCoords.v = bottom;
- quads[i].tl.texCoords.u = left;
- quads[i].tl.texCoords.v = top;
- quads[i].tr.texCoords.u = right;
- quads[i].tr.texCoords.v = top;
- }
- }
-
- void CCParticleSystemQuad::setTextureWithRect(CCTexture2D *texture, const CCRect& rect)
- {
-
- if( !m_pTexture || texture->getName() != m_pTexture->getName() )
- {
- CCParticleSystem::setTexture(texture);
- }
-
- this->initTexCoordsWithRect(rect);
- }
-
- void CCParticleSystemQuad::setTexture(CCTexture2D* texture)
- {
-
- const CCSize& s = texture->getContentSize();
-
- this->setTextureWithRect(texture, CCRectMake(0, 0, s.width, s.height));
- }
-
- void CCParticleSystemQuad::setDisplayFrame(CCSpriteFrame *spriteFrame)
- {
-
- CCAssert(spriteFrame->getOffsetInPixels().equals(CCPointZero),
- "QuadParticle only supports SpriteFrames with no offsets");
-
-
- if ( !m_pTexture || spriteFrame->getTexture()->getName() != m_pTexture->getName())
- {
-
- this->setTexture(spriteFrame->getTexture());
- }
- }
-
- void CCParticleSystemQuad::setupIndices()
- {
-
- for(unsigned int i = 0; i < m_uTotalParticles; ++i)
- {
- const unsigned int i6 = i*6;
- const unsigned int i4 = i*4;
- m_pIndices[i6+0] = (GLushort) i4+0;
- m_pIndices[i6+1] = (GLushort) i4+1;
- m_pIndices[i6+2] = (GLushort) i4+2;
-
- m_pIndices[i6+5] = (GLushort) i4+1;
- m_pIndices[i6+4] = (GLushort) i4+2;
- m_pIndices[i6+3] = (GLushort) i4+3;
- }
- }
-
- void CCParticleSystemQuad::updateQuadWithParticle(tCCParticle* particle, const CCPoint& newPosition)
- {
-
- ccV3F_C4B_T2F_Quad *quad;
-
- if (m_pBatchNode)
- {
-
- ccV3F_C4B_T2F_Quad *batchQuads = m_pBatchNode->getTextureAtlas()->getQuads();
-
- quad = &(batchQuads[m_uAtlasIndex+particle->atlasIndex]);
- }
- else
- {
-
- quad = &(m_pQuads[m_uParticleIdx]);
- }
-
- ccColor4B color = (m_bOpacityModifyRGB)
- ccc4( particle->color.r*particle->color.a*255, particle->color.g*particle->color.a*255, particle->color.b*particle->color.a*255, particle->color.a*255)
- : ccc4( particle->color.r*255, particle->color.g*255, particle->color.b*255, particle->color.a*255);
-
- quad->bl.colors = color;
- quad->br.colors = color;
- quad->tl.colors = color;
- quad->tr.colors = color;
-
-
- GLfloat size_2 = particle->size/2;
-
- if (particle->rotation)
- {
-
- GLfloat x1 = -size_2;
- GLfloat y1 = -size_2;
-
- GLfloat x2 = size_2;
- GLfloat y2 = size_2;
-
- GLfloat x = newPosition.x;
- GLfloat y = newPosition.y;
-
- GLfloat r = (GLfloat)-CC_DEGREES_TO_RADIANS(particle->rotation);
-
- GLfloat cr = cosf(r);
- GLfloat sr = sinf(r);
- GLfloat ax = x1 * cr - y1 * sr + x;
- GLfloat ay = x1 * sr + y1 * cr + y;
- GLfloat bx = x2 * cr - y1 * sr + x;
- GLfloat by = x2 * sr + y1 * cr + y;
- GLfloat cx = x2 * cr - y2 * sr + x;
- GLfloat cy = x2 * sr + y2 * cr + y;
- GLfloat dx = x1 * cr - y2 * sr + x;
- GLfloat dy = x1 * sr + y2 * cr + y;
-
-
- quad->bl.vertices.x = ax;
- quad->bl.vertices.y = ay;
- quad->br.vertices.x = bx;
- quad->br.vertices.y = by;
- quad->tl.vertices.x = dx;
- quad->tl.vertices.y = dy;
- quad->tr.vertices.x = cx;
- quad->tr.vertices.y = cy;
- }
- else
- {
-
- quad->bl.vertices.x = newPosition.x - size_2;
- quad->bl.vertices.y = newPosition.y - size_2;
- quad->br.vertices.x = newPosition.x + size_2;
- quad->br.vertices.y = newPosition.y - size_2;
- quad->tl.vertices.x = newPosition.x - size_2;
- quad->tl.vertices.y = newPosition.y + size_2;
- quad->tr.vertices.x = newPosition.x + size_2;
- quad->tr.vertices.y = newPosition.y + size_2;
- }
- }
-
- void CCParticleSystemQuad::postStep()
- {
-
- glBindBuffer(GL_ARRAY_BUFFER, m_pBuffersVBO[0] );
-
- glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(m_pQuads[0])*m_uParticleCount, m_pQuads);
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- CHECK_GL_ERROR_DEBUG();
-
- }
-
-
- void CCParticleSystemQuad::draw()
- {
-
- CCAssert(!m_pBatchNode,"draw should not be called when added to a particleBatchNode");
-
- CC_NODE_DRAW_SETUP();
-
- ccGLBindTexture2D( m_pTexture->getName() );
-
- ccGLBlendFunc( m_tBlendFunc.src, m_tBlendFunc.dst );
-
- CCAssert( m_uParticleIdx == m_uParticleCount, "Abnormal error in particle quad");
-
- #if CC_TEXTURE_ATLAS_USE_VAO
-
- glBindVertexArray( m_uVAOname );
-
- #if CC_REBIND_INDICES_BUFFER
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_pBuffersVBO[1]);
- #endif
-
- glDrawElements(GL_TRIANGLES, (GLsizei) m_uParticleIdx*6, GL_UNSIGNED_SHORT, 0);
-
- #if CC_REBIND_INDICES_BUFFER
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- #endif
-
- glBindVertexArray( 0 );
-
- #else
-
-
-
-
- #define kQuadSize sizeof(m_pQuads[0].bl)
-
- ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex );
-
- glBindBuffer(GL_ARRAY_BUFFER, m_pBuffersVBO[0]);
-
- glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, vertices));
-
- glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, colors));
-
- glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, texCoords));
-
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_pBuffersVBO[1]);
-
- glDrawElements(GL_TRIANGLES, (GLsizei) m_uParticleIdx*6, GL_UNSIGNED_SHORT, 0);
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-
- #endif
-
- CC_INCREMENT_GL_DRAWS(1);
- CHECK_GL_ERROR_DEBUG();
- }
-
- void CCParticleSystemQuad::setTotalParticles(unsigned int tp)
- {
-
- if( tp > m_uAllocatedParticles )
- {
-
-
- size_t particlesSize = tp * sizeof(tCCParticle);
-
- size_t quadsSize = sizeof(m_pQuads[0]) * tp * 1;
-
- size_t indicesSize = sizeof(m_pIndices[0]) * tp * 6 * 1;
-
- tCCParticle* particlesNew = (tCCParticle*)realloc(m_pParticles, particlesSize);
-
- ccV3F_C4B_T2F_Quad* quadsNew = (ccV3F_C4B_T2F_Quad*)realloc(m_pQuads, quadsSize);
-
- GLushort* indicesNew = (GLushort*)realloc(m_pIndices, indicesSize);
-
- if (particlesNew && quadsNew && indicesNew)
- {
-
- m_pParticles = particlesNew;
- m_pQuads = quadsNew;
- m_pIndices = indicesNew;
-
-
- memset(m_pParticles, 0, particlesSize);
- memset(m_pQuads, 0, quadsSize);
- memset(m_pIndices, 0, indicesSize);
-
- m_uAllocatedParticles = tp;
- }
- else
- {
-
- if (particlesNew) m_pParticles = particlesNew;
- if (quadsNew) m_pQuads = quadsNew;
- if (indicesNew) m_pIndices = indicesNew;
-
- CCLOG("Particle system: out of memory");
- return;
- }
-
- m_uTotalParticles = tp;
-
-
- if (m_pBatchNode)
- {
- for (unsigned int i = 0; i < m_uTotalParticles; i++)
- {
- m_pParticles[i].atlasIndex=i;
- }
- }
-
- setupIndices();
-
- #if CC_TEXTURE_ATLAS_USE_VAO
- setupVBOandVAO();
- #else
-
- setupVBO();
- #endif
- }
- else
- {
-
- m_uTotalParticles = tp;
- }
- }
-
- #if CC_TEXTURE_ATLAS_USE_VAO
-
- void CCParticleSystemQuad::setupVBOandVAO()
- {
- glGenVertexArrays(1, &m_uVAOname);
-
- glBindVertexArray(m_uVAOname);
-
- #define kQuadSize sizeof(m_pQuads[0].bl)
-
- glGenBuffers(2, &m_pBuffersVBO[0]);
-
- glBindBuffer(GL_ARRAY_BUFFER, m_pBuffersVBO[0]);
-
- glBufferData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0]) * m_uTotalParticles, m_pQuads, GL_DYNAMIC_DRAW);
-
-
- glEnableVertexAttribArray(kCCVertexAttrib_Position);
-
- glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, vertices));
-
-
- glEnableVertexAttribArray(kCCVertexAttrib_Color);
-
- glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, colors));
-
-
- glEnableVertexAttribArray(kCCVertexAttrib_TexCoords);
-
- glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, texCoords));
-
-
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_pBuffersVBO[1]);
-
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_pIndices[0]) * m_uTotalParticles * 6, m_pIndices, GL_STATIC_DRAW);
-
- glBindVertexArray(0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-
- CHECK_GL_ERROR_DEBUG();
- }
- #else
-
- void CCParticleSystemQuad::setupVBO()
- {
-
- glGenBuffers(2, &m_pBuffersVBO[0]);
-
- glBindBuffer(GL_ARRAY_BUFFER, m_pBuffersVBO[0]);
- glBufferData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0]) * m_uTotalParticles, m_pQuads, GL_DYNAMIC_DRAW);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_pBuffersVBO[1]);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_pIndices[0]) * m_uTotalParticles * 6, m_pIndices, GL_STATIC_DRAW);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-
- CHECK_GL_ERROR_DEBUG();
- }
-
- #endif
-
- void CCParticleSystemQuad::listenBackToForeground(CCObject *obj)
- {
-
- #if CC_TEXTURE_ATLAS_USE_VAO
- setupVBOandVAO();
- #else
- setupVBO();
- #endif
- }
-
- bool CCParticleSystemQuad::allocMemory()
- {
-
- CCAssert( ( !m_pQuads && !m_pIndices), "Memory already alloced");
- CCAssert( !m_pBatchNode, "Memory should not be alloced when not using batchNode");
-
- CC_SAFE_FREE(m_pQuads);
- CC_SAFE_FREE(m_pIndices);
-
- m_pQuads = (ccV3F_C4B_T2F_Quad*)malloc(m_uTotalParticles * sizeof(ccV3F_C4B_T2F_Quad));
- m_pIndices = (GLushort*)malloc(m_uTotalParticles * 6 * sizeof(GLushort));
-
- if( !m_pQuads || !m_pIndices)
- {
- CCLOG("cocos2d: Particle system: not enough memory");
- CC_SAFE_FREE(m_pQuads);
- CC_SAFE_FREE(m_pIndices);
-
- return false;
- }
-
- memset(m_pQuads, 0, m_uTotalParticles * sizeof(ccV3F_C4B_T2F_Quad));
- memset(m_pIndices, 0, m_uTotalParticles * 6 * sizeof(GLushort));
-
- return true;
- }
-
- void CCParticleSystemQuad::setBatchNode(CCParticleBatchNode * batchNode)
- {
-
- if( m_pBatchNode != batchNode )
- {
-
- CCParticleBatchNode* oldBatch = m_pBatchNode;
-
- CCParticleSystem::setBatchNode(batchNode);
-
-
- if( ! batchNode )
- {
-
- allocMemory();
- setupIndices();
- setTexture(oldBatch->getTexture());
- #if CC_TEXTURE_ATLAS_USE_VAO
- setupVBOandVAO();
- #else
- setupVBO();
- #endif
- }
-
- else if( !oldBatch )
- {
-
- ccV3F_C4B_T2F_Quad *batchQuads = m_pBatchNode->getTextureAtlas()->getQuads();
- ccV3F_C4B_T2F_Quad *quad = &(batchQuads[m_uAtlasIndex] );
- memcpy( quad, m_pQuads, m_uTotalParticles * sizeof(m_pQuads[0]) );
-
- CC_SAFE_FREE(m_pQuads);
- CC_SAFE_FREE(m_pIndices);
-
- glDeleteBuffers(2, &m_pBuffersVBO[0]);
- #if CC_TEXTURE_ATLAS_USE_VAO
- glDeleteVertexArrays(1, &m_uVAOname);
- #endif
- }
- }
- }
-
- CCParticleSystemQuad * CCParticleSystemQuad::node()
- {
- return CCParticleSystemQuad::create();
- }
-
- CCParticleSystemQuad * CCParticleSystemQuad::create() {
-
- CCParticleSystemQuad *pParticleSystemQuad = new CCParticleSystemQuad();
-
- if (pParticleSystemQuad && pParticleSystemQuad->init())
- {
- pParticleSystemQuad->autorelease();
- return pParticleSystemQuad;
- }
-
- CC_SAFE_DELETE(pParticleSystemQuad);
- return NULL;
- }
总结: 类CCParticleSystemQuad的源码进一步完善了粒子系统的功能,使我们可以在不需要批次结点时也能够实现粒子系统的OPENGL顶点和索引缓冲的创建和渲染,这么看来CCParticleSystem是一个不完整的粒子系统的类,它只提供了使用粒子批次结点的粒子系统的渲染方案。
到这里,我们基本算领悟了Cocos2d-x中粒子系统的完整功能基类。后面我们将由此进入到多彩的粒子系统的演示中去!下课~
|