// override visit // don't call visit on it's children void SpriteBatchNode::visit(void) { CC_PROFILER_START_CATEGORY(kProfilerCategoryBatchSprite, "CCSpriteBatchNode - visit"); // CAREFUL: // This visit is almost identical to CocosNode#visit // with the exception that it doesn't call visit on it's children // // The alternative is to have a void Sprite#visit, but // although this is less maintainable, is faster // if (! _visible) { return; } kmGLPushMatrix(); sortAllChildren(); transform(); draw(); kmGLPopMatrix(); setOrderOfArrival(0); CC_PROFILER_STOP_CATEGORY(kProfilerCategoryBatchSprite, "CCSpriteBatchNode - visit"); }
//-------------------------------------------------------- void CRemoveBKSprite::draw(void) { CC_PROFILER_START_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw"); CCAssert(!m_pobBatchNode, "If CCSprite is being rendered by CCSpriteBatchNode, CCSprite#draw SHOULD NOT be called"); CC_NODE_DRAW_SETUP(); // 启用attributes变量输入,顶点坐标,纹理坐标,颜色 ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex ); ccGLBlendFunc(m_sBlendFunc.src, m_sBlendFunc.dst); m_pShaderProgram->use(); m_pShaderProgram->setUniformsForBuiltins(); // 绑定纹理到纹理槽0 ccGLBindTexture2D(m_pobTexture->getName()); long offset = (long)&m_sQuad; // vertex int diff = offsetof( ccV3F_C4B_T2F, vertices); glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, sizeof(m_sQuad.bl), (void*) (offset + diff)); // texCoods diff = offsetof( ccV3F_C4B_T2F, texCoords); glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, sizeof(m_sQuad.bl), (void*)(offset + diff)); // color diff = offsetof( ccV3F_C4B_T2F, colors); glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(m_sQuad.bl), (void*)(offset + diff)); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); CHECK_GL_ERROR_DEBUG(); CC_INCREMENT_GL_DRAWS(1); CC_PROFILER_STOP_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw"); }
void HueSprite::draw() { CC_PROFILER_START_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw"); CCAssert(!m_pobBatchNode, "If CCSprite is being rendered by CCSpriteBatchNode, CCSprite#draw SHOULD NOT be called"); //CC_NODE_DRAW_SETUP(); ccGLEnable( m_eGLServerState ); ccGLBlendFunc( m_sBlendFunc.src, m_sBlendFunc.dst ); m_shader->use(); m_shader->setUniformsForBuiltins(); if (m_pobTexture != NULL) { //ccGLBindTexture2D( m_texure1->getName()); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_pobTexture->getName()); } else { ccGLBindTexture2D(0); } glUniformMatrix3fv(m_loc_hue, 1, GL_FALSE, (GLfloat*)&m_mat); // // Attributes // ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex ); #define kQuadSize sizeof(m_sQuad.bl) long offset = (long)&m_sQuad; // vertex int diff = offsetof( ccV3F_C4B_T2F, vertices); glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff)); // texCoods diff = offsetof( ccV3F_C4B_T2F, texCoords); glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff)); // color diff = offsetof( ccV3F_C4B_T2F, colors); glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff)); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); CHECK_GL_ERROR_DEBUG(); CC_INCREMENT_GL_DRAWS(1); CC_PROFILER_STOP_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw"); }
/** * 绘制 */ void MapCoordLine::draw(void) { CC_PROFILER_START_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw"); CCAssert(!m_pobBatchNode, "If CCSprite is being rendered by CCSpriteBatchNode, CCSprite#draw SHOULD NOT be called"); CC_NODE_DRAW_SETUP(); ccGLBlendFunc( m_sBlendFunc.src, m_sBlendFunc.dst ); if (m_pobTexture != NULL) { ccGLBindTexture2D( m_pobTexture->getName() ); } else { ccGLBindTexture2D(0); } // // Attributes // ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex ); #define kQuadSize sizeof(m_sQuad.bl) if (points.size()) { long offset = (long)&points[0]; // vertex int diff = offsetof( ccV3F_C4B_T2F, vertices); glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff)); // texCoods diff = offsetof( ccV3F_C4B_T2F, texCoords); glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff)); // color diff = offsetof( ccV3F_C4B_T2F, colors); glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff)); glDrawArrays(GL_LINES, 0, points.size()); } CHECK_GL_ERROR_DEBUG(); CC_INCREMENT_GL_DRAWS(1); CC_PROFILER_STOP_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw"); }
void CCCatmullRomSprite::draw() { // at least we need two points if(m_controlPoints.getCount() < 2) return; // build atlas if(m_dirty) { updateAtlas(); m_dirty = false; } // profile start CC_PROFILER_START_CATEGORY(kCCProfilerCategorySprite, "CCCatmullRomSprite - draw"); // setup CC_NODE_DRAW_SETUP(); // blend func ccBlendFunc bf = m_sprite->getBlendFunc(); ccGLBlendFunc(bf.src, bf.dst); // draw if(m_atlas) { if(m_allVisible) { m_atlas->drawQuadsEx(); } else { int startIndex = 0; int sc = getSegmentCount(); for(int i = 0; i < sc; i++) { bool visible = isSegmentVisible(i); if(!visible) { int endIndex = m_segmentQuadIndices[i]; m_atlas->drawNumberOfQuadsEx(endIndex - startIndex, startIndex); startIndex = m_segmentQuadIndices[i + 1]; } } // last if(m_atlas->getTotalQuads() > startIndex) { m_atlas->drawNumberOfQuadsEx(m_atlas->getTotalQuads() - startIndex, startIndex); } } } // profile end CC_PROFILER_STOP_CATEGORY(kCCProfilerCategorySprite, "CCCatmullRomSprite - draw"); }
void IsometryNode::visit() { //setPosition(CCPointMake(0, 500)); //CCNode::visit(); //Stats(); if(getShaderProgram() == nullptr) { setShaderProgram(CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionTextureColor)); } CC_PROFILER_START_CATEGORY(kCCProfilerCategoryBatchSprite, "CCSpriteBatchNode - visit"); // CAREFUL: // This visit is almost identical to CocosNode#visit // with the exception that it doesn't call visit on it's children // // The alternative is to have a void CCSprite#visit, but // although this is less maintainable, is faster // if (! m_bVisible) { return; } kmGLPushMatrix(); if (m_pGrid && m_pGrid->isActive()) { m_pGrid->beforeDraw(); transformAncestors(); } sortAllChildren(); transform(); draw(); if (m_pGrid && m_pGrid->isActive()) { m_pGrid->afterDraw(this); } kmGLPopMatrix(); setOrderOfArrival(0); CC_PROFILER_STOP_CATEGORY(kCCProfilerCategoryBatchSprite, "CCSpriteBatchNode - visit"); }
void ShaderSprite::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) { CC_PROFILER_START_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw"); // CCAssert(, "If CCSprite is being rendered by CCSpriteBatchNode, CCSprite#draw SHOULD NOT be called"); CC_NODE_DRAW_SETUP(); // // 启用attributes变量输入,顶点坐标,纹理坐标,颜色 // ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex ); ccGLBlendFunc(this->getBlendFunc().src, this->getBlendFunc().dst); this->getShaderProgram()->use(); this->getShaderProgram()->setUniformsForBuiltins(); // 绑定纹理到纹理槽0 ccGLBindTexture2D(this->getTexture()->getName()); #define kQuadSize sizeof(this->_quad.bl) long offset = (long)&this->_quad; // vertex int diff = offsetof( ccV3F_C4B_T2F, vertices); glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff)); // texCoods diff = offsetof( ccV3F_C4B_T2F, texCoords); glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff)); // color diff = offsetof( ccV3F_C4B_T2F, colors); glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff)); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); CHECK_GL_ERROR_DEBUG(); CC_INCREMENT_GL_DRAWS(1); CC_PROFILER_STOP_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw"); }
void CABatchView::visit(void) { CC_PROFILER_START_CATEGORY(kCCProfilerCategoryBatchSprite, "CABatchView - visit"); CC_RETURN_IF(!m_bVisible); kmGLPushMatrix(); sortAllSubview(); transform(); draw(); kmGLPopMatrix(); setOrderOfArrival(0); CC_PROFILER_STOP_CATEGORY(kCCProfilerCategoryBatchSprite, "CABatchView - visit"); }
// override visit // don't call visit on it's children // 是基类CCNode虚函数,是每帧会被调用到的函数。 void CCSpriteBatchNode::visit(void) { CC_PROFILER_START_CATEGORY(kCCProfilerCategoryBatchSprite, "CCSpriteBatchNode - visit"); // CAREFUL: // This visit is almost identical to CocosNode#visit // with the exception that it doesn't call visit on it's children // // The alternative is to have a void CCSprite#visit, but // although this is less maintainable, is faster // // 如果不显示,直接返回 if (! m_bVisible) { return; } //矩阵压栈,保存渲染此结点前的所有OpenGL所需矩阵的值 kmGLPushMatrix(); if (m_pGrid && m_pGrid->isActive()) { m_pGrid->beforeDraw(); transformAncestors(); } sortAllChildren(); //矩阵变量 transform(); //基类CCNode虚函数,用于实现当前CCNode的绘制 draw(); if (m_pGrid && m_pGrid->isActive()) { m_pGrid->afterDraw(this); } //矩阵出栈。恢复渲染此结点前的所有OpenGL所需矩阵的值 kmGLPopMatrix(); setOrderOfArrival(0); CC_PROFILER_STOP_CATEGORY(kCCProfilerCategoryBatchSprite, "CCSpriteBatchNode - visit"); }
// override visit // don't call visit on it's children void CCSpriteBatchNode::visit(void) { CC_PROFILER_START_CATEGORY(kCCProfilerCategoryBatchSprite, "CCSpriteBatchNode - visit"); // CAREFUL: // This visit is almost identical to CocosNode#visit // with the exception that it doesn't call visit on it's children // // The alternative is to have a void CCSprite#visit, but // although this is less maintainable, is faster // if (! m_bVisible) { return; } kmGLPushMatrix(); if (m_pGrid && m_pGrid->isActive()) { m_pGrid->beforeDraw(); transformAncestors(); } sortAllChildren(); transform(); draw(); if (m_pGrid && m_pGrid->isActive()) { m_pGrid->afterDraw(this); } kmGLPopMatrix(); CC_PROFILER_STOP_CATEGORY(kCCProfilerCategoryBatchSprite, "CCSpriteBatchNode - visit"); }
// override visit // don't call visit on it's children void SpriteBatchNode::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t parentFlags) { CC_PROFILER_START_CATEGORY(kProfilerCategoryBatchSprite, "CCSpriteBatchNode - visit"); // CAREFUL: // This visit is almost identical to CocosNode#visit // with the exception that it doesn't call visit on it's children // // The alternative is to have a void Sprite#visit, but // although this is less maintainable, is faster // if (! _visible) { return; } sortAllChildren(); uint32_t flags = processParentFlags(parentTransform, parentFlags); if (isVisitableByVisitingCamera()) { // IMPORTANT: // To ease the migration to v3.0, we still support the Mat4 stack, // but it is deprecated and your code should not rely on it Director* director = Director::getInstance(); director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform); draw(renderer, _modelViewTransform, flags); director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); // FIX ME: Why need to set _orderOfArrival to 0?? // Please refer to https://github.com/cocos2d/cocos2d-x/pull/6920 // setOrderOfArrival(0); CC_PROFILER_STOP_CATEGORY(kProfilerCategoryBatchSprite, "CCSpriteBatchNode - visit"); } }
void NParticleSystemQuad::update(float dt) { CC_PROFILER_START_CATEGORY(kProfilerCategoryParticles , "CCParticleSystem - update"); if (_isActive && _emissionRate) { float rate = 1.0f / _emissionRate; //issue #1201, prevent bursts of particles, due to too high emitCounter if (_particleCount < _totalParticles) { _emitCounter += dt; } while (_particleCount < _totalParticles && _emitCounter > rate) { this->addParticle(); _emitCounter -= rate; } _elapsed += dt; if (_duration != -1 && _duration < _elapsed) { this->stopSystem(); } } _particleIdx = 0; Vec2 currentPosition = Vec2::ZERO; if (_positionType == PositionType::FREE) { currentPosition = this->convertToWorldSpace(Vec2::ZERO); } else if (_positionType == PositionType::RELATIVE) { currentPosition = _position; } { while (_particleIdx < _particleCount) { tParticle *p = &_particles[_particleIdx]; // life p->timeToLive -= dt; if (p->timeToLive > 0) { // Mode A: gravity, direction, tangential accel & radial accel if (_emitterMode == Mode::GRAVITY) { Vec2 tmp, radial, tangential; radial = Vec2::ZERO; // radial acceleration if (p->pos.x || p->pos.y) { radial = p->pos.getNormalized(); } tangential = radial; radial = radial * p->modeA.radialAccel; // tangential acceleration float newy = tangential.x; tangential.x = -tangential.y; tangential.y = newy; tangential = tangential * p->modeA.tangentialAccel; // (gravity + radial + tangential) * dt tmp = radial + tangential + modeA.gravity; tmp = tmp * dt; p->modeA.dir = p->modeA.dir + tmp; // this is cocos2d-x v3.0 // if (_configName.length()>0 && _yCoordFlipped != -1) // this is cocos2d-x v3.0 tmp = p->modeA.dir * dt * _yCoordFlipped; p->pos = p->pos + tmp; } // Mode B: radius movement else { // Update the angle and radius of the particle. p->modeB.angle += p->modeB.degreesPerSecond * dt; p->modeB.radius += p->modeB.deltaRadius * dt; p->pos.x = - cosf(p->modeB.angle) * p->modeB.radius; p->pos.y = - sinf(p->modeB.angle) * p->modeB.radius; p->pos.y *= _yCoordFlipped; } // color p->color.r += (p->deltaColor.r * dt); p->color.g += (p->deltaColor.g * dt); p->color.b += (p->deltaColor.b * dt); p->color.a += (p->deltaColor.a * dt); // size p->size += (p->deltaSize * dt); p->size = MAX( 0, p->size ); // angle p->rotation += (p->deltaRotation * dt); // // update values in quad // Vec2 newPos; if (_positionType == PositionType::FREE || _positionType == PositionType::RELATIVE) { Vec2 diff = currentPosition - p->startPos; newPos = p->pos - diff; } else { newPos = p->pos; } // translate newPos to correct position, since matrix transform isn't performed in batchnode // don't update the particle with the new position information, it will interfere with the radius and tangential calculations if (_batchNode) { newPos.x+=_position.x; newPos.y+=_position.y; } updateQuadWithParticle(p, newPos); //updateParticleImp(self, updateParticleSel, p, newPos); // update particle counter ++_particleIdx; } else { // life < 0 int currentIndex = p->atlasIndex; if( _particleIdx != _particleCount-1 ) { _particles[_particleIdx] = _particles[_particleCount-1]; } if (_batchNode) { //disable the switched particle _batchNode->disableParticle(_atlasIndex+currentIndex); //switch indexes _particles[_particleCount-1].atlasIndex = currentIndex; } --_particleCount; if( _particleCount == 0 && _isAutoRemoveOnFinish ) { this->unscheduleUpdate(); _parent->removeChild(this, true); // 親から remove されるときにコールバック関数を呼ぶ if (onFinishListener) { onFinishListener(this); } return; } } } //while _transformSystemDirty = false; } // only update gl buffer when visible if (_visible && ! _batchNode) { postStep(); } CC_PROFILER_STOP_CATEGORY(kProfilerCategoryParticles , "CCParticleSystem - update"); }
void SpriteMask::draw() { if (!_isSetMask) //沒有設定就直接用預設方法 { CCSprite::draw(); return; } CC_PROFILER_START_CATEGORY(kProfilerCategorySprite, "CCSprite - draw"); CCASSERT(!_batchNode, "If Sprite is being rendered by SpriteBatchNode, Sprite#draw SHOULD NOT be called"); CC_NODE_DRAW_SETUP(); GL::blendFunc(_blendFunc.src, _blendFunc.dst); GL::bindTexture2D(_texture->getName()); GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); if (_texture != NULL) { ccGLBindTexture2D(_texture->getName()); } else { ccGLBindTexture2D(0); } //mask 設定 設定使用mask貼圖 glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, _maskTexture->getName()); glUniform1i(_maskLocation, 1); glUniform2f(_offsetLocation, offsetWithPosition.x, offsetWithPosition.y); #define kQuadSize sizeof(_quad.bl) #ifdef EMSCRIPTEN long offset = 0; setGLBufferData(&_quad, 4 * kQuadSize, 0); #else long offset = (long)&_quad; #endif // EMSCRIPTEN // vertex int diff = offsetof(V3F_C4B_T2F, vertices); glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff)); // texCoods diff = offsetof(V3F_C4B_T2F, texCoords); glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORDS, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff)); // color diff = offsetof(V3F_C4B_T2F, colors); glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff)); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); CHECK_GL_ERROR_DEBUG(); #if CC_SPRITE_DEBUG_DRAW == 1 // draw bounding box Point vertices[4] = { Point(_quad.tl.vertices.x, _quad.tl.vertices.y), Point(_quad.bl.vertices.x, _quad.bl.vertices.y), Point(_quad.br.vertices.x, _quad.br.vertices.y), Point(_quad.tr.vertices.x, _quad.tr.vertices.y), }; ccDrawPoly(vertices, 4, true); #elif CC_SPRITE_DEBUG_DRAW == 2 // draw texture box Size s = this->getTextureRect().size; Point offsetPix = this->getOffsetPosition(); Point vertices[4] = { Point(offsetPix.x, offsetPix.y), Point(offsetPix.x + s.width, offsetPix.y), Point(offsetPix.x + s.width, offsetPix.y + s.height), Point(offsetPix.x, offsetPix.y + s.height) }; ccDrawPoly(vertices, 4, true); #endif // CC_SPRITE_DEBUG_DRAW CC_INCREMENT_GL_DRAWS(1); glActiveTexture(GL_TEXTURE0); //must set to texture0 CC_PROFILER_STOP_CATEGORY(kProfilerCategorySprite, "CCSprite - draw"); }
void YUVSprite::draw() { CC_PROFILER_START_CATEGORY(kCCProfilerCategorySprite, "YUVSprite - draw"); CCAssert(!m_pobBatchNode, "If YUVSprite is being rendered by CCSpriteBatchNode, YUVSprite#draw SHOULD NOT be called"); // CC_NODE_DRAW_SETUP(); ccGLBlendFunc( m_sBlendFunc.src, m_sBlendFunc.dst ); if(_prog){ _prog->use(); _prog->setUniformsForBuiltins(); } if(textureDone){ glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, id_y); glUniform1i(textureUniformY, 0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, id_u); glUniform1i(textureUniformU, 1); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, id_v); glUniform1i(textureUniformV, 2); glUniform1f(borderUniformY,_border[0]); glUniform1f(borderUniformU,_border[1]); glUniform1f(borderUniformV,_border[2]); } //ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex ); #define kQuadSize sizeof(m_sQuad.bl) #ifdef EMSCRIPTEN long offset = 0; setGLBufferData(&m_sQuad, 4 * kQuadSize, 0); #else long offset = (long)&m_sQuad; #endif // EMSCRIPTEN CHECK_GL_ERROR_DEBUG(); GLfloat square[8]; CCSize s = this->getTextureRect().size; CCPoint offsetPix = this->getOffsetPosition(); square[0] = offsetPix.x; square[1] = offsetPix.y; square[2] = offsetPix.x+s.width; square[3] = offsetPix.y; square[6] = offsetPix.x+s.width; square[7] = offsetPix.y+s.height; square[4] = offsetPix.x; square[5] = offsetPix.y+s.height; glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, square); glEnableVertexAttribArray(ATTRIB_VERTEX); glVertexAttribPointer(ATTRIB_TEXTURE, 2, GL_FLOAT, 0, 0, coordVertices); glEnableVertexAttribArray(ATTRIB_TEXTURE); /* // vertex int diff = offsetof( ccV3F_C4B_T2F, vertices); glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff)); // texCoods diff = offsetof( ccV3F_C4B_T2F, texCoords); glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff)); // color diff = offsetof( ccV3F_C4B_T2F, colors); glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff)); */ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); CHECK_GL_ERROR_DEBUG(); #if CC_SPRITE_DEBUG_DRAW == 1 // draw bounding box CCPoint vertices[4]={ ccp(m_sQuad.tl.vertices.x,m_sQuad.tl.vertices.y), ccp(m_sQuad.bl.vertices.x,m_sQuad.bl.vertices.y), ccp(m_sQuad.br.vertices.x,m_sQuad.br.vertices.y), ccp(m_sQuad.tr.vertices.x,m_sQuad.tr.vertices.y), }; ccDrawPoly(vertices, 4, true); #elif CC_SPRITE_DEBUG_DRAW == 2 // draw texture box CCSize s = this->getTextureRect().size; CCPoint offsetPix = this->getOffsetPosition(); CCPoint vertices[4] = { ccp(offsetPix.x,offsetPix.y), ccp(offsetPix.x+s.width,offsetPix.y), ccp(offsetPix.x+s.width,offsetPix.y+s.height), ccp(offsetPix.x,offsetPix.y+s.height) }; ccDrawPoly(vertices, 4, true); #endif // CC_SPRITE_DEBUG_DRAW CC_INCREMENT_GL_DRAWS(1); CC_PROFILER_STOP_CATEGORY(kCCProfilerCategorySprite, "YUVSprite - draw"); }
void Live2dXSprite::draw() { if(!m_pobTexture) { return; } if(m_isAnimation) { cc_timeval nowTime; CCTime::gettimeofdayCocos2d(&nowTime, NULL); float deltime = (float)(nowTime.tv_sec - m_nowTime.tv_sec) + (float)(nowTime.tv_usec - m_nowTime.tv_usec)/1000000.0f; m_nowTime = nowTime; animationUpdate(deltime); // animationUpdate(1/30.0f); } #define Live2dX_Vertex_Size sizeof(Live2dX_Vertex) #define Live2dX_UV_Size sizeof(Live2dX_UV) #define Live2dX_Color_Size sizeof(Live2dX_Color) #ifndef __QT__ CC_PROFILER_START_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw"); CCAssert(!m_pobBatchNode, "If CCSprite is being rendered by CCSpriteBatchNode, CCSprite#draw SHOULD NOT be called"); CC_NODE_DRAW_SETUP(); ccGLBlendFunc( m_sBlendFunc.src, m_sBlendFunc.dst ); ccGLBindTexture2D( m_pobTexture->getName() ); ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex ); // vertex glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, Live2dX_Vertex_Size, (void*)m_nowVertex.data()); // texCoods glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, Live2dX_UV_Size, (void*)m_orginUV.data()); // color glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, Live2dX_Color_Size, (void*)m_orginColor.data()); glDrawArrays(GL_TRIANGLES, 0, (int)m_nowVertex.size()); CHECK_GL_ERROR_DEBUG(); CC_INCREMENT_GL_DRAWS(1); CC_PROFILER_STOP_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw"); #else glTranslatef(-0.5f,0,0); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glBindTexture(GL_TEXTURE_2D,m_pobTexture->m_name); for(int i = 0; i < m_nowVertex.size();i+=3) { float a,b; glBegin(GL_TRIANGLES); glColor4f(1,1,1,1); glTexCoord2f(m_orginUV[i].u,1-m_orginUV[i].v); a = m_nowVertex[i].x * 2 / m_baseSize.width - 1; b = m_nowVertex[i].y * 2 / m_baseSize.height-1; glVertex3f(a,b,0); glColor4f(1,1,1,1); glTexCoord2f(m_orginUV[i+1].u,1-m_orginUV[i+1].v); a = m_nowVertex[i+1].x * 2 / m_baseSize.width - 1; b = m_nowVertex[i+1].y * 2 / m_baseSize.height-1; glVertex3f(a,b,0); glColor4f(1,1,1,1); glTexCoord2f(m_orginUV[i+2].u,1-m_orginUV[i+2].v); a = m_nowVertex[i+2].x * 2 / m_baseSize.width - 1; b = m_nowVertex[i+2].y * 2 / m_baseSize.height-1; glVertex3f(a,b,0); glColor4f(1,1,1,1); glEnd(); } #endif }
void CCSquirmAnimNode::draw() { CCAssert(m_pobTexture != 0 && m_maskTexture != 0, "CCSquirmAnimNode::draw(), textures mustn't be null!"); CC_PROFILER_START_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw"); // 如果顶点数据需要刷新,就刷新之 if(m_vertices_dirty) { rebuildVertices(); } CC_NODE_DRAW_SETUP(); ccGLBlendFunc( m_sBlendFunc.src, m_sBlendFunc.dst ); ccGLBindTexture2DN(0, m_pobTexture->getName()); ccGLBindTexture2DN(1, m_maskTexture->getName()); // // Attributes // ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTexTex ); #define kQuadSize sizeof(m_sQuad.bl) long offset = (long)&m_sQuad; // vertex int diff = offsetof( ccV3F_C4B_T2Fx2, vertices); glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff)); // texCoods diff = offsetof( ccV3F_C4B_T2Fx2, texCoords); glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff)); diff = offsetof(ccV3F_C4B_T2Fx2, texCoords1); glVertexAttribPointer(kCCVertexAttrib_TexCoords1, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff)); // color diff = offsetof( ccV3F_C4B_T2Fx2, colors); glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff)); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); CHECK_GL_ERROR_DEBUG(); #if CC_SPRITE_DEBUG_DRAW == 1 // draw bounding box CCPoint vertices[4]={ ccp(m_sQuad.tl.vertices.x,m_sQuad.tl.vertices.y), ccp(m_sQuad.bl.vertices.x,m_sQuad.bl.vertices.y), ccp(m_sQuad.br.vertices.x,m_sQuad.br.vertices.y), ccp(m_sQuad.tr.vertices.x,m_sQuad.tr.vertices.y), }; ccDrawPoly(vertices, 4, true); #elif CC_SPRITE_DEBUG_DRAW == 2 // draw texture box CCSize s = this->getTextureRect().size; CCPoint offsetPix = this->getOffsetPosition(); CCPoint vertices[4] = { ccp(offsetPix.x,offsetPix.y), ccp(offsetPix.x+s.width,offsetPix.y), ccp(offsetPix.x+s.width,offsetPix.y+s.height), ccp(offsetPix.x,offsetPix.y+s.height) }; ccDrawPoly(vertices, 4, true); #endif // CC_SPRITE_DEBUG_DRAW CC_INCREMENT_GL_DRAWS(1); CC_PROFILER_STOP_CATEGORY(kCCProfilerCategorySprite, "CCSquirmAnimNode - draw"); }
void CCParticleSystemFrameQuad::update(float dt) { CC_PROFILER_START_CATEGORY(kCCProfilerCategoryParticles , "CCParticleSystemFrameQuad - update"); if (m_bIsActive && m_fEmissionRate) { float rate = 1.0f / m_fEmissionRate; //issue #1201, prevent bursts of particles, due to too high emitCounter if (m_uParticleCount < m_uTotalParticles) { m_fEmitCounter += dt; } while (m_uParticleCount < m_uTotalParticles && m_fEmitCounter > rate) { this->addParticle(); m_fEmitCounter -= rate; } m_fElapsed += dt; if (m_fDuration != -1 && m_fDuration < m_fElapsed) { this->stopSystem(); } } m_uParticleIdx = 0; CCPoint currentPosition = CCPointZero; if (m_ePositionType == kCCPositionTypeFree) { currentPosition = this->convertToWorldSpace(CCPointZero); } else if (m_ePositionType == kCCPositionTypeRelative) { currentPosition = m_obPosition; } if (m_bVisible) { while (m_uParticleIdx < m_uParticleCount) { tCCParticle *p = &m_pParticles[m_uParticleIdx]; // life p->timeToLive -= dt; if (p->timeToLive > 0) { // Mode A: gravity, direction, tangential accel & radial accel if (m_nEmitterMode == kCCParticleModeGravity) { CCPoint tmp, radial, tangential; radial = CCPointZero; // radial acceleration if (p->pos.x || p->pos.y) { radial = ccpNormalize(p->pos); } tangential = radial; radial = ccpMult(radial, p->modeA.radialAccel); // tangential acceleration float newy = tangential.x; tangential.x = -tangential.y; tangential.y = newy; tangential = ccpMult(tangential, p->modeA.tangentialAccel); // (gravity + radial + tangential) * dt tmp = ccpAdd( ccpAdd( radial, tangential), modeA.gravity); tmp = ccpMult( tmp, dt); p->modeA.dir = ccpAdd( p->modeA.dir, tmp); tmp = ccpMult(p->modeA.dir, dt); p->pos = ccpAdd( p->pos, tmp ); } // Mode B: radius movement else { // Update the angle and radius of the particle. p->modeB.angle += p->modeB.degreesPerSecond * dt; p->modeB.radius += p->modeB.deltaRadius * dt; p->pos.x = - cosf(p->modeB.angle) * p->modeB.radius; p->pos.y = - sinf(p->modeB.angle) * p->modeB.radius; } // color p->color.r += (p->deltaColor.r * dt); p->color.g += (p->deltaColor.g * dt); p->color.b += (p->deltaColor.b * dt); p->color.a += (p->deltaColor.a * dt); // size p->size += (p->deltaSize * dt); p->size = MAX( 0, p->size ); // angle p->rotation += (p->deltaRotation * dt); // // update values in quad // CCPoint newPos; if (m_ePositionType == kCCPositionTypeFree || m_ePositionType == kCCPositionTypeRelative) { CCPoint diff = ccpSub( currentPosition, p->startPos ); newPos = ccpSub(p->pos, diff); } else { newPos = p->pos; } // translate newPos to correct position, since matrix transform isn't performed in batchnode // don't update the particle with the new position information, it will interfere with the radius and tangential calculations if (m_pBatchNode) { newPos.x+=m_obPosition.x; newPos.y+=m_obPosition.y; } updateQuadWithParticle(p, newPos); //updateParticleImp(self, updateParticleSel, p, newPos); // update particle counter ++m_uParticleIdx; } else { // life < 0 int currentIndex = p->atlasIndex; if( m_uParticleIdx != m_uParticleCount-1 ) { m_pParticles[m_uParticleIdx] = m_pParticles[m_uParticleCount-1]; } if (m_pBatchNode) { //disable the switched particle m_pBatchNode->disableParticle(m_uAtlasIndex+currentIndex); //switch indexes m_pParticles[m_uParticleCount-1].atlasIndex = currentIndex; } else if( m_uParticleIdx != m_uParticleCount-1 ) { //switch quads texCoords ccV3F_C4B_T2F_Quad temp = m_pQuads[m_uParticleIdx]; m_pQuads[m_uParticleIdx] = m_pQuads[m_uParticleCount-1]; m_pQuads[m_uParticleCount-1] = temp; } --m_uParticleCount; if( m_uParticleCount == 0 && m_bIsAutoRemoveOnFinish ) { this->unscheduleUpdate(); m_pParent->removeChild(this, true); return; } } } //while m_bTransformSystemDirty = false; } if (! m_pBatchNode) { postStep(); } CC_PROFILER_STOP_CATEGORY(kCCProfilerCategoryParticles , "CCParticleSystemFrameQuad - update"); }
void GAFSprite::draw(void) { if (_isLocator) { return; } CC_PROFILER_START_CATEGORY(kCCProfilerCategorySprite, "GAFSprite - draw"); CCAssert(!m_pobBatchNode, "If CCSprite is being rendered by CCSpriteBatchNode, CCSprite#draw SHOULD NOT be called"); CC_NODE_DRAW_SETUP(); if (_useSeparateBlendFunc) { glBlendFuncSeparate(_blendFuncSeparate.src, _blendFuncSeparate.dst, _blendFuncSeparate.srcAlpha, _blendFuncSeparate.dstAlpha); } else { ccGLBlendFunc(m_sBlendFunc.src, m_sBlendFunc.dst); } if (_blendEquation != -1) { glBlendEquation(_blendEquation); } if (m_pobTexture != NULL) { ccGLBindTexture2D( m_pobTexture->getName() ); } else { ccGLBindTexture2D(0); } // // Attributes // ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex ); setUniformsForFragmentShader(); CHECK_GL_ERROR_DEBUG(); #define kQuadSize sizeof(m_sQuad.bl) long offset = (long)&m_sQuad; // vertex int diff = offsetof( ccV3F_C4B_T2F, vertices); glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff)); // texCoods diff = offsetof( ccV3F_C4B_T2F, texCoords); glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff)); // color diff = offsetof( ccV3F_C4B_T2F, colors); glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff)); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); CHECK_GL_ERROR_DEBUG(); CC_INCREMENT_GL_DRAWS(1); CC_PROFILER_STOP_CATEGORY(kCCProfilerCategorySprite, "GAFSprite - draw"); }
void BlurSprite::draw() { CC_PROFILER_START_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw"); CCAssert(!m_pobBatchNode, "If CCSprite is being rendered by CCSpriteBatchNode, CCSprite#draw SHOULD NOT be called"); //CC_NODE_DRAW_SETUP(); ccGLEnable( m_eGLServerState ); ccGLBlendFunc( m_sBlendFunc.src, m_sBlendFunc.dst ); // 水平方向blur m_frameTexture->clear(0.f, 0.f, 0.f, 0.f); m_frameTexture->begin(); { m_shader->use(); m_shader->setUniformsForBuiltins(); glUniform2f(m_location_pix_size, 1.f/m_tex_size.width, 0); if (m_pobTexture != NULL) { ccGLBindTexture2D(m_pobTexture->getName()); } else { ccGLBindTexture2D(0); } // // Attributes // ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex ); #define kQuadSize sizeof(m_sQuad.bl) long offset = (long)&m_sQuad; // vertex int diff = offsetof( ccV3F_C4B_T2F, vertices); glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff)); // texCoods diff = offsetof( ccV3F_C4B_T2F, texCoords); glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff)); // color diff = offsetof( ccV3F_C4B_T2F, colors); glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff)); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); CHECK_GL_ERROR_DEBUG(); } m_frameTexture->end(); // 垂直方向blur CCTexture2D* rt = m_frameTexture->getSprite()->getTexture(); #if CC_DEBUG m_frameTexture2->clear(0.f, 0.f, 0.f, 0.f); m_frameTexture2->begin(); #endif { m_shader->use(); m_shader->setUniformsForBuiltins(); glUniform2f(m_location_pix_size, 0, 1.f/m_tex_size.height); if ( rt != NULL) { ccGLBindTexture2D(rt->getName()); } else { ccGLBindTexture2D(0); } // // Attributes // ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex ); #define kQuadSize sizeof(m_sQuad.bl) long offset = (long)&m_sQuad; // vertex int diff = offsetof( ccV3F_C4B_T2F, vertices); glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff)); // texCoods diff = offsetof( ccV3F_C4B_T2F, texCoords); glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff)); // color diff = offsetof( ccV3F_C4B_T2F, colors); glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff)); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); CHECK_GL_ERROR_DEBUG(); } #if CC_DEBUG m_frameTexture2->end(); m_frameTexture2->saveToFile("blur_complete.png"); #endif CC_INCREMENT_GL_DRAWS(1); CC_PROFILER_STOP_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw"); }
void CAView::draw() { m_uZLevel = CAApplication::getApplication()->getCurrentNumberOfDraws(); CC_RETURN_IF(m_pobImage == NULL); CC_RETURN_IF(m_pShaderProgram == NULL); CC_NODE_DRAW_SETUP(); ccGLBlendFunc(m_sBlendFunc.src, m_sBlendFunc.dst); ccGLBindTexture2D(m_pobImage->getName()); ccGLEnableVertexAttribs(kCCVertexAttribFlag_PosColorTex); #define kQuadSize sizeof(m_sQuad.bl) #ifdef EMSCRIPTEN long offset = 0; setGLBufferData(&m_sQuad, 4 * kQuadSize, 0); #else long offset = (long)&m_sQuad; #endif // vertex int diff = offsetof( ccV3F_C4B_T2F, vertices); glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff)); // texCoods diff = offsetof( ccV3F_C4B_T2F, texCoords); glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff)); // color diff = offsetof( ccV3F_C4B_T2F, colors); glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff)); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); #if CC_SPRITE_DEBUG_DRAW // draw bounding box DPoint vertices[4]= { DPoint(m_sQuad.tl.vertices.x, m_sQuad.tl.vertices.y), DPoint(m_sQuad.bl.vertices.x, m_sQuad.bl.vertices.y), DPoint(m_sQuad.br.vertices.x, m_sQuad.br.vertices.y), DPoint(m_sQuad.tr.vertices.x, m_sQuad.tr.vertices.y), }; ccDrawPoly(vertices, 4, true); #endif // CC_SPRITE_DEBUG_DRAW CC_PROFILER_STOP_CATEGORY(kCCProfilerCategorySprite, "CAView - draw"); }
void BillboardParticleSystem::update(float dt) { if(_camera) { const Mat4& cameraViewMatrix = _camera->getViewMatrix().getInversed(); cameraViewMatrix.getRightVector(&_cameraRight); cameraViewMatrix.getUpVector(&_cameraUp); } const Mat4& WorldMat = getNodeToWorldTransform(); Quaternion rotation;; WorldMat.getRotation(&rotation); Mat4 roaMat; Mat4::createRotation(rotation,&roaMat); CC_PROFILER_START_CATEGORY(kProfilerCategoryParticles , "CCParticleSystem - update"); if (_isActive && _emissionRate) { float rate = 1.0f / _emissionRate; //issue #1201, prevent bursts of particles, due to too high emitCounter if (_particleCount < _totalParticles) { _emitCounter += dt; } while (_particleCount < _totalParticles && _emitCounter > rate) { this->addParticle(); _emitCounter -= rate; } _elapsed += dt; if (_duration != -1 && _duration < _elapsed) { this->stopSystem(); } } _particleIdx = 0; Vec3 currentPosition = Vec3::ZERO; if (_positionType == PositionType::FREE) { currentPosition = this->convertToWorldSpace3D(Vec3::ZERO); } else if (_positionType == PositionType::RELATIVE) { currentPosition.x = _position.x; currentPosition.y = _position.y; currentPosition.z = _positionZ; } { while (_particleIdx < _particleCount) { sBillboardParticle *p = &_particles[_particleIdx]; // life p->timeToLive -= dt; if (p->timeToLive > 0) { // Mode A: gravity, direction, tangential accel & radial accel if (_emitterMode == Mode::GRAVITY) { Vec2 tmp, radial, tangential; radial = Vec2::ZERO; // radial acceleration if (p->pos.x || p->pos.y) { radial = p->pos.getNormalized(); } tangential = radial; radial = radial * p->modeA.radialAccel; // tangential acceleration float newy = tangential.x; tangential.x = -tangential.y; tangential.y = newy; tangential = tangential * p->modeA.tangentialAccel; // (gravity + radial + tangential) * dt tmp = radial + tangential + modeA.gravity; tmp = tmp * dt; p->modeA.dir = p->modeA.dir + tmp; // this is cocos2d-x v3.0 // if (_configName.length()>0 && _yCoordFlipped != -1) // this is cocos2d-x v3.0 tmp = p->modeA.dir * dt * _yCoordFlipped; p->pos = p->pos + tmp; } // Mode B: radius movement else { // Update the angle and radius of the particle. p->modeB.angle += p->modeB.degreesPerSecond * dt; p->modeB.radius += p->modeB.deltaRadius * dt; p->pos.x = - cosf(p->modeB.angle) * p->modeB.radius; p->pos.y = - sinf(p->modeB.angle) * p->modeB.radius; p->pos.y *= _yCoordFlipped; } // color p->color.r += (p->deltaColor.r * dt); p->color.g += (p->deltaColor.g * dt); p->color.b += (p->deltaColor.b * dt); p->color.a += (p->deltaColor.a * dt); // size p->size += (p->deltaSize * dt); p->size = MAX( 0, p->size ); // angle p->rotation += (p->deltaRotation * dt); // // update values in quad // Vec3 newPos; Vec3 parPos(p->pos.x,p->pos.y,0); roaMat.transformVector(&parPos); if (_positionType == PositionType::FREE) { Vec3 diff = convertToNodeSpace3D(currentPosition) - convertToNodeSpace3D(p->startPos); //newPos.x = p->pos.x - diff.x; //newPos.y = p->pos.y - diff.y; //newPos.z = - diff.z; newPos = parPos-diff; } else if(_positionType == PositionType::RELATIVE) { Vec3 diff = currentPosition - p->startPos; newPos.x = p->pos.x - diff.x; newPos.y = p->pos.y - diff.y; newPos.z = - diff.z; } else { newPos.x = p->pos.x; newPos.y = p->pos.y; newPos.z = 0; } updateQuadWithParticle(p, newPos); //updateParticleImp(self, updateParticleSel, p, newPos); // update particle counter ++_particleIdx; } else { // life < 0 int currentIndex = p->atlasIndex; if( _particleIdx != _particleCount-1 ) { _particles[_particleIdx] = _particles[_particleCount-1]; } --_particleCount; if( _particleCount == 0 && _isAutoRemoveOnFinish ) { this->unscheduleUpdate(); _parent->removeChild(this, true); return; } } } //while _transformSystemDirty = false; } // only update gl buffer when visible if (_visible) { postStep(); } CC_PROFILER_STOP_CATEGORY(kProfilerCategoryParticles , "BillboardParticleSystem - update"); }