2013-12-18 10:12:15 +08:00
/****************************************************************************
2014-01-07 11:25:07 +08:00
Copyright ( c ) 2013 - 2014 Chukong Technologies Inc .
2013-12-18 10:12:15 +08:00
http : //www.cocos2d-x.org
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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-11-05 01:14:22 +08:00
2014-01-17 13:35:58 +08:00
# include "renderer/CCRenderer.h"
2013-12-26 16:36:03 +08:00
# include "renderer/CCQuadCommand.h"
2014-01-16 08:07:38 +08:00
# include "renderer/CCBatchCommand.h"
2014-01-17 13:35:58 +08:00
# include "renderer/CCCustomCommand.h"
# include "renderer/CCGroupCommand.h"
# include "CCShaderCache.h"
# include "ccGLStateCache.h"
2013-12-05 09:02:02 +08:00
# include "CCConfiguration.h"
2013-12-31 10:54:37 +08:00
# include "CCDirector.h"
# include "CCEventDispatcher.h"
# include "CCEventListenerCustom.h"
2013-12-17 14:18:41 +08:00
# include "CCEventType.h"
2014-01-19 03:35:27 +08:00
# include <algorithm>
2013-11-05 01:14:22 +08:00
NS_CC_BEGIN
2014-01-18 15:10:04 +08:00
bool compareRenderCommand ( RenderCommand * a , RenderCommand * b )
{
2014-01-19 03:35:27 +08:00
return a - > getGlobalOrder ( ) < b - > getGlobalOrder ( ) ;
2014-01-18 15:10:04 +08:00
}
void RenderQueue : : push_back ( RenderCommand * command )
{
2014-01-19 03:35:27 +08:00
float z = command - > getGlobalOrder ( ) ;
2014-01-18 15:10:04 +08:00
if ( z < 0 )
_queueNegZ . push_back ( command ) ;
2014-01-19 03:35:27 +08:00
else if ( z > 0 )
2014-01-18 15:10:04 +08:00
_queuePosZ . push_back ( command ) ;
else
_queue0 . push_back ( command ) ;
}
ssize_t RenderQueue : : size ( ) const
{
return _queueNegZ . size ( ) + _queue0 . size ( ) + _queuePosZ . size ( ) ;
}
void RenderQueue : : sort ( )
{
// Don't sort _queue0, it already comes sorted
std : : sort ( std : : begin ( _queueNegZ ) , std : : end ( _queueNegZ ) , compareRenderCommand ) ;
std : : sort ( std : : begin ( _queuePosZ ) , std : : end ( _queuePosZ ) , compareRenderCommand ) ;
}
2014-01-19 03:35:27 +08:00
RenderCommand * RenderQueue : : operator [ ] ( ssize_t index ) const
2014-01-18 15:10:04 +08:00
{
if ( index < _queueNegZ . size ( ) )
return _queueNegZ [ index ] ;
2013-11-05 01:14:22 +08:00
2014-01-18 15:10:04 +08:00
index - = _queueNegZ . size ( ) ;
if ( index < _queue0 . size ( ) )
return _queue0 [ index ] ;
index - = _queue0 . size ( ) ;
if ( index < _queuePosZ . size ( ) )
return _queuePosZ [ index ] ;
CCASSERT ( false , " invalid index " ) ;
return nullptr ;
}
void RenderQueue : : clear ( )
{
_queueNegZ . clear ( ) ;
_queue0 . clear ( ) ;
_queuePosZ . clear ( ) ;
}
2013-11-05 01:14:22 +08:00
2014-01-18 15:10:04 +08:00
//
//
//
2013-12-18 09:50:17 +08:00
# define DEFAULT_RENDER_QUEUE 0
2013-11-05 01:14:22 +08:00
Renderer : : Renderer ( )
2013-11-08 02:09:53 +08:00
: _lastMaterialID ( 0 )
2013-12-27 15:06:16 +08:00
, _numQuads ( 0 )
2013-11-22 08:36:19 +08:00
, _glViewAssigned ( false )
2013-12-31 11:02:01 +08:00
# if CC_ENABLE_CACHE_TEXTURE_DATA
2013-12-31 10:54:37 +08:00
, _cacheTextureListener ( nullptr )
2013-12-31 11:02:01 +08:00
# endif
2013-11-08 07:48:37 +08:00
{
2013-11-21 03:05:01 +08:00
_commandGroupStack . push ( DEFAULT_RENDER_QUEUE ) ;
2013-11-14 09:31:12 +08:00
RenderQueue defaultRenderQueue ;
_renderGroups . push_back ( defaultRenderQueue ) ;
2013-12-18 14:36:49 +08:00
RenderStackElement elelment = { DEFAULT_RENDER_QUEUE , 0 } ;
_renderStack . push ( elelment ) ;
2013-11-08 07:48:37 +08:00
}
Renderer : : ~ Renderer ( )
2013-11-05 01:14:22 +08:00
{
2013-11-14 09:31:12 +08:00
_renderGroups . clear ( ) ;
2013-11-22 08:36:19 +08:00
glDeleteBuffers ( 2 , _buffersVBO ) ;
2013-12-05 09:02:02 +08:00
if ( Configuration : : getInstance ( ) - > supportsShareableVAO ( ) )
{
2013-11-23 02:24:52 +08:00
glDeleteVertexArrays ( 1 , & _quadVAO ) ;
2013-11-22 08:36:19 +08:00
GL : : bindVAO ( 0 ) ;
2013-12-05 09:02:02 +08:00
}
2013-12-27 11:56:56 +08:00
# if CC_ENABLE_CACHE_TEXTURE_DATA
2013-12-31 10:54:37 +08:00
Director : : getInstance ( ) - > getEventDispatcher ( ) - > removeEventListener ( _cacheTextureListener ) ;
2013-12-27 11:56:56 +08:00
# endif
2013-11-08 08:50:53 +08:00
}
2013-11-22 08:36:19 +08:00
void Renderer : : initGLView ( )
{
2013-12-27 11:56:56 +08:00
# if CC_ENABLE_CACHE_TEXTURE_DATA
2013-12-31 10:54:37 +08:00
_cacheTextureListener = EventListenerCustom : : create ( EVENT_COME_TO_FOREGROUND , [ this ] ( EventCustom * event ) {
/** listen the event that coming to foreground on Android */
this - > setupBuffer ( ) ;
} ) ;
Director : : getInstance ( ) - > getEventDispatcher ( ) - > addEventListenerWithFixedPriority ( _cacheTextureListener , - 1 ) ;
2013-12-05 09:02:02 +08:00
# endif
2013-11-22 08:36:19 +08:00
setupIndices ( ) ;
2013-12-05 09:02:02 +08:00
setupBuffer ( ) ;
2013-11-22 08:36:19 +08:00
_glViewAssigned = true ;
2013-11-08 08:50:53 +08:00
}
void Renderer : : setupIndices ( )
{
2013-12-19 05:52:10 +08:00
for ( int i = 0 ; i < VBO_SIZE ; i + + )
2013-11-08 08:50:53 +08:00
{
_indices [ i * 6 + 0 ] = ( GLushort ) ( i * 4 + 0 ) ;
_indices [ i * 6 + 1 ] = ( GLushort ) ( i * 4 + 1 ) ;
_indices [ i * 6 + 2 ] = ( GLushort ) ( i * 4 + 2 ) ;
_indices [ i * 6 + 3 ] = ( GLushort ) ( i * 4 + 3 ) ;
_indices [ i * 6 + 4 ] = ( GLushort ) ( i * 4 + 2 ) ;
_indices [ i * 6 + 5 ] = ( GLushort ) ( i * 4 + 1 ) ;
}
}
2013-12-05 09:02:02 +08:00
void Renderer : : setupBuffer ( )
{
if ( Configuration : : getInstance ( ) - > supportsShareableVAO ( ) )
{
setupVBOAndVAO ( ) ;
}
else
{
setupVBO ( ) ;
}
}
2013-11-08 08:50:53 +08:00
void Renderer : : setupVBOAndVAO ( )
{
2013-11-23 02:24:52 +08:00
glGenVertexArrays ( 1 , & _quadVAO ) ;
GL : : bindVAO ( _quadVAO ) ;
2013-11-08 08:50:53 +08:00
glGenBuffers ( 2 , & _buffersVBO [ 0 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , _buffersVBO [ 0 ] ) ;
2013-12-19 05:52:10 +08:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( _quads [ 0 ] ) * VBO_SIZE , _quads , GL_DYNAMIC_DRAW ) ;
2013-11-08 08:50:53 +08:00
// vertices
glEnableVertexAttribArray ( GLProgram : : VERTEX_ATTRIB_POSITION ) ;
glVertexAttribPointer ( GLProgram : : VERTEX_ATTRIB_POSITION , 3 , GL_FLOAT , GL_FALSE , sizeof ( V3F_C4B_T2F ) , ( GLvoid * ) offsetof ( V3F_C4B_T2F , vertices ) ) ;
// colors
glEnableVertexAttribArray ( GLProgram : : VERTEX_ATTRIB_COLOR ) ;
glVertexAttribPointer ( GLProgram : : VERTEX_ATTRIB_COLOR , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( V3F_C4B_T2F ) , ( GLvoid * ) offsetof ( V3F_C4B_T2F , colors ) ) ;
// tex coords
glEnableVertexAttribArray ( GLProgram : : VERTEX_ATTRIB_TEX_COORDS ) ;
glVertexAttribPointer ( GLProgram : : VERTEX_ATTRIB_TEX_COORDS , 2 , GL_FLOAT , GL_FALSE , sizeof ( V3F_C4B_T2F ) , ( GLvoid * ) offsetof ( V3F_C4B_T2F , texCoords ) ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , _buffersVBO [ 1 ] ) ;
2013-12-19 05:52:10 +08:00
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , sizeof ( _indices [ 0 ] ) * VBO_SIZE * 6 , _indices , GL_STATIC_DRAW ) ;
2013-11-08 08:50:53 +08:00
// Must unbind the VAO before changing the element buffer.
GL : : bindVAO ( 0 ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
CHECK_GL_ERROR_DEBUG ( ) ;
2013-11-05 01:14:22 +08:00
}
2013-12-05 09:02:02 +08:00
void Renderer : : setupVBO ( )
{
glGenBuffers ( 2 , & _buffersVBO [ 0 ] ) ;
mapBuffers ( ) ;
}
void Renderer : : mapBuffers ( )
{
// Avoid changing the element buffer for whatever VAO might be bound.
GL : : bindVAO ( 0 ) ;
glBindBuffer ( GL_ARRAY_BUFFER , _buffersVBO [ 0 ] ) ;
2013-12-19 05:52:10 +08:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( _quads [ 0 ] ) * VBO_SIZE , _quads , GL_DYNAMIC_DRAW ) ;
2013-12-05 09:02:02 +08:00
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , _buffersVBO [ 1 ] ) ;
2013-12-19 05:52:10 +08:00
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , sizeof ( _indices [ 0 ] ) * VBO_SIZE * 6 , _indices , GL_STATIC_DRAW ) ;
2013-12-05 09:02:02 +08:00
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
CHECK_GL_ERROR_DEBUG ( ) ;
}
2013-11-16 09:32:29 +08:00
void Renderer : : addCommand ( RenderCommand * command )
{
2014-01-17 14:29:25 +08:00
int renderQueue = _commandGroupStack . top ( ) ;
addCommand ( command , renderQueue ) ;
2013-11-16 09:32:29 +08:00
}
void Renderer : : addCommand ( RenderCommand * command , int renderQueue )
2013-11-05 01:14:22 +08:00
{
2014-01-17 14:29:25 +08:00
CCASSERT ( renderQueue > = 0 , " Invalid render queue " ) ;
CCASSERT ( command - > getType ( ) ! = RenderCommand : : Type : : UNKNOWN_COMMAND , " Invalid Command Type " ) ;
2013-11-14 09:31:12 +08:00
_renderGroups [ renderQueue ] . push_back ( command ) ;
2013-11-05 01:14:22 +08:00
}
2013-11-21 03:05:01 +08:00
void Renderer : : pushGroup ( int renderQueueID )
{
_commandGroupStack . push ( renderQueueID ) ;
}
void Renderer : : popGroup ( )
{
_commandGroupStack . pop ( ) ;
}
2013-11-16 03:29:11 +08:00
int Renderer : : createRenderQueue ( )
{
RenderQueue newRenderQueue ;
_renderGroups . push_back ( newRenderQueue ) ;
2013-11-21 03:05:01 +08:00
return ( int ) _renderGroups . size ( ) - 1 ;
2013-11-16 03:29:11 +08:00
}
2013-11-05 01:14:22 +08:00
void Renderer : : render ( )
{
2013-11-07 06:57:42 +08:00
//Uncomment this once everything is rendered by new renderer
2013-11-05 01:14:22 +08:00
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2013-11-07 08:39:20 +08:00
//TODO setup camera or MVP
2013-11-22 08:36:19 +08:00
if ( _glViewAssigned )
2013-11-14 09:31:12 +08:00
{
2013-11-22 08:36:19 +08:00
//Process render commands
//1. Sort render commands based on ID
2014-01-18 15:10:04 +08:00
for ( auto & renderqueue : _renderGroups )
2013-11-14 09:31:12 +08:00
{
2014-01-18 15:10:04 +08:00
renderqueue . sort ( ) ;
2013-11-22 08:36:19 +08:00
}
while ( ! _renderStack . empty ( ) )
{
RenderQueue currRenderQueue = _renderGroups [ _renderStack . top ( ) . renderQueueID ] ;
size_t len = currRenderQueue . size ( ) ;
//Process RenderQueue
for ( size_t i = _renderStack . top ( ) . currentIndex ; i < len ; i + + )
2013-11-14 09:31:12 +08:00
{
2014-01-22 16:03:04 +08:00
_renderStack . top ( ) . currentIndex = i ;
2013-11-22 08:36:19 +08:00
auto command = currRenderQueue [ i ] ;
2013-12-18 10:12:15 +08:00
auto commandType = command - > getType ( ) ;
2013-11-22 08:36:19 +08:00
2013-12-18 10:12:15 +08:00
if ( commandType = = RenderCommand : : Type : : QUAD_COMMAND )
2013-11-14 09:31:12 +08:00
{
2014-01-19 03:35:27 +08:00
auto cmd = static_cast < QuadCommand * > ( command ) ;
2014-01-22 15:18:27 +08:00
CCASSERT ( nullptr ! = cmd , " Illegal command for RenderCommand Taged as QUAD_COMMAND " ) ;
2013-12-18 10:12:15 +08:00
2013-11-22 08:36:19 +08:00
//Batch quads
2014-01-22 15:18:27 +08:00
if ( _numQuads + cmd - > getQuadCount ( ) > VBO_SIZE )
2013-11-22 08:36:19 +08:00
{
2014-01-22 15:37:25 +08:00
CCASSERT ( cmd - > getQuadCount ( ) > = 0 & & cmd - > getQuadCount ( ) < VBO_SIZE , " VBO is not big enough for quad data, please break the quad data down or use customized render command " ) ;
2013-12-05 11:05:17 +08:00
2013-11-22 08:36:19 +08:00
//Draw batched quads if VBO is full
drawBatchedQuads ( ) ;
}
2014-01-22 15:18:27 +08:00
_batchedQuadCommands . push_back ( cmd ) ;
memcpy ( _quads + _numQuads , cmd - > getQuads ( ) , sizeof ( V3F_C4B_T2F_Quad ) * cmd - > getQuadCount ( ) ) ;
convertToWorldCoordiantes ( _quads + _numQuads , cmd - > getQuadCount ( ) , cmd - > getModelView ( ) ) ;
2013-12-06 06:25:45 +08:00
2014-01-22 15:18:27 +08:00
_numQuads + = cmd - > getQuadCount ( ) ;
2013-11-22 08:36:19 +08:00
}
2013-12-18 10:12:15 +08:00
else if ( commandType = = RenderCommand : : Type : : CUSTOM_COMMAND )
2013-11-22 08:36:19 +08:00
{
flush ( ) ;
2014-01-19 03:35:27 +08:00
auto cmd = static_cast < CustomCommand * > ( command ) ;
2013-11-22 08:36:19 +08:00
cmd - > execute ( ) ;
}
2014-01-16 08:07:38 +08:00
else if ( commandType = = RenderCommand : : Type : : BATCH_COMMAND )
{
flush ( ) ;
2014-01-19 03:35:27 +08:00
auto cmd = static_cast < BatchCommand * > ( command ) ;
2014-01-16 08:07:38 +08:00
cmd - > execute ( ) ;
}
2013-12-18 10:12:15 +08:00
else if ( commandType = = RenderCommand : : Type : : GROUP_COMMAND )
2013-11-22 08:36:19 +08:00
{
flush ( ) ;
2014-01-19 03:35:27 +08:00
auto cmd = static_cast < GroupCommand * > ( command ) ;
2013-11-22 08:36:19 +08:00
_renderStack . top ( ) . currentIndex = i + 1 ;
//push new renderQueue to renderStack
2013-12-18 14:36:49 +08:00
RenderStackElement element = { cmd - > getRenderQueueID ( ) , 0 } ;
_renderStack . push ( element ) ;
2013-11-22 08:36:19 +08:00
//Exit current loop
break ;
2013-11-14 09:31:12 +08:00
}
else
{
2014-01-17 14:29:25 +08:00
CCASSERT ( true , " Invalid command " ) ;
2013-11-22 08:36:19 +08:00
flush ( ) ;
2013-11-14 09:31:12 +08:00
}
}
2013-11-22 08:36:19 +08:00
//Draw the batched quads
drawBatchedQuads ( ) ;
currRenderQueue = _renderGroups [ _renderStack . top ( ) . renderQueueID ] ;
len = currRenderQueue . size ( ) ;
//If pop the render stack if we already processed all the commands
if ( _renderStack . top ( ) . currentIndex + 1 > = len )
2013-11-14 09:31:12 +08:00
{
2013-11-22 08:36:19 +08:00
_renderStack . pop ( ) ;
2013-11-14 09:31:12 +08:00
}
}
}
2013-11-05 01:14:22 +08:00
2013-11-15 02:35:28 +08:00
for ( size_t j = 0 ; j < _renderGroups . size ( ) ; j + + )
2013-11-05 01:14:22 +08:00
{
2013-12-27 14:02:17 +08:00
//commands are owned by nodes
// for (const auto &cmd : _renderGroups[j])
// {
// cmd->releaseToCommandPool();
// }
2013-11-15 02:35:28 +08:00
_renderGroups [ j ] . clear ( ) ;
2013-11-11 16:14:29 +08:00
}
2013-11-22 08:36:19 +08:00
//Clear the stack incase gl view hasn't been initialized yet
while ( ! _renderStack . empty ( ) )
{
_renderStack . pop ( ) ;
}
2013-12-18 14:36:49 +08:00
RenderStackElement element = { DEFAULT_RENDER_QUEUE , 0 } ;
_renderStack . push ( element ) ;
2013-11-11 16:14:29 +08:00
_lastMaterialID = 0 ;
}
2013-11-09 04:06:39 +08:00
2014-01-16 06:35:26 +08:00
void Renderer : : convertToWorldCoordiantes ( V3F_C4B_T2F_Quad * quads , ssize_t quantity , const kmMat4 & modelView )
{
2014-01-17 13:35:58 +08:00
// kmMat4 matrixP, mvp;
// kmGLGetMatrix(KM_GL_PROJECTION, &matrixP);
// kmMat4Multiply(&mvp, &matrixP, &modelView);
2014-01-16 06:35:26 +08:00
for ( ssize_t i = 0 ; i < quantity ; + + i ) {
V3F_C4B_T2F_Quad * q = & quads [ i ] ;
2014-01-16 11:10:40 +08:00
kmVec3 * vec1 = ( kmVec3 * ) & q - > bl . vertices ;
kmVec3Transform ( vec1 , vec1 , & modelView ) ;
kmVec3 * vec2 = ( kmVec3 * ) & q - > br . vertices ;
kmVec3Transform ( vec2 , vec2 , & modelView ) ;
kmVec3 * vec3 = ( kmVec3 * ) & q - > tr . vertices ;
kmVec3Transform ( vec3 , vec3 , & modelView ) ;
kmVec3 * vec4 = ( kmVec3 * ) & q - > tl . vertices ;
kmVec3Transform ( vec4 , vec4 , & modelView ) ;
2014-01-16 06:35:26 +08:00
}
}
2013-11-11 16:14:29 +08:00
void Renderer : : drawBatchedQuads ( )
{
2013-11-19 07:52:47 +08:00
//TODO we can improve the draw performance by insert material switching command before hand.
2013-11-14 02:26:26 +08:00
2013-11-11 16:14:29 +08:00
int quadsToDraw = 0 ;
int startQuad = 0 ;
2013-11-05 01:14:22 +08:00
2013-11-11 16:14:29 +08:00
//Upload buffer to VBO
2014-01-22 15:18:27 +08:00
if ( _numQuads < = 0 | | 0 = = _batchedQuadCommands . size ( ) )
2013-11-19 07:52:47 +08:00
{
2013-11-11 16:14:29 +08:00
return ;
2013-11-19 07:52:47 +08:00
}
2013-11-11 16:14:29 +08:00
2013-12-05 09:02:02 +08:00
if ( Configuration : : getInstance ( ) - > supportsShareableVAO ( ) )
{
//Set VBO data
glBindBuffer ( GL_ARRAY_BUFFER , _buffersVBO [ 0 ] ) ;
2013-11-11 16:14:29 +08:00
2014-01-17 13:35:58 +08:00
// 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
2013-12-18 17:47:20 +08:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( _quads [ 0 ] ) * ( _numQuads ) , nullptr , GL_DYNAMIC_DRAW ) ;
2013-12-05 09:02:02 +08:00
void * buf = glMapBuffer ( GL_ARRAY_BUFFER , GL_WRITE_ONLY ) ;
memcpy ( buf , _quads , sizeof ( _quads [ 0 ] ) * ( _numQuads ) ) ;
glUnmapBuffer ( GL_ARRAY_BUFFER ) ;
2013-11-11 16:14:29 +08:00
2013-12-05 09:02:02 +08:00
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
2013-11-11 16:14:29 +08:00
2013-12-05 09:02:02 +08:00
//Bind VAO
GL : : bindVAO ( _quadVAO ) ;
}
else
{
# define kQuadSize sizeof(_quads[0].bl)
glBindBuffer ( GL_ARRAY_BUFFER , _buffersVBO [ 0 ] ) ;
2014-01-17 07:02:39 +08:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( _quads [ 0 ] ) * _numQuads , _quads , GL_DYNAMIC_DRAW ) ;
2013-12-05 09:02:02 +08:00
GL : : enableVertexAttribs ( GL : : VERTEX_ATTRIB_FLAG_POS_COLOR_TEX ) ;
// vertices
glVertexAttribPointer ( GLProgram : : VERTEX_ATTRIB_POSITION , 3 , GL_FLOAT , GL_FALSE , kQuadSize , ( GLvoid * ) offsetof ( V3F_C4B_T2F , vertices ) ) ;
// colors
glVertexAttribPointer ( GLProgram : : VERTEX_ATTRIB_COLOR , 4 , GL_UNSIGNED_BYTE , GL_TRUE , kQuadSize , ( GLvoid * ) offsetof ( V3F_C4B_T2F , colors ) ) ;
// tex coords
glVertexAttribPointer ( GLProgram : : VERTEX_ATTRIB_TEX_COORDS , 2 , GL_FLOAT , GL_FALSE , kQuadSize , ( GLvoid * ) offsetof ( V3F_C4B_T2F , texCoords ) ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , _buffersVBO [ 1 ] ) ;
}
2013-11-11 16:14:29 +08:00
2013-11-12 03:54:08 +08:00
//Start drawing verties in batch
2014-01-22 15:18:27 +08:00
for ( auto i = _batchedQuadCommands . begin ( ) ; i ! = _batchedQuadCommands . end ( ) ; + + i )
2013-11-11 16:14:29 +08:00
{
2014-01-22 15:52:00 +08:00
QuadCommand * cmd = * i ;
if ( _lastMaterialID ! = cmd - > getMaterialID ( ) )
2013-11-11 16:14:29 +08:00
{
2014-01-22 15:52:00 +08:00
//Draw quads
if ( quadsToDraw > 0 )
2013-11-09 04:06:39 +08:00
{
2014-01-22 15:52:00 +08:00
glDrawElements ( GL_TRIANGLES , ( GLsizei ) quadsToDraw * 6 , GL_UNSIGNED_SHORT , ( GLvoid * ) ( startQuad * 6 * sizeof ( _indices [ 0 ] ) ) ) ;
CC_INCREMENT_GL_DRAWS ( 1 ) ;
2013-11-09 04:06:39 +08:00
2014-01-22 15:52:00 +08:00
startQuad + = quadsToDraw ;
quadsToDraw = 0 ;
2013-11-09 04:06:39 +08:00
}
2013-11-05 01:14:22 +08:00
2014-01-22 15:52:00 +08:00
//Use new material
cmd - > useMaterial ( ) ;
_lastMaterialID = cmd - > getMaterialID ( ) ;
2013-11-11 16:14:29 +08:00
}
2014-01-22 15:52:00 +08:00
quadsToDraw + = cmd - > getQuadCount ( ) ;
2013-11-05 01:14:22 +08:00
}
2013-11-12 03:54:08 +08:00
//Draw any remaining quad
if ( quadsToDraw > 0 )
{
glDrawElements ( GL_TRIANGLES , ( GLsizei ) quadsToDraw * 6 , GL_UNSIGNED_SHORT , ( GLvoid * ) ( startQuad * 6 * sizeof ( _indices [ 0 ] ) ) ) ;
2013-11-23 09:14:24 +08:00
CC_INCREMENT_GL_DRAWS ( 1 ) ;
2013-11-12 03:54:08 +08:00
}
2013-11-08 07:48:37 +08:00
2013-12-05 09:02:02 +08:00
if ( Configuration : : getInstance ( ) - > supportsShareableVAO ( ) )
{
//Unbind VAO
GL : : bindVAO ( 0 ) ;
}
else
{
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
}
2014-01-22 15:18:27 +08:00
_batchedQuadCommands . clear ( ) ;
2013-11-08 07:48:37 +08:00
_numQuads = 0 ;
}
2013-11-09 04:06:39 +08:00
void Renderer : : flush ( )
{
2013-11-12 03:54:08 +08:00
drawBatchedQuads ( ) ;
2013-11-09 04:06:39 +08:00
_lastMaterialID = 0 ;
}
2014-01-17 13:49:14 +08:00
NS_CC_END