Пример #1
0
void TextureAtlas::setupVBOandVAO()
{
    glGenVertexArrays(1, &_VAOname);
    ccGLBindVAO(_VAOname);

#define kQuadSize sizeof(_quads[0].bl)

    glGenBuffers(2, &_buffersVBO[0]);

    glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(_quads[0]) * _capacity, _quads, GL_DYNAMIC_DRAW);

    // vertices
    glEnableVertexAttribArray(kVertexAttrib_Position);
    glVertexAttribPointer(kVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( V3F_C4B_T2F, vertices));

    // colors
    glEnableVertexAttribArray(kVertexAttrib_Color);
    glVertexAttribPointer(kVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (GLvoid*) offsetof( V3F_C4B_T2F, colors));

    // tex coords
    glEnableVertexAttribArray(kVertexAttrib_TexCoords);
    glVertexAttribPointer(kVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( V3F_C4B_T2F, texCoords));

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _buffersVBO[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(_indices[0]) * _capacity * 6, _indices, GL_STATIC_DRAW);

    // Must unbind the VAO before changing the element buffer.
    ccGLBindVAO(0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    CHECK_GL_ERROR_DEBUG();
}
void CCTextureAtlas::setupVBOandVAO ( KDvoid )
{
    glGenVertexArrays ( 1, &m_uVAOname );
    ccGLBindVAO ( 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_uCapacity, m_pQuads, GL_DYNAMIC_DRAW );

    // vertices
    glEnableVertexAttribArray ( kCCVertexAttrib_Position );
    glVertexAttribPointer ( kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, vertices ) );

    // colors
    glEnableVertexAttribArray ( kCCVertexAttrib_Color );
    glVertexAttribPointer ( kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, colors ) );

    // tex coords
    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_uCapacity * 6, m_pIndices, GL_STATIC_DRAW );

    ccGLBindVAO  ( 0 );
    glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, 0 );
    glBindBuffer ( GL_ARRAY_BUFFER, 0 );

    CHECK_GL_ERROR_DEBUG ( );
}
void CCParticleSystemQuad::setupVBOandVAO()
{
    glGenVertexArrays(1, &m_uVAOname);
    ccGLBindVAO(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);

    // vertices
    glEnableVertexAttribArray(kCCVertexAttrib_Position);
    glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, vertices));

    // colors
    glEnableVertexAttribArray(kCCVertexAttrib_Color);
    glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, colors));

    // tex coords
    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);

    // Must unbind the VAO before changing the element buffer.
    ccGLBindVAO(0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    CHECK_GL_ERROR_DEBUG();
}
Пример #4
0
void GLESDebugDraw::resetVertexBuffers()
{
#if CC_TEXTURE_ATLAS_USE_VAO
    ccGLBindVAO(0);
#endif
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}
Пример #5
0
void CCDrawNode::render()
{
    if (m_bDirty)
    {
        glBindBuffer(GL_ARRAY_BUFFER, m_uVbo);
        glBufferData(GL_ARRAY_BUFFER, sizeof(ccV2F_C4B_T2F)*m_uBufferCapacity, m_pBuffer, GL_STREAM_DRAW);
        m_bDirty = false;
    }
#if CC_TEXTURE_ATLAS_USE_VAO     
    ccGLBindVAO(m_uVao);
#else
    ccGLEnableVertexAttribs(kCCVertexAttribFlag_PosColorTex);
    glBindBuffer(GL_ARRAY_BUFFER, m_uVbo);
    // vertex
    glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, sizeof(ccV2F_C4B_T2F), (GLvoid *)offsetof(ccV2F_C4B_T2F, vertices));
    
    // color
    glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(ccV2F_C4B_T2F), (GLvoid *)offsetof(ccV2F_C4B_T2F, colors));
    
    // texcood
    glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, sizeof(ccV2F_C4B_T2F), (GLvoid *)offsetof(ccV2F_C4B_T2F, texCoords));
#endif

    glDrawArrays(GL_TRIANGLES, 0, m_nBufferCount);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    
    //CC_INCREMENT_GL_DRAWS(1);
}
Пример #6
0
bool CCDrawNode::init()
{
    m_sBlendFunc.src = CC_BLEND_SRC;
    m_sBlendFunc.dst = CC_BLEND_DST;

    setShaderProgram(CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionLengthTexureColor));
    
    ensureCapacity(512);
    
#if CC_TEXTURE_ATLAS_USE_VAO    
    glGenVertexArrays(1, &m_uVao);
    ccGLBindVAO(m_uVao);
#endif
    
    glGenBuffers(1, &m_uVbo);
    glBindBuffer(GL_ARRAY_BUFFER, m_uVbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(ccV2F_C4B_T2F)* m_uBufferCapacity, m_pBuffer, GL_STREAM_DRAW);
    
    glEnableVertexAttribArray(kCCVertexAttrib_Position);
    glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, sizeof(ccV2F_C4B_T2F), (GLvoid *)offsetof(ccV2F_C4B_T2F, vertices));
    
    glEnableVertexAttribArray(kCCVertexAttrib_Color);
    glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ccV2F_C4B_T2F), (GLvoid *)offsetof(ccV2F_C4B_T2F, colors));
    
    glEnableVertexAttribArray(kCCVertexAttrib_TexCoords);
    glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, sizeof(ccV2F_C4B_T2F), (GLvoid *)offsetof(ccV2F_C4B_T2F, texCoords));
    
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    
#if CC_TEXTURE_ATLAS_USE_VAO 
    ccGLBindVAO(0);
#endif
    
    CHECK_GL_ERROR_DEBUG();
    
    m_bDirty = true;

#if CC_ENABLE_CACHE_TEXTURE_DATA
    // Need to listen the event only when not use batchnode, because it will use VBO
    CCNotificationCenter::sharedNotificationCenter()->addObserver(this,
            callfuncO_selector(CCDrawNode::listenBackToForeground),
            EVENT_COME_TO_FOREGROUND,
            NULL);
#endif

    return true;
}
// overriding draw method
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
    //
    // Using VBO and VAO
    //
    ccGLBindVAO(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

#else
    //
    // Using VBO without VAO
    //

    #define kQuadSize sizeof(m_pQuads[0].bl)

    ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex );

    glBindBuffer(GL_ARRAY_BUFFER, m_pBuffersVBO[0]);
    // vertices
    glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, vertices));
    // colors
    glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, colors));
    // tex coords
    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();
}
Пример #8
0
bool DrawNode::init()
{
    _blendFunc.src = CC_BLEND_SRC;
    _blendFunc.dst = CC_BLEND_DST;

    setShaderProgram(ShaderCache::sharedShaderCache()->programForKey(kShader_PositionLengthTexureColor));
    
    ensureCapacity(512);
    
#if CC_TEXTURE_ATLAS_USE_VAO    
    glGenVertexArrays(1, &_vao);
    ccGLBindVAO(_vao);
#endif
    
    glGenBuffers(1, &_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, _vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(ccV2F_C4B_T2F)* _bufferCapacity, _buffer, GL_STREAM_DRAW);
    
    glEnableVertexAttribArray(kVertexAttrib_Position);
    glVertexAttribPointer(kVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, sizeof(ccV2F_C4B_T2F), (GLvoid *)offsetof(ccV2F_C4B_T2F, vertices));
    
    glEnableVertexAttribArray(kVertexAttrib_Color);
    glVertexAttribPointer(kVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ccV2F_C4B_T2F), (GLvoid *)offsetof(ccV2F_C4B_T2F, colors));
    
    glEnableVertexAttribArray(kVertexAttrib_TexCoords);
    glVertexAttribPointer(kVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, sizeof(ccV2F_C4B_T2F), (GLvoid *)offsetof(ccV2F_C4B_T2F, texCoords));
    
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    
#if CC_TEXTURE_ATLAS_USE_VAO 
    ccGLBindVAO(0);
#endif
    
    CHECK_GL_ERROR_DEBUG();
    
    _dirty = true;
    
    return true;
}
KDvoid CCTextureAtlas::mapBuffers ( KDvoid )
{
	ccGLBindVAO  ( 0 );

    glBindBuffer ( GL_ARRAY_BUFFER, m_pBuffersVBO [ 0 ] );
    glBufferData ( GL_ARRAY_BUFFER, sizeof ( m_pQuads [ 0 ] ) * m_uCapacity, 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_uCapacity * 6, m_pIndices, GL_STATIC_DRAW );
    glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, 0 );

    CHECK_GL_ERROR_DEBUG ( );
}
Пример #10
0
void CCTextureAtlas::mapBuffers()
{
    // Avoid changing the element buffer for whatever VAO might be bound.
    ccGLBindVAO(0);

    glBindBuffer(GL_ARRAY_BUFFER, m_pBuffersVBO[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0]) * m_uCapacity, 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_uCapacity * 6, m_pIndices, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    CHECK_GL_ERROR_DEBUG();
}
Пример #11
0
CADrawView::~CADrawView()
{
    free(m_pBuffer);
    m_pBuffer = NULL;
    
    glDeleteBuffers(1, &m_uVbo);
    m_uVbo = 0;
    
#if CC_TEXTURE_ATLAS_USE_VAO      
    glDeleteVertexArrays(1, &m_uVao);
    ccGLBindVAO(0);
    m_uVao = 0;
#endif

}
Пример #12
0
CCTextureAtlas::~CCTextureAtlas()
{
    CCLOGINFO("cocos2d: CCTextureAtlas deallocing %p.", this);
    
    CC_SAFE_FREE(m_pQuads);
    CC_SAFE_FREE(m_pIndices);
    
    glDeleteBuffers(2, m_pBuffersVBO);
    
#if CC_TEXTURE_ATLAS_USE_VAO
    glDeleteVertexArrays(1, &m_uVAOname);
    ccGLBindVAO(0);
#endif
    CC_SAFE_RELEASE(m_pTexture);
    
    CCNotificationCenter::sharedNotificationCenter()->removeObserver(this, EVNET_COME_TO_FOREGROUND);
}
Пример #13
0
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);
        ccGLBindVAO(0);
#endif
    }

#if CC_ENABLE_CACHE_TEXTURE_DATA
    CCNotificationCenter::sharedNotificationCenter()->removeObserver(this, EVENT_COME_TO_FOREGROUND);
#endif
}
Пример #14
0
CCDrawNode::~CCDrawNode()
{
    free(m_pBuffer);
    m_pBuffer = NULL;
    
    glDeleteBuffers(1, &m_uVbo);
    m_uVbo = 0;
    
#if CC_TEXTURE_ATLAS_USE_VAO      
    glDeleteVertexArrays(1, &m_uVao);
    ccGLBindVAO(0);
    m_uVao = 0;
#endif

#if CC_ENABLE_CACHE_TEXTURE_DATA
    CCNotificationCenter::sharedNotificationCenter()->removeObserver(this, EVENT_COME_TO_FOREGROUND);
#endif    
}
Пример #15
0
TextureAtlas::~TextureAtlas()
{
    CCLOGINFO("cocos2d: TextureAtlas deallocing %p.", this);

    CC_SAFE_FREE(_quads);
    CC_SAFE_FREE(_indices);

    glDeleteBuffers(2, _buffersVBO);

#if CC_TEXTURE_ATLAS_USE_VAO
    glDeleteVertexArrays(1, &_VAOname);
    ccGLBindVAO(0);
#endif
    CC_SAFE_RELEASE(_texture);
    
#if CC_ENABLE_CACHE_TEXTURE_DATA
    NotificationCenter::getInstance()->removeObserver(this, EVNET_COME_TO_FOREGROUND);
#endif
}
Пример #16
0
void CCParticleSystemQuad::setBatchNode(CCParticleBatchNode * batchNode)
{
    if( m_pBatchNode != batchNode ) 
    {
        CCParticleBatchNode* oldBatch = m_pBatchNode;

        CCParticleSystem::setBatchNode(batchNode);

        // NEW: is self render ?
        if( ! batchNode ) 
        {
            allocMemory();
            initIndices();
            setTexture(oldBatch->getTexture());
#if CC_TEXTURE_ATLAS_USE_VAO
            setupVBOandVAO();
#else
            setupVBO();
#endif
        }
        // OLD: was it self render ? cleanup
        else if( !oldBatch )
        {
            // copy current state to batch
            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]);
            memset(m_pBuffersVBO, 0, sizeof(m_pBuffersVBO));
#if CC_TEXTURE_ATLAS_USE_VAO
            glDeleteVertexArrays(1, &m_uVAOname);
            ccGLBindVAO(0);
            m_uVAOname = 0;
#endif
        }
    }
}
Пример #17
0
void ccGLEnableVertexAttribs( unsigned int flags )
{
    ccGLBindVAO(0);
    
    /* Position */
    bool enablePosition = flags & kCCVertexAttribFlag_Position;

    if( enablePosition != s_bVertexAttribPosition ) {
        if( enablePosition )
            glEnableVertexAttribArray( kCCVertexAttrib_Position );
        else
            glDisableVertexAttribArray( kCCVertexAttrib_Position );

        s_bVertexAttribPosition = enablePosition;
    }

    /* Color */
    bool enableColor = (flags & kCCVertexAttribFlag_Color) != 0 ? true : false;

    if( enableColor != s_bVertexAttribColor ) {
        if( enableColor )
            glEnableVertexAttribArray( kCCVertexAttrib_Color );
        else
            glDisableVertexAttribArray( kCCVertexAttrib_Color );

        s_bVertexAttribColor = enableColor;
    }

    /* Tex Coords */
    bool enableTexCoords = (flags & kCCVertexAttribFlag_TexCoords) != 0 ? true : false;

    if( enableTexCoords != s_bVertexAttribTexCoords ) {
        if( enableTexCoords )
            glEnableVertexAttribArray( kCCVertexAttrib_TexCoords );
        else
            glDisableVertexAttribArray( kCCVertexAttrib_TexCoords );

        s_bVertexAttribTexCoords = enableTexCoords;
    }
}
Пример #18
0
void TextureAtlas::drawNumberOfQuads(int numberOfQuads, int start)
{
    CCASSERT(numberOfQuads>=0 && start>=0, "numberOfQuads and start must be >= 0");

    if(!numberOfQuads)
        return;

    ccGLBindTexture2D(_texture->getName());

#if CC_TEXTURE_ATLAS_USE_VAO

    //
    // Using VBO and VAO
    //

    // XXX: update is done in draw... perhaps it should be done in a timer
    if (_dirty) 
    {
        glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]);
        // option 1: subdata
        //glBufferSubData(GL_ARRAY_BUFFER, sizeof(_quads[0])*start, sizeof(_quads[0]) * n , &_quads[start] );
		
		// option 2: data
        //		glBufferData(GL_ARRAY_BUFFER, sizeof(quads_[0]) * (n-start), &quads_[start], GL_DYNAMIC_DRAW);
		
		// option 3: orphaning + glMapBuffer
		glBufferData(GL_ARRAY_BUFFER, sizeof(_quads[0]) * (numberOfQuads-start), NULL, GL_DYNAMIC_DRAW);
		void *buf = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
		memcpy(buf, _quads, sizeof(_quads[0])* (numberOfQuads-start));
		glUnmapBuffer(GL_ARRAY_BUFFER);
		
		glBindBuffer(GL_ARRAY_BUFFER, 0);

        _dirty = false;
    }

    ccGLBindVAO(_VAOname);

#if CC_REBIND_INDICES_BUFFER
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _buffersVBO[1]);
#endif

#if CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP
    glDrawElements(GL_TRIANGLE_STRIP, (GLsizei) numberOfQuads*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(_indices[0])) );
#else
    glDrawElements(GL_TRIANGLES, (GLsizei) numberOfQuads*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(_indices[0])) );
#endif // CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP

#if CC_REBIND_INDICES_BUFFER
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
#endif

//    glBindVertexArray(0);

#else // ! CC_TEXTURE_ATLAS_USE_VAO

    //
    // Using VBO without VAO
    //

#define kQuadSize sizeof(_quads[0].bl)
    glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]);

    // XXX: update is done in draw... perhaps it should be done in a timer
    if (_dirty) 
    {
        glBufferSubData(GL_ARRAY_BUFFER, sizeof(_quads[0])*start, sizeof(_quads[0]) * numberOfQuads , &_quads[start] );
        _dirty = false;
    }

    ccGLEnableVertexAttribs(kVertexAttribFlag_PosColorTex);

    // vertices
    glVertexAttribPointer(kVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof(V3F_C4B_T2F, vertices));

    // colors
    glVertexAttribPointer(kVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (GLvoid*) offsetof(V3F_C4B_T2F, colors));

    // tex coords
    glVertexAttribPointer(kVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof(V3F_C4B_T2F, texCoords));

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _buffersVBO[1]);

#if CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP
    glDrawElements(GL_TRIANGLE_STRIP, (GLsizei)numberOfQuads*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(_indices[0])));
#else
    glDrawElements(GL_TRIANGLES, (GLsizei)numberOfQuads*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(_indices[0])));
#endif // CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

#endif // CC_TEXTURE_ATLAS_USE_VAO

    CC_INCREMENT_GL_DRAWS(1);
    CHECK_GL_ERROR_DEBUG();
}
KDvoid CCTextureAtlas::drawNumberOfQuads ( KDuint uNumber, KDuint uStart )
{
	if ( 0 == uNumber )
	{
		return;
	}

    ccGLBindTexture2D ( m_pTexture->getName ( ) );

#if CC_TEXTURE_ATLAS_USE_VAO

    //
    // Using VBO and VAO
    //

    // XXX: update is done in draw... perhaps it should be done in a timer
    if ( m_bDirty ) 
    {
        glBindBuffer    ( GL_ARRAY_BUFFER, m_pBuffersVBO[0] );
		
		// option 1: subdata
        // glBufferSubData ( GL_ARRAY_BUFFER, sizeof ( m_pQuads[0] ) * uStart, sizeof ( m_pQuads[0] ) * uNumber , &m_pQuads [ uStart ] );

		// option 2: data
        // glBufferData ( GL_ARRAY_BUFFER, sizeof ( m_pQuads[0] ) * ( n - uStart ), &m_pQuads [ uStart ], GL_DYNAMIC_DRAW );
		
		// option 3: orphaning + glMapBuffer
		glBufferData    ( GL_ARRAY_BUFFER, sizeof ( m_pQuads[0] ) * ( n - uStart ), KD_NULL, GL_DYNAMIC_DRAW );
		KDvoid*  pBuff = glMapBuffer ( GL_ARRAY_BUFFER, GL_WRITE_ONLY );
		kdMemcpy ( pBuff, m_pQuads, sizeof ( m_pQuads [ 0 ] ) * ( n - uStart ) );
		glUnmapBuffer ( GL_ARRAY_BUFFER );

        glBindBuffer    ( GL_ARRAY_BUFFER, 0 );

        m_bDirty = KD_FALSE;
    }

    ccGLBindVAO ( m_uVAOname );

#if CC_REBIND_INDICES_BUFFER
    glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, m_pBuffersVBO[1] );
#endif

    glDrawElements ( GL_TRIANGLES, (GLsizei) uNumber * 6, GL_UNSIGNED_SHORT, (GLvoid*) ( uStart * 6 * sizeof ( m_pIndices[0] ) ) );

#if CC_REBIND_INDICES_BUFFER
    glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, 0 );
#endif

//    glBindVertexArray ( 0 );

#else // CC_TEXTURE_ATLAS_USE_VAO

    //
    // Using VBO without VAO
    //

#define kQuadSize sizeof(m_pQuads[0].bl)
    glBindBuffer ( GL_ARRAY_BUFFER, m_pBuffersVBO[0] );

    // XXX: update is done in draw... perhaps it should be done in a timer
    if ( m_bDirty ) 
    {
		glBufferSubData ( GL_ARRAY_BUFFER, sizeof ( m_pQuads[0] ) * uStart, sizeof ( m_pQuads[0] ) * uNumber , &m_pQuads[ uStart ] );
        m_bDirty = KD_FALSE;
    }

	ccGLEnableVertexAttribs ( kCCVertexAttribFlag_PosColorTex );

    ccGLVertexAttribPointer ( kCCVertexAttrib_Position , 3, GL_FLOAT        , GL_FALSE, kQuadSize, (GLvoid*) offsetof ( ccV3F_C4B_T2F, vertices  ) );
    ccGLVertexAttribPointer ( kCCVertexAttrib_Color    , 4, GL_UNSIGNED_BYTE, GL_TRUE , kQuadSize, (GLvoid*) offsetof ( ccV3F_C4B_T2F, colors    ) );
    ccGLVertexAttribPointer ( 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) uNumber * 6, GL_UNSIGNED_SHORT, (GLvoid*) ( uStart * 6 * sizeof ( m_pIndices[0] ) ) );

    glBindBuffer ( GL_ARRAY_BUFFER, 0 );
    glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, 0 );

#endif // CC_TEXTURE_ATLAS_USE_VAO

    CC_INCREMENT_GL_DRAWS ( 1 );
    CHECK_GL_ERROR_DEBUG ( );
}