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"
# include <algorithm> // for std::stable_sort
2013-11-05 01:14:22 +08:00
NS_CC_BEGIN
using namespace std ;
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-11-11 16:14:29 +08:00
, _firstCommand ( 0 )
, _lastCommand ( 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-06 09:00:34 +08:00
bool compareRenderCommand ( RenderCommand * a , RenderCommand * b )
{
2014-01-18 08:08:29 +08:00
return a - > getDepth ( ) < b - > getDepth ( ) ;
2013-11-06 09:00:34 +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
for ( auto it = _renderGroups . begin ( ) ; it ! = _renderGroups . end ( ) ; + + it )
2013-11-14 09:31:12 +08:00
{
2013-12-17 14:18:41 +08:00
std : : stable_sort ( ( * it ) . begin ( ) , ( * it ) . end ( ) , compareRenderCommand ) ;
2013-11-22 08:36:19 +08:00
}
while ( ! _renderStack . empty ( ) )
{
RenderQueue currRenderQueue = _renderGroups [ _renderStack . top ( ) . renderQueueID ] ;
size_t len = currRenderQueue . size ( ) ;
//Refresh the batch command index in case the renderStack has changed.
_firstCommand = _lastCommand = _renderStack . top ( ) . currentIndex ;
//Process RenderQueue
for ( size_t i = _renderStack . top ( ) . currentIndex ; i < len ; i + + )
2013-11-14 09:31:12 +08:00
{
2013-11-22 08:36:19 +08:00
_renderStack . top ( ) . currentIndex = _lastCommand = i ;
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
{
2013-11-22 08:36:19 +08:00
QuadCommand * cmd = static_cast < QuadCommand * > ( command ) ;
2013-12-18 10:12:15 +08:00
ssize_t cmdQuadCount = cmd - > getQuadCount ( ) ;
2013-11-22 08:36:19 +08:00
//Batch quads
2013-12-19 05:52:10 +08:00
if ( _numQuads + cmdQuadCount > VBO_SIZE )
2013-11-22 08:36:19 +08:00
{
2014-01-17 07:02:39 +08:00
CCASSERT ( cmdQuadCount > = 0 & & cmdQuadCount < 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
2014-01-15 08:45:40 +08:00
_lastCommand - - ;
2013-11-22 08:36:19 +08:00
drawBatchedQuads ( ) ;
2014-01-15 08:45:40 +08:00
_lastCommand + + ;
2013-11-22 08:36:19 +08:00
}
2013-12-06 06:25:45 +08:00
2014-01-16 06:35:26 +08:00
memcpy ( _quads + _numQuads , cmd - > getQuads ( ) , sizeof ( V3F_C4B_T2F_Quad ) * cmdQuadCount ) ;
convertToWorldCoordiantes ( _quads + _numQuads , cmdQuadCount , cmd - > getModelView ( ) ) ;
2013-12-18 10:12:15 +08:00
_numQuads + = cmdQuadCount ;
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 ( ) ;
CustomCommand * cmd = static_cast < CustomCommand * > ( command ) ;
cmd - > execute ( ) ;
}
2014-01-16 08:07:38 +08:00
else if ( commandType = = RenderCommand : : Type : : BATCH_COMMAND )
{
flush ( ) ;
BatchCommand * cmd = static_cast < BatchCommand * > ( command ) ;
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 ( ) ;
GroupCommand * cmd = static_cast < GroupCommand * > ( command ) ;
_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
_firstCommand = _lastCommand = 0 ;
_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 ;
2014-01-17 13:49:14 +08:00
kmVec3Transform ( vec1 , vec1 , & modelView ) ;
2014-01-16 11:10:40 +08:00
kmVec3 * vec2 = ( kmVec3 * ) & q - > br . vertices ;
2014-01-17 13:49:14 +08:00
kmVec3Transform ( vec2 , vec2 , & modelView ) ;
2014-01-16 11:10:40 +08:00
kmVec3 * vec3 = ( kmVec3 * ) & q - > tr . vertices ;
2014-01-17 13:49:14 +08:00
kmVec3Transform ( vec3 , vec3 , & modelView ) ;
2014-01-16 11:10:40 +08:00
kmVec3 * vec4 = ( kmVec3 * ) & q - > tl . vertices ;
2014-01-17 13:49:14 +08:00
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
if ( _numQuads < = 0 )
2013-11-19 07:52:47 +08:00
{
_firstCommand = _lastCommand ;
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-17 07:02:39 +08:00
for ( ssize_t i = _firstCommand ; i < = _lastCommand ; i + + )
2013-11-11 16:14:29 +08:00
{
2013-11-15 04:17:54 +08:00
RenderCommand * command = _renderGroups [ _renderStack . top ( ) . renderQueueID ] [ i ] ;
2013-12-18 10:02:11 +08:00
if ( command - > getType ( ) = = RenderCommand : : Type : : QUAD_COMMAND )
2013-11-11 16:14:29 +08:00
{
QuadCommand * cmd = static_cast < QuadCommand * > ( command ) ;
if ( _lastMaterialID ! = cmd - > getMaterialID ( ) )
2013-11-09 04:06:39 +08:00
{
2013-11-11 16:14:29 +08:00
//Draw quads
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-22 08:36:19 +08:00
2013-11-11 16:14:29 +08:00
startQuad + = quadsToDraw ;
quadsToDraw = 0 ;
}
2013-11-09 04:06:39 +08:00
2013-11-11 16:14:29 +08:00
//Use new material
cmd - > useMaterial ( ) ;
_lastMaterialID = cmd - > getMaterialID ( ) ;
2013-11-09 04:06:39 +08:00
}
2013-11-05 01:14:22 +08:00
2013-11-11 16:14:29 +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 ) ;
}
2013-11-21 12:39:32 +08:00
2014-01-15 08:45:40 +08:00
_firstCommand = _lastCommand + 1 ;
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