KDvoid Controller::draw ( KDvoid )
{
    CC_NODE_DRAW_SETUP ( );
    
	GLfloat  fVertices [ ] = 
	{
		   0,  512, 
		1024,  512, 
		   0,    0, 
		1024,    0, 
	};

	GLfloat  fCoords [ ] =
	{
		   0,  0,
		   1,  0,
		   0,  1, 
		   1,  1, 
	};

	ccGLBindTexture2D ( m_uTexture );
    ccGLEnableVertexAttribs ( kCCVertexAttribFlag_Position | kCCVertexAttribFlag_TexCoords );

	if ( m_pDrawFunc )
	{
		m_pDrawFunc ( KD_GET_UST2MSEC );
	}

	ccGLVertexAttribPointer ( kCCVertexAttrib_Position , 2, GL_FLOAT, GL_FALSE, 0, fVertices );
	ccGLVertexAttribPointer ( kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, 0, fCoords );	

	glDrawArrays ( GL_TRIANGLE_STRIP, 0, 4 );

	ccGLBindTexture2D ( 0 );
}
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 ( );
}
// 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
    //
    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
    //
    // 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));
	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) 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();
}