2013-12-18 10:12:15 +08:00
/****************************************************************************
2016-08-05 09:42:15 +08:00
Copyright ( c ) 2013 - 2016 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-04-30 08:37:36 +08:00
# include "renderer/CCRenderer.h"
2014-04-15 07:46:19 +08:00
# include <algorithm>
2014-09-01 11:49:04 +08:00
# include "renderer/CCTrianglesCommand.h"
2014-04-30 08:37:36 +08:00
# include "renderer/CCBatchCommand.h"
# include "renderer/CCCustomCommand.h"
# include "renderer/CCGroupCommand.h"
2014-08-05 15:08:01 +08:00
# include "renderer/CCPrimitiveCommand.h"
2015-05-06 04:07:32 +08:00
# include "renderer/CCMeshCommand.h"
2014-05-10 09:39:25 +08:00
# include "renderer/CCGLProgramCache.h"
2015-05-06 04:07:32 +08:00
# include "renderer/CCMaterial.h"
# include "renderer/CCTechnique.h"
# include "renderer/CCPass.h"
# include "renderer/CCRenderState.h"
2014-05-09 09:01:48 +08:00
# include "renderer/ccGLStateCache.h"
2015-05-06 04:07:32 +08:00
2014-05-01 10:09:13 +08:00
# include "base/CCConfiguration.h"
2014-04-30 08:37:36 +08:00
# include "base/CCDirector.h"
# include "base/CCEventDispatcher.h"
# include "base/CCEventListenerCustom.h"
# include "base/CCEventType.h"
2014-10-20 16:25:24 +08:00
# include "2d/CCCamera.h"
2014-08-27 12:09:23 +08:00
# include "2d/CCScene.h"
2014-04-15 07:46:19 +08:00
2013-11-05 01:14:22 +08:00
NS_CC_BEGIN
2014-04-15 07:46:19 +08:00
// helper
2014-04-17 10:16:37 +08:00
static bool compareRenderCommand ( RenderCommand * a , RenderCommand * b )
2014-01-18 15:10:04 +08:00
{
2014-01-19 03:35:27 +08:00
return a - > getGlobalOrder ( ) < b - > getGlobalOrder ( ) ;
2014-01-18 15:10:04 +08:00
}
2015-01-12 14:20:41 +08:00
static bool compare3DCommand ( RenderCommand * a , RenderCommand * b )
{
2015-01-28 07:41:58 +08:00
return a - > getDepth ( ) > b - > getDepth ( ) ;
2015-01-12 14:20:41 +08:00
}
2014-04-15 07:46:19 +08:00
// queue
2015-04-06 21:45:19 +08:00
RenderQueue : : RenderQueue ( )
{
}
2014-04-15 07:46:19 +08:00
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 ( ) ;
2015-01-27 14:29:09 +08:00
if ( z < 0 )
2015-01-12 14:20:41 +08:00
{
2015-01-27 14:29:09 +08:00
_commands [ QUEUE_GROUP : : GLOBALZ_NEG ] . push_back ( command ) ;
}
else if ( z > 0 )
{
_commands [ QUEUE_GROUP : : GLOBALZ_POS ] . push_back ( command ) ;
}
else
{
if ( command - > is3D ( ) )
2015-01-12 14:20:41 +08:00
{
2015-01-27 14:29:09 +08:00
if ( command - > isTransparent ( ) )
{
_commands [ QUEUE_GROUP : : TRANSPARENT_3D ] . push_back ( command ) ;
}
else
{
_commands [ QUEUE_GROUP : : OPAQUE_3D ] . push_back ( command ) ;
}
2015-01-12 14:20:41 +08:00
}
else
{
2015-01-27 14:29:09 +08:00
_commands [ QUEUE_GROUP : : GLOBALZ_ZERO ] . push_back ( command ) ;
2015-01-12 14:20:41 +08:00
}
}
2014-01-18 15:10:04 +08:00
}
ssize_t RenderQueue : : size ( ) const
{
2015-01-27 14:29:09 +08:00
ssize_t result ( 0 ) ;
2015-01-28 10:32:22 +08:00
for ( int index = 0 ; index < QUEUE_GROUP : : QUEUE_COUNT ; + + index )
2015-01-27 14:29:09 +08:00
{
result + = _commands [ index ] . size ( ) ;
}
return result ;
2014-01-18 15:10:04 +08:00
}
void RenderQueue : : sort ( )
{
// Don't sort _queue0, it already comes sorted
2015-01-27 14:29:09 +08:00
std : : sort ( std : : begin ( _commands [ QUEUE_GROUP : : TRANSPARENT_3D ] ) , std : : end ( _commands [ QUEUE_GROUP : : TRANSPARENT_3D ] ) , compare3DCommand ) ;
std : : sort ( std : : begin ( _commands [ QUEUE_GROUP : : GLOBALZ_NEG ] ) , std : : end ( _commands [ QUEUE_GROUP : : GLOBALZ_NEG ] ) , compareRenderCommand ) ;
std : : sort ( std : : begin ( _commands [ QUEUE_GROUP : : GLOBALZ_POS ] ) , std : : end ( _commands [ QUEUE_GROUP : : GLOBALZ_POS ] ) , compareRenderCommand ) ;
2014-01-18 15:10:04 +08:00
}
2014-01-19 03:35:27 +08:00
RenderCommand * RenderQueue : : operator [ ] ( ssize_t index ) const
2014-01-18 15:10:04 +08:00
{
2015-01-28 10:32:22 +08:00
for ( int queIndex = 0 ; queIndex < QUEUE_GROUP : : QUEUE_COUNT ; + + queIndex )
2015-01-27 14:29:09 +08:00
{
if ( index < static_cast < ssize_t > ( _commands [ queIndex ] . size ( ) ) )
return _commands [ queIndex ] [ index ] ;
else
{
index - = _commands [ queIndex ] . size ( ) ;
}
}
2015-01-12 14:20:41 +08:00
2014-01-18 15:10:04 +08:00
CCASSERT ( false , " invalid index " ) ;
return nullptr ;
}
void RenderQueue : : clear ( )
{
2015-04-06 21:45:19 +08:00
for ( int i = 0 ; i < QUEUE_COUNT ; + + i )
{
_commands [ i ] . clear ( ) ;
}
}
void RenderQueue : : realloc ( size_t reserveSize )
{
for ( int i = 0 ; i < QUEUE_COUNT ; + + i )
2015-01-27 14:29:09 +08:00
{
2015-04-06 21:45:19 +08:00
_commands [ i ] = std : : vector < RenderCommand * > ( ) ;
_commands [ i ] . reserve ( reserveSize ) ;
2015-01-27 14:29:09 +08:00
}
2014-01-18 15:10:04 +08:00
}
2013-11-05 01:14:22 +08:00
2015-01-27 08:37:11 +08:00
void RenderQueue : : saveRenderState ( )
{
2015-01-29 17:40:00 +08:00
_isDepthEnabled = glIsEnabled ( GL_DEPTH_TEST ) ! = GL_FALSE ;
_isCullEnabled = glIsEnabled ( GL_CULL_FACE ) ! = GL_FALSE ;
2015-01-27 08:37:11 +08:00
glGetBooleanv ( GL_DEPTH_WRITEMASK , & _isDepthWrite ) ;
CHECK_GL_ERROR_DEBUG ( ) ;
}
void RenderQueue : : restoreRenderState ( )
{
if ( _isCullEnabled )
{
glEnable ( GL_CULL_FACE ) ;
2015-05-06 04:07:32 +08:00
RenderState : : StateBlock : : _defaultState - > setCullFace ( true ) ;
2015-01-27 08:37:11 +08:00
}
else
{
glDisable ( GL_CULL_FACE ) ;
2015-05-06 04:07:32 +08:00
RenderState : : StateBlock : : _defaultState - > setCullFace ( false ) ;
2015-01-27 08:37:11 +08:00
}
2016-02-09 03:25:37 +08:00
2015-01-27 08:37:11 +08:00
if ( _isDepthEnabled )
{
glEnable ( GL_DEPTH_TEST ) ;
2015-05-06 04:07:32 +08:00
RenderState : : StateBlock : : _defaultState - > setDepthTest ( true ) ;
2015-01-27 08:37:11 +08:00
}
else
{
glDisable ( GL_DEPTH_TEST ) ;
2015-05-06 04:07:32 +08:00
RenderState : : StateBlock : : _defaultState - > setDepthTest ( false ) ;
2015-01-27 08:37:11 +08:00
}
glDepthMask ( _isDepthWrite ) ;
2015-05-06 04:07:32 +08:00
RenderState : : StateBlock : : _defaultState - > setDepthWrite ( _isDepthEnabled ) ;
2015-01-27 08:37:11 +08:00
CHECK_GL_ERROR_DEBUG ( ) ;
}
2014-01-18 15:10:04 +08:00
//
//
//
2014-04-15 07:46:19 +08:00
static const int DEFAULT_RENDER_QUEUE = 0 ;
2013-11-05 01:14:22 +08:00
2014-04-15 07:46:19 +08:00
//
2015-09-22 16:08:23 +08:00
// constructors, destructor, init
2014-04-15 07:46:19 +08:00
//
2013-11-05 01:14:22 +08:00
Renderer : : Renderer ( )
2016-02-09 03:25:37 +08:00
: _lastBatchedMeshCommand ( nullptr )
2014-08-27 14:54:35 +08:00
, _filledVertex ( 0 )
, _filledIndex ( 0 )
2013-11-22 08:36:19 +08:00
, _glViewAssigned ( false )
2014-04-11 16:05:22 +08:00
, _isRendering ( false )
2015-01-16 08:41:07 +08:00
, _isDepthTestFor2D ( false )
2016-02-09 03:25:37 +08:00
, _triBatchesToDraw ( nullptr )
, _triBatchesToDrawCapacity ( - 1 )
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
{
2014-08-28 07:31:57 +08:00
_groupCommandManager = new ( std : : nothrow ) GroupCommandManager ( ) ;
2014-04-12 13:01:42 +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 ) ;
2016-07-20 23:49:19 +08:00
_queuedTriangleCommands . reserve ( BATCH_TRIAGCOMMAND_RESERVED_SIZE ) ;
2015-01-10 06:06:21 +08:00
// default clear color
_clearColor = Color4F : : BLACK ;
2016-02-09 03:25:37 +08:00
// for the batched TriangleCommand
_triBatchesToDrawCapacity = 500 ;
_triBatchesToDraw = ( TriBatchToDraw * ) malloc ( sizeof ( _triBatchesToDraw [ 0 ] ) * _triBatchesToDrawCapacity ) ;
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 ( ) ;
2014-04-12 13:01:42 +08:00
_groupCommandManager - > release ( ) ;
2013-11-22 08:36:19 +08:00
glDeleteBuffers ( 2 , _buffersVBO ) ;
2016-02-09 03:25:37 +08:00
free ( _triBatchesToDraw ) ;
2013-12-05 09:02:02 +08:00
if ( Configuration : : getInstance ( ) - > supportsShareableVAO ( ) )
{
2014-10-16 14:15:29 +08:00
glDeleteVertexArrays ( 1 , & _buffersVAO ) ;
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
2014-07-09 23:03:04 +08:00
_cacheTextureListener = EventListenerCustom : : create ( EVENT_RENDERER_RECREATED , [ this ] ( EventCustom * event ) {
/** listen the event that renderer was recreated on Android/WP8 */
2013-12-31 10:54:37 +08:00
this - > setupBuffer ( ) ;
} ) ;
Director : : getInstance ( ) - > getEventDispatcher ( ) - > addEventListenerWithFixedPriority ( _cacheTextureListener , - 1 ) ;
2013-12-05 09:02:02 +08:00
# endif
2016-02-09 03:25:37 +08:00
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
}
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 ( )
{
2014-10-16 14:15:29 +08:00
//generate vbo and vao for trianglesCommand
glGenVertexArrays ( 1 , & _buffersVAO ) ;
GL : : bindVAO ( _buffersVAO ) ;
2013-11-08 08:50:53 +08:00
glGenBuffers ( 2 , & _buffersVBO [ 0 ] ) ;
glBindBuffer ( GL_ARRAY_BUFFER , _buffersVBO [ 0 ] ) ;
2014-08-27 14:54:35 +08:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( _verts [ 0 ] ) * VBO_SIZE , _verts , 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
2014-05-09 03:34:26 +08:00
glEnableVertexAttribArray ( GLProgram : : VERTEX_ATTRIB_TEX_COORD ) ;
glVertexAttribPointer ( GLProgram : : VERTEX_ATTRIB_TEX_COORD , 2 , GL_FLOAT , GL_FALSE , sizeof ( V3F_C4B_T2F ) , ( GLvoid * ) offsetof ( V3F_C4B_T2F , texCoords ) ) ;
2013-11-08 08:50:53 +08:00
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , _buffersVBO [ 1 ] ) ;
2014-08-27 14:54:35 +08:00
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , sizeof ( _indices [ 0 ] ) * INDEX_VBO_SIZE , _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 ] ) ;
2016-06-12 11:34:27 +08:00
// Issue #15652
// Should not initialzie VBO with a large size (VBO_SIZE=65536),
// it may cause low FPS on some Android devices like LG G4 & Nexus 5X.
// It's probably because some implementations of OpenGLES driver will
// copy the whole memory of VBO which initialzied at the first time
// once glBufferData/glBufferSubData is invoked.
// For more discussion, please refer to https://github.com/cocos2d/cocos2d-x/issues/15652
// mapBuffers();
2013-12-05 09:02:02 +08:00
}
void Renderer : : mapBuffers ( )
{
// Avoid changing the element buffer for whatever VAO might be bound.
GL : : bindVAO ( 0 ) ;
glBindBuffer ( GL_ARRAY_BUFFER , _buffersVBO [ 0 ] ) ;
2014-08-27 14:54:35 +08:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( _verts [ 0 ] ) * VBO_SIZE , _verts , GL_DYNAMIC_DRAW ) ;
2014-10-16 14:15:29 +08:00
2016-02-09 03:25:37 +08:00
2013-12-05 09:02:02 +08:00
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , _buffersVBO [ 1 ] ) ;
2014-08-27 14:54:35 +08:00
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , sizeof ( _indices [ 0 ] ) * INDEX_VBO_SIZE , _indices , GL_STATIC_DRAW ) ;
2014-10-16 14:15:29 +08:00
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-04-11 16:05:22 +08:00
CCASSERT ( ! _isRendering , " Cannot add command while rendering " ) ;
2014-01-17 14:29:25 +08:00
CCASSERT ( renderQueue > = 0 , " Invalid render queue " ) ;
CCASSERT ( command - > getType ( ) ! = RenderCommand : : Type : : UNKNOWN_COMMAND , " Invalid Command Type " ) ;
2015-02-13 09:48:27 +08:00
_renderGroups [ renderQueue ] . push_back ( command ) ;
2014-08-27 17:53:46 +08:00
}
2013-11-21 03:05:01 +08:00
void Renderer : : pushGroup ( int renderQueueID )
{
2014-04-11 16:07:55 +08:00
CCASSERT ( ! _isRendering , " Cannot change render queue while rendering " ) ;
2013-11-21 03:05:01 +08:00
_commandGroupStack . push ( renderQueueID ) ;
}
void Renderer : : popGroup ( )
{
2014-04-11 16:07:55 +08:00
CCASSERT ( ! _isRendering , " Cannot change render queue while rendering " ) ;
2013-11-21 03:05:01 +08:00
_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
}
2015-01-12 14:20:41 +08:00
void Renderer : : processRenderCommand ( RenderCommand * command )
2014-04-07 22:51:32 +08:00
{
2015-01-12 14:20:41 +08:00
auto commandType = command - > getType ( ) ;
if ( RenderCommand : : Type : : TRIANGLES_COMMAND = = commandType )
2014-04-07 22:51:32 +08:00
{
2016-02-09 03:25:37 +08:00
// flush other queues
2015-01-12 14:20:41 +08:00
flush3D ( ) ;
2016-02-09 03:25:37 +08:00
2015-01-12 14:20:41 +08:00
auto cmd = static_cast < TrianglesCommand * > ( command ) ;
2016-02-09 03:25:37 +08:00
// flush own queue when buffer is full
if ( _filledVertex + cmd - > getVertexCount ( ) > VBO_SIZE | | _filledIndex + cmd - > getIndexCount ( ) > INDEX_VBO_SIZE )
2014-04-07 22:51:32 +08:00
{
2015-01-12 14:20:41 +08:00
CCASSERT ( cmd - > getVertexCount ( ) > = 0 & & cmd - > getVertexCount ( ) < VBO_SIZE , " VBO for vertex is not big enough, please break the data down or use customized render command " ) ;
CCASSERT ( cmd - > getIndexCount ( ) > = 0 & & cmd - > getIndexCount ( ) < INDEX_VBO_SIZE , " VBO for index is not big enough, please break the data down or use customized render command " ) ;
drawBatchedTriangles ( ) ;
}
2016-02-09 03:25:37 +08:00
// queue it
_queuedTriangleCommands . push_back ( cmd ) ;
_filledIndex + = cmd - > getIndexCount ( ) ;
_filledVertex + = cmd - > getVertexCount ( ) ;
2015-01-12 14:20:41 +08:00
}
else if ( RenderCommand : : Type : : MESH_COMMAND = = commandType )
{
flush2D ( ) ;
auto cmd = static_cast < MeshCommand * > ( command ) ;
if ( cmd - > isSkipBatching ( ) | | _lastBatchedMeshCommand = = nullptr | | _lastBatchedMeshCommand - > getMaterialID ( ) ! = cmd - > getMaterialID ( ) )
2014-10-16 14:15:29 +08:00
{
flush3D ( ) ;
2016-06-16 02:33:25 +08:00
CCGL_DEBUG_INSERT_EVENT_MARKER ( " RENDERER_MESH_COMMAND " ) ;
2015-01-10 06:06:21 +08:00
if ( cmd - > isSkipBatching ( ) )
{
2015-06-16 05:12:44 +08:00
// XXX: execute() will call bind() and unbind()
// but unbind() shouldn't be call if the next command is a MESH_COMMAND with Material.
// Once most of cocos2d-x moves to Pass/StateBlock, only bind() should be used.
2015-01-12 14:20:41 +08:00
cmd - > execute ( ) ;
2015-01-10 06:06:21 +08:00
}
else
{
2015-01-12 14:20:41 +08:00
cmd - > preBatchDraw ( ) ;
2015-01-10 06:06:21 +08:00
cmd - > batchDraw ( ) ;
2015-01-12 14:20:41 +08:00
_lastBatchedMeshCommand = cmd ;
2015-01-10 06:06:21 +08:00
}
2014-04-07 22:51:32 +08:00
}
else
{
2016-06-16 02:33:25 +08:00
CCGL_DEBUG_INSERT_EVENT_MARKER ( " RENDERER_MESH_COMMAND " ) ;
2015-01-12 14:20:41 +08:00
cmd - > batchDraw ( ) ;
2014-04-07 22:51:32 +08:00
}
}
2015-01-12 14:20:41 +08:00
else if ( RenderCommand : : Type : : GROUP_COMMAND = = commandType )
{
flush ( ) ;
int renderQueueID = ( ( GroupCommand * ) command ) - > getRenderQueueID ( ) ;
2016-06-16 02:33:25 +08:00
CCGL_DEBUG_PUSH_GROUP_MARKER ( " RENDERER_GROUP_COMMAND " ) ;
2015-01-12 14:20:41 +08:00
visitRenderQueue ( _renderGroups [ renderQueueID ] ) ;
2016-06-16 02:33:25 +08:00
CCGL_DEBUG_POP_GROUP_MARKER ( ) ;
2015-01-12 14:20:41 +08:00
}
else if ( RenderCommand : : Type : : CUSTOM_COMMAND = = commandType )
{
flush ( ) ;
auto cmd = static_cast < CustomCommand * > ( command ) ;
2016-06-16 02:33:25 +08:00
CCGL_DEBUG_INSERT_EVENT_MARKER ( " RENDERER_CUSTOM_COMMAND " ) ;
2015-01-12 14:20:41 +08:00
cmd - > execute ( ) ;
}
else if ( RenderCommand : : Type : : BATCH_COMMAND = = commandType )
{
flush ( ) ;
auto cmd = static_cast < BatchCommand * > ( command ) ;
2016-06-16 02:33:25 +08:00
CCGL_DEBUG_INSERT_EVENT_MARKER ( " RENDERER_BATCH_COMMAND " ) ;
2015-01-12 14:20:41 +08:00
cmd - > execute ( ) ;
}
else if ( RenderCommand : : Type : : PRIMITIVE_COMMAND = = commandType )
{
flush ( ) ;
auto cmd = static_cast < PrimitiveCommand * > ( command ) ;
2016-06-16 02:33:25 +08:00
CCGL_DEBUG_INSERT_EVENT_MARKER ( " RENDERER_PRIMITIVE_COMMAND " ) ;
2015-01-12 14:20:41 +08:00
cmd - > execute ( ) ;
}
else
{
CCLOGERROR ( " Unknown commands in renderQueue " ) ;
}
}
2015-01-27 08:37:11 +08:00
void Renderer : : visitRenderQueue ( RenderQueue & queue )
2015-01-12 14:20:41 +08:00
{
2015-01-27 08:37:11 +08:00
queue . saveRenderState ( ) ;
2015-01-28 06:41:16 +08:00
//
//Process Global-Z < 0 Objects
//
2015-01-28 10:59:29 +08:00
const auto & zNegQueue = queue . getSubQueue ( RenderQueue : : QUEUE_GROUP : : GLOBALZ_NEG ) ;
2015-01-28 06:41:16 +08:00
if ( zNegQueue . size ( ) > 0 )
2015-01-28 03:23:48 +08:00
{
2015-01-28 06:41:16 +08:00
if ( _isDepthTestFor2D )
{
glEnable ( GL_DEPTH_TEST ) ;
glDepthMask ( true ) ;
2015-08-28 23:00:45 +08:00
glEnable ( GL_BLEND ) ;
2015-05-06 04:07:32 +08:00
RenderState : : StateBlock : : _defaultState - > setDepthTest ( true ) ;
RenderState : : StateBlock : : _defaultState - > setDepthWrite ( true ) ;
2015-08-28 23:00:45 +08:00
RenderState : : StateBlock : : _defaultState - > setBlend ( true ) ;
2015-01-28 06:41:16 +08:00
}
else
{
glDisable ( GL_DEPTH_TEST ) ;
glDepthMask ( false ) ;
2015-08-28 23:00:45 +08:00
glEnable ( GL_BLEND ) ;
2015-05-06 04:07:32 +08:00
RenderState : : StateBlock : : _defaultState - > setDepthTest ( false ) ;
RenderState : : StateBlock : : _defaultState - > setDepthWrite ( false ) ;
2015-08-28 23:00:45 +08:00
RenderState : : StateBlock : : _defaultState - > setBlend ( true ) ;
2015-01-28 06:41:16 +08:00
}
2015-11-09 10:42:12 +08:00
glDisable ( GL_CULL_FACE ) ;
RenderState : : StateBlock : : _defaultState - > setCullFace ( false ) ;
2015-01-28 06:41:16 +08:00
for ( auto it = zNegQueue . cbegin ( ) ; it ! = zNegQueue . cend ( ) ; + + it )
{
processRenderCommand ( * it ) ;
}
flush ( ) ;
2015-01-27 14:29:09 +08:00
}
2015-01-28 03:23:48 +08:00
2015-01-28 06:41:16 +08:00
//
2015-01-12 14:20:41 +08:00
//Process Opaque Object
2015-01-28 06:41:16 +08:00
//
2015-01-28 10:59:29 +08:00
const auto & opaqueQueue = queue . getSubQueue ( RenderQueue : : QUEUE_GROUP : : OPAQUE_3D ) ;
2015-01-12 14:20:41 +08:00
if ( opaqueQueue . size ( ) > 0 )
{
2015-01-28 07:41:58 +08:00
//Clear depth to achieve layered rendering
2015-01-12 14:20:41 +08:00
glEnable ( GL_DEPTH_TEST ) ;
2015-05-06 04:07:32 +08:00
glDepthMask ( true ) ;
2015-08-28 23:00:45 +08:00
glDisable ( GL_BLEND ) ;
2015-11-09 10:42:12 +08:00
glEnable ( GL_CULL_FACE ) ;
2015-05-06 04:07:32 +08:00
RenderState : : StateBlock : : _defaultState - > setDepthTest ( true ) ;
RenderState : : StateBlock : : _defaultState - > setDepthWrite ( true ) ;
2015-08-28 23:00:45 +08:00
RenderState : : StateBlock : : _defaultState - > setBlend ( false ) ;
2015-11-09 10:42:12 +08:00
RenderState : : StateBlock : : _defaultState - > setCullFace ( true ) ;
2015-05-06 04:07:32 +08:00
2015-01-28 06:41:16 +08:00
for ( auto it = opaqueQueue . cbegin ( ) ; it ! = opaqueQueue . cend ( ) ; + + it )
{
2015-01-12 14:20:41 +08:00
processRenderCommand ( * it ) ;
}
2015-01-28 06:41:16 +08:00
flush ( ) ;
2015-01-12 14:20:41 +08:00
}
2015-01-28 06:41:16 +08:00
//
//Process 3D Transparent object
//
2015-01-28 10:59:29 +08:00
const auto & transQueue = queue . getSubQueue ( RenderQueue : : QUEUE_GROUP : : TRANSPARENT_3D ) ;
2015-01-28 06:41:16 +08:00
if ( transQueue . size ( ) > 0 )
2015-01-12 14:20:41 +08:00
{
glEnable ( GL_DEPTH_TEST ) ;
2015-01-28 06:41:16 +08:00
glDepthMask ( false ) ;
2015-08-28 23:00:45 +08:00
glEnable ( GL_BLEND ) ;
2015-11-09 10:42:12 +08:00
glEnable ( GL_CULL_FACE ) ;
2015-05-06 04:07:32 +08:00
RenderState : : StateBlock : : _defaultState - > setDepthTest ( true ) ;
RenderState : : StateBlock : : _defaultState - > setDepthWrite ( false ) ;
2015-08-28 23:00:45 +08:00
RenderState : : StateBlock : : _defaultState - > setBlend ( true ) ;
2015-11-09 10:42:12 +08:00
RenderState : : StateBlock : : _defaultState - > setCullFace ( true ) ;
2015-05-06 04:07:32 +08:00
2015-01-28 06:41:16 +08:00
for ( auto it = transQueue . cbegin ( ) ; it ! = transQueue . cend ( ) ; + + it )
{
processRenderCommand ( * it ) ;
}
flush ( ) ;
2015-01-12 14:20:41 +08:00
}
2015-01-28 06:41:16 +08:00
//
//Process Global-Z = 0 Queue
//
2015-01-28 10:59:29 +08:00
const auto & zZeroQueue = queue . getSubQueue ( RenderQueue : : QUEUE_GROUP : : GLOBALZ_ZERO ) ;
2015-01-28 06:41:16 +08:00
if ( zZeroQueue . size ( ) > 0 )
2015-01-16 08:41:07 +08:00
{
2015-01-28 06:41:16 +08:00
if ( _isDepthTestFor2D )
{
glEnable ( GL_DEPTH_TEST ) ;
glDepthMask ( true ) ;
2015-08-28 23:00:45 +08:00
glEnable ( GL_BLEND ) ;
2015-05-06 04:07:32 +08:00
RenderState : : StateBlock : : _defaultState - > setDepthTest ( true ) ;
RenderState : : StateBlock : : _defaultState - > setDepthWrite ( true ) ;
2015-08-28 23:00:45 +08:00
RenderState : : StateBlock : : _defaultState - > setBlend ( true ) ;
2015-01-28 06:41:16 +08:00
}
else
{
glDisable ( GL_DEPTH_TEST ) ;
glDepthMask ( false ) ;
2015-08-28 23:00:45 +08:00
glEnable ( GL_BLEND ) ;
2015-05-06 04:07:32 +08:00
RenderState : : StateBlock : : _defaultState - > setDepthTest ( false ) ;
RenderState : : StateBlock : : _defaultState - > setDepthWrite ( false ) ;
2015-08-28 23:00:45 +08:00
RenderState : : StateBlock : : _defaultState - > setBlend ( true ) ;
2015-01-28 06:41:16 +08:00
}
2015-11-09 10:42:12 +08:00
glDisable ( GL_CULL_FACE ) ;
RenderState : : StateBlock : : _defaultState - > setCullFace ( false ) ;
2015-01-28 06:41:16 +08:00
for ( auto it = zZeroQueue . cbegin ( ) ; it ! = zZeroQueue . cend ( ) ; + + it )
{
processRenderCommand ( * it ) ;
}
flush ( ) ;
2015-01-16 08:41:07 +08:00
}
2015-01-28 06:41:16 +08:00
//
//Process Global-Z > 0 Queue
//
2015-01-28 10:59:29 +08:00
const auto & zPosQueue = queue . getSubQueue ( RenderQueue : : QUEUE_GROUP : : GLOBALZ_POS ) ;
2015-01-28 06:41:16 +08:00
if ( zPosQueue . size ( ) > 0 )
2015-01-12 14:20:41 +08:00
{
2015-08-28 23:00:45 +08:00
if ( _isDepthTestFor2D )
{
glEnable ( GL_DEPTH_TEST ) ;
glDepthMask ( true ) ;
glEnable ( GL_BLEND ) ;
RenderState : : StateBlock : : _defaultState - > setDepthTest ( true ) ;
RenderState : : StateBlock : : _defaultState - > setDepthWrite ( true ) ;
RenderState : : StateBlock : : _defaultState - > setBlend ( true ) ;
}
else
{
glDisable ( GL_DEPTH_TEST ) ;
glDepthMask ( false ) ;
glEnable ( GL_BLEND ) ;
RenderState : : StateBlock : : _defaultState - > setDepthTest ( false ) ;
RenderState : : StateBlock : : _defaultState - > setDepthWrite ( false ) ;
RenderState : : StateBlock : : _defaultState - > setBlend ( true ) ;
}
2015-11-09 10:42:12 +08:00
glDisable ( GL_CULL_FACE ) ;
RenderState : : StateBlock : : _defaultState - > setCullFace ( false ) ;
2015-08-28 23:00:45 +08:00
2015-01-28 06:41:16 +08:00
for ( auto it = zPosQueue . cbegin ( ) ; it ! = zPosQueue . cend ( ) ; + + it )
{
processRenderCommand ( * it ) ;
}
flush ( ) ;
2015-01-12 14:20:41 +08:00
}
2015-01-27 08:37:11 +08:00
queue . restoreRenderState ( ) ;
2014-04-07 22:51:32 +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);
2014-08-30 03:54:24 +08:00
//TODO: setup camera or MVP
2014-04-11 16:05:22 +08:00
_isRendering = true ;
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
}
2014-04-07 22:51:32 +08:00
visitRenderQueue ( _renderGroups [ 0 ] ) ;
2013-11-14 09:31:12 +08:00
}
2014-04-04 12:48:16 +08:00
clean ( ) ;
2014-04-11 16:05:22 +08:00
_isRendering = false ;
2014-04-04 12:48:16 +08:00
}
void Renderer : : clean ( )
{
// Clear render group
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
}
2014-04-04 12:48:16 +08:00
2014-10-16 14:56:17 +08:00
// Clear batch commands
2016-02-09 03:25:37 +08:00
_queuedTriangleCommands . clear ( ) ;
2014-08-27 14:54:35 +08:00
_filledVertex = 0 ;
_filledIndex = 0 ;
2014-06-23 23:58:45 +08:00
_lastBatchedMeshCommand = nullptr ;
2013-11-11 16:14:29 +08:00
}
2013-11-09 04:06:39 +08:00
2015-01-10 06:06:21 +08:00
void Renderer : : clear ( )
{
2015-01-12 14:20:41 +08:00
//Enable Depth mask to make sure glClear clear the depth buffer correctly
2015-01-10 06:06:21 +08:00
glDepthMask ( true ) ;
2015-05-13 17:40:10 +08:00
glClearColor ( _clearColor . r , _clearColor . g , _clearColor . b , _clearColor . a ) ;
2015-01-10 06:06:21 +08:00
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
glDepthMask ( false ) ;
2015-05-06 06:59:41 +08:00
RenderState : : StateBlock : : _defaultState - > setDepthWrite ( false ) ;
2015-01-10 06:06:21 +08:00
}
2015-01-16 08:54:27 +08:00
void Renderer : : setDepthTest ( bool enable )
{
if ( enable )
{
glClearDepth ( 1.0f ) ;
glEnable ( GL_DEPTH_TEST ) ;
glDepthFunc ( GL_LEQUAL ) ;
2015-05-06 04:07:32 +08:00
RenderState : : StateBlock : : _defaultState - > setDepthTest ( true ) ;
RenderState : : StateBlock : : _defaultState - > setDepthFunction ( RenderState : : DEPTH_LEQUAL ) ;
2015-01-16 08:54:27 +08:00
// glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}
else
{
glDisable ( GL_DEPTH_TEST ) ;
2015-05-06 04:07:32 +08:00
RenderState : : StateBlock : : _defaultState - > setDepthTest ( false ) ;
2015-01-16 08:54:27 +08:00
}
2015-05-06 04:07:32 +08:00
2015-01-16 08:54:27 +08:00
_isDepthTestFor2D = enable ;
CHECK_GL_ERROR_DEBUG ( ) ;
}
2015-01-12 14:20:41 +08:00
void Renderer : : fillVerticesAndIndices ( const TrianglesCommand * cmd )
2014-01-16 06:35:26 +08:00
{
2016-02-09 03:25:37 +08:00
memcpy ( & _verts [ _filledVertex ] , cmd - > getVertices ( ) , sizeof ( V3F_C4B_T2F ) * cmd - > getVertexCount ( ) ) ;
// fill vertex, and convert them to world coordinates
2014-08-27 16:43:14 +08:00
const Mat4 & modelView = cmd - > getModelView ( ) ;
2016-02-09 03:25:37 +08:00
for ( ssize_t i = 0 ; i < cmd - > getVertexCount ( ) ; + + i )
2014-04-09 14:21:41 +08:00
{
2016-02-09 03:25:37 +08:00
modelView . transformPoint ( & ( _verts [ i + _filledVertex ] . vertices ) ) ;
2014-01-16 06:35:26 +08:00
}
2016-02-09 03:25:37 +08:00
// fill index
2014-08-27 18:39:49 +08:00
const unsigned short * indices = cmd - > getIndices ( ) ;
for ( ssize_t i = 0 ; i < cmd - > getIndexCount ( ) ; + + i )
2014-08-27 16:43:14 +08:00
{
2014-08-27 18:39:49 +08:00
_indices [ _filledIndex + i ] = _filledVertex + indices [ i ] ;
2014-08-27 16:43:14 +08:00
}
2016-02-09 03:25:37 +08:00
2014-08-27 18:39:49 +08:00
_filledVertex + = cmd - > getVertexCount ( ) ;
_filledIndex + = cmd - > getIndexCount ( ) ;
2014-01-16 06:35:26 +08:00
}
2014-10-16 14:15:29 +08:00
void Renderer : : drawBatchedTriangles ( )
2013-11-11 16:14:29 +08:00
{
2016-02-09 03:25:37 +08:00
if ( _queuedTriangleCommands . empty ( ) )
return ;
2016-06-16 02:33:25 +08:00
CCGL_DEBUG_INSERT_EVENT_MARKER ( " RENDERER_BATCH_TRIANGLES " ) ;
2016-02-09 03:25:37 +08:00
_filledVertex = 0 ;
_filledIndex = 0 ;
/************** 1: Setup up vertices/indices *************/
_triBatchesToDraw [ 0 ] . offset = 0 ;
_triBatchesToDraw [ 0 ] . indicesToDraw = 0 ;
_triBatchesToDraw [ 0 ] . cmd = nullptr ;
2013-11-14 02:26:26 +08:00
2016-02-09 03:25:37 +08:00
int batchesTotal = 0 ;
int prevMaterialID = - 1 ;
bool firstCommand = true ;
2013-11-05 01:14:22 +08:00
2016-02-09 03:25:37 +08:00
for ( auto it = std : : begin ( _queuedTriangleCommands ) ; it ! = std : : end ( _queuedTriangleCommands ) ; + + it )
2013-11-19 07:52:47 +08:00
{
2016-02-09 03:25:37 +08:00
const auto & cmd = * it ;
auto currentMaterialID = cmd - > getMaterialID ( ) ;
const bool batchable = ! cmd - > isSkipBatching ( ) ;
fillVerticesAndIndices ( cmd ) ;
// in the same batch ?
if ( batchable & & ( prevMaterialID = = currentMaterialID | | firstCommand ) )
{
CC_ASSERT ( firstCommand | | _triBatchesToDraw [ batchesTotal ] . cmd - > getMaterialID ( ) = = cmd - > getMaterialID ( ) & & " argh... error in logic " ) ;
_triBatchesToDraw [ batchesTotal ] . indicesToDraw + = cmd - > getIndexCount ( ) ;
_triBatchesToDraw [ batchesTotal ] . cmd = cmd ;
}
else
{
// is this the first one?
if ( ! firstCommand ) {
batchesTotal + + ;
_triBatchesToDraw [ batchesTotal ] . offset = _triBatchesToDraw [ batchesTotal - 1 ] . offset + _triBatchesToDraw [ batchesTotal - 1 ] . indicesToDraw ;
}
_triBatchesToDraw [ batchesTotal ] . cmd = cmd ;
_triBatchesToDraw [ batchesTotal ] . indicesToDraw = ( int ) cmd - > getIndexCount ( ) ;
// is this a single batch ? Prevent creating a batch group then
if ( ! batchable )
currentMaterialID = - 1 ;
}
// capacity full ?
if ( batchesTotal + 1 > = _triBatchesToDrawCapacity ) {
_triBatchesToDrawCapacity * = 1.4 ;
_triBatchesToDraw = ( TriBatchToDraw * ) realloc ( _triBatchesToDraw , sizeof ( _triBatchesToDraw [ 0 ] ) * _triBatchesToDrawCapacity ) ;
}
prevMaterialID = currentMaterialID ;
firstCommand = false ;
2013-11-19 07:52:47 +08:00
}
2016-02-09 03:25:37 +08:00
batchesTotal + + ;
2013-11-11 16:14:29 +08:00
2016-02-09 03:25:37 +08:00
/************** 2: Copy vertices/indices to GL objects *************/
2016-07-15 07:45:04 +08:00
auto conf = Configuration : : getInstance ( ) ;
if ( conf - > supportsShareableVAO ( ) & & conf - > supportsMapBuffer ( ) )
2013-12-05 09:02:02 +08:00
{
2014-08-27 14:54:35 +08:00
//Bind VAO
2014-10-16 14:15:29 +08:00
GL : : bindVAO ( _buffersVAO ) ;
2013-12-05 09:02:02 +08:00
//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
2016-02-09 03:25:37 +08:00
// glBufferData(GL_ARRAY_BUFFER, sizeof(_verts[0]) * _filledVertex, _verts, GL_STATIC_DRAW);
2014-01-17 13:35:58 +08:00
// option 3: orphaning + glMapBuffer
2016-02-09 03:25:37 +08:00
// FIXME: in order to work as fast as possible, it must "and the exact same size and usage hints it had before."
// source: https://www.opengl.org/wiki/Buffer_Object_Streaming#Explicit_multiple_buffering
// so most probably we won't have any benefit of using it
glBufferData ( GL_ARRAY_BUFFER , sizeof ( _verts [ 0 ] ) * _filledVertex , nullptr , GL_STATIC_DRAW ) ;
2013-12-05 09:02:02 +08:00
void * buf = glMapBuffer ( GL_ARRAY_BUFFER , GL_WRITE_ONLY ) ;
2016-02-09 03:25:37 +08:00
memcpy ( buf , _verts , sizeof ( _verts [ 0 ] ) * _filledVertex ) ;
2013-12-05 09:02:02 +08:00
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 ) ;
2014-08-27 14:54:35 +08:00
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , _buffersVBO [ 1 ] ) ;
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , sizeof ( _indices [ 0 ] ) * _filledIndex , _indices , GL_STATIC_DRAW ) ;
2013-12-05 09:02:02 +08:00
}
else
{
2016-02-09 03:25:37 +08:00
// Client Side Arrays
2014-08-27 14:54:35 +08:00
# define kQuadSize sizeof(_verts[0])
2013-12-05 09:02:02 +08:00
glBindBuffer ( GL_ARRAY_BUFFER , _buffersVBO [ 0 ] ) ;
2014-08-27 14:54:35 +08:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( _verts [ 0 ] ) * _filledVertex , _verts , 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
2014-05-09 03:34:26 +08:00
glVertexAttribPointer ( GLProgram : : VERTEX_ATTRIB_TEX_COORD , 2 , GL_FLOAT , GL_FALSE , kQuadSize , ( GLvoid * ) offsetof ( V3F_C4B_T2F , texCoords ) ) ;
2013-12-05 09:02:02 +08:00
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , _buffersVBO [ 1 ] ) ;
2014-08-27 14:54:35 +08:00
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , sizeof ( _indices [ 0 ] ) * _filledIndex , _indices , GL_STATIC_DRAW ) ;
2013-12-05 09:02:02 +08:00
}
2013-11-11 16:14:29 +08:00
2016-02-09 03:25:37 +08:00
/************** 3: Draw *************/
for ( int i = 0 ; i < batchesTotal ; + + i )
2013-11-12 03:54:08 +08:00
{
2016-02-09 03:25:37 +08:00
CC_ASSERT ( _triBatchesToDraw [ i ] . cmd & & " Invalid batch " ) ;
_triBatchesToDraw [ i ] . cmd - > useMaterial ( ) ;
glDrawElements ( GL_TRIANGLES , ( GLsizei ) _triBatchesToDraw [ i ] . indicesToDraw , GL_UNSIGNED_SHORT , ( GLvoid * ) ( _triBatchesToDraw [ i ] . offset * sizeof ( _indices [ 0 ] ) ) ) ;
2014-02-08 11:37:44 +08:00
_drawnBatches + + ;
2016-02-09 03:25:37 +08:00
_drawnVertices + = _triBatchesToDraw [ i ] . indicesToDraw ;
2013-11-12 03:54:08 +08:00
}
2013-11-08 07:48:37 +08:00
2016-02-09 03:25:37 +08:00
/************** 4: Cleanup *************/
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 ) ;
}
2016-02-09 03:25:37 +08:00
_queuedTriangleCommands . clear ( ) ;
2014-08-27 14:54:35 +08:00
_filledVertex = 0 ;
_filledIndex = 0 ;
2013-11-08 07:48:37 +08:00
}
2013-11-09 04:06:39 +08:00
void Renderer : : flush ( )
2014-06-23 23:58:45 +08:00
{
flush2D ( ) ;
flush3D ( ) ;
}
void Renderer : : flush2D ( )
2013-11-09 04:06:39 +08:00
{
2015-01-12 14:20:41 +08:00
flushTriangles ( ) ;
2013-11-09 04:06:39 +08:00
}
2014-06-23 23:58:45 +08:00
void Renderer : : flush3D ( )
{
if ( _lastBatchedMeshCommand )
{
2016-06-16 02:33:25 +08:00
CCGL_DEBUG_INSERT_EVENT_MARKER ( " RENDERER_BATCH_MESH " ) ;
2014-06-24 19:45:51 +08:00
_lastBatchedMeshCommand - > postBatchDraw ( ) ;
2014-06-23 23:58:45 +08:00
_lastBatchedMeshCommand = nullptr ;
}
}
2015-01-10 06:06:21 +08:00
void Renderer : : flushTriangles ( )
{
2016-02-09 03:25:37 +08:00
drawBatchedTriangles ( ) ;
2015-01-10 06:06:21 +08:00
}
2014-04-15 07:46:19 +08:00
2015-01-10 06:06:21 +08:00
// helpers
2014-05-15 01:07:09 +08:00
bool Renderer : : checkVisibility ( const Mat4 & transform , const Size & size )
2014-04-15 07:46:19 +08:00
{
2014-08-27 12:09:23 +08:00
auto scene = Director : : getInstance ( ) - > getRunningScene ( ) ;
2015-08-21 17:38:56 +08:00
//If draw to Rendertexture, return true directly.
2014-08-27 12:09:23 +08:00
// only cull the default camera. The culling algorithm is valid for default camera.
2015-08-21 17:38:56 +08:00
if ( ! scene | | ( scene & & scene - > _defaultCamera ! = Camera : : getVisitingCamera ( ) ) )
2014-08-27 12:09:23 +08:00
return true ;
2014-04-15 07:46:19 +08:00
2015-06-23 15:22:27 +08:00
auto director = Director : : getInstance ( ) ;
Rect visiableRect ( director - > getVisibleOrigin ( ) , director - > getVisibleSize ( ) ) ;
// transform center point to screen space
2014-04-15 07:46:19 +08:00
float hSizeX = size . width / 2 ;
float hSizeY = size . height / 2 ;
2015-06-23 15:22:27 +08:00
Vec3 v3p ( hSizeX , hSizeY , 0 ) ;
transform . transformPoint ( & v3p ) ;
Vec2 v2p = Camera : : getVisitingCamera ( ) - > projectGL ( v3p ) ;
2014-04-15 07:46:19 +08:00
// convert content size to world coordinates
2014-04-15 22:35:35 +08:00
float wshw = std : : max ( fabsf ( hSizeX * transform . m [ 0 ] + hSizeY * transform . m [ 4 ] ) , fabsf ( hSizeX * transform . m [ 0 ] - hSizeY * transform . m [ 4 ] ) ) ;
float wshh = std : : max ( fabsf ( hSizeX * transform . m [ 1 ] + hSizeY * transform . m [ 5 ] ) , fabsf ( hSizeX * transform . m [ 1 ] - hSizeY * transform . m [ 5 ] ) ) ;
2015-06-23 15:22:27 +08:00
2015-09-22 16:08:23 +08:00
// enlarge visible rect half size in screen coord
2015-06-23 15:22:27 +08:00
visiableRect . origin . x - = wshw ;
visiableRect . origin . y - = wshh ;
visiableRect . size . width + = wshw * 2 ;
visiableRect . size . height + = wshh * 2 ;
bool ret = visiableRect . containsPoint ( v2p ) ;
2014-04-15 07:46:19 +08:00
return ret ;
}
2015-01-10 06:06:21 +08:00
void Renderer : : setClearColor ( const Color4F & clearColor )
{
_clearColor = clearColor ;
}
2014-01-17 13:49:14 +08:00
NS_CC_END