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-04-30 08:37:36 +08:00
# include "renderer/CCRenderer.h"
2014-04-15 07:46:19 +08:00
# include <algorithm>
2014-04-30 08:37:36 +08:00
# include "renderer/CCQuadCommand.h"
# include "renderer/CCBatchCommand.h"
# include "renderer/CCCustomCommand.h"
# include "renderer/CCGroupCommand.h"
2014-08-05 15:08:01 +08:00
# include "renderer/CCPrimitiveCommand.h"
2014-05-10 09:39:25 +08:00
# include "renderer/CCGLProgramCache.h"
2014-05-09 09:01:48 +08:00
# include "renderer/ccGLStateCache.h"
2014-05-19 05:49:16 +08:00
# include "renderer/CCMeshCommand.h"
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-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
}
2014-04-15 07:46:19 +08:00
// queue
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
{
2014-04-09 23:54:40 +08:00
if ( index < static_cast < ssize_t > ( _queueNegZ . size ( ) ) )
2014-01-18 15:10:04 +08:00
return _queueNegZ [ index ] ;
2013-11-05 01:14:22 +08:00
2014-01-18 15:10:04 +08:00
index - = _queueNegZ . size ( ) ;
2014-04-09 23:54:40 +08:00
if ( index < static_cast < ssize_t > ( _queue0 . size ( ) ) )
2014-01-18 15:10:04 +08:00
return _queue0 [ index ] ;
index - = _queue0 . size ( ) ;
2014-04-09 23:54:40 +08:00
if ( index < static_cast < ssize_t > ( _queuePosZ . size ( ) ) )
2014-01-18 15:10:04 +08:00
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
//
//
//
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
//
// constructors, destructors, init
//
2013-11-05 01:14:22 +08:00
Renderer : : Renderer ( )
2013-11-08 02:09:53 +08:00
: _lastMaterialID ( 0 )
2014-06-23 23:58:45 +08:00
, _lastBatchedMeshCommand ( nullptr )
2013-12-27 15:06:16 +08:00
, _numQuads ( 0 )
2013-11-22 08:36:19 +08:00
, _glViewAssigned ( false )
2014-04-11 16:05:22 +08:00
, _isRendering ( 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
{
2014-04-12 13:01:42 +08:00
_groupCommandManager = new GroupCommandManager ( ) ;
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 ) ;
2014-01-22 18:24:23 +08:00
_batchedQuadCommands . reserve ( BATCH_QUADCOMMAND_RESEVER_SIZE ) ;
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 ) ;
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
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
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
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 ] ) ;
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-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 " ) ;
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 )
{
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
}
2014-04-07 22:51:32 +08:00
void Renderer : : visitRenderQueue ( const RenderQueue & queue )
{
ssize_t size = queue . size ( ) ;
2014-04-11 13:51:40 +08:00
for ( ssize_t index = 0 ; index < size ; + + index )
2014-04-07 22:51:32 +08:00
{
auto command = queue [ index ] ;
auto commandType = command - > getType ( ) ;
if ( RenderCommand : : Type : : QUAD_COMMAND = = commandType )
{
2014-06-23 23:58:45 +08:00
flush3D ( ) ;
2014-04-07 22:51:32 +08:00
auto cmd = static_cast < QuadCommand * > ( command ) ;
//Batch quads
if ( _numQuads + cmd - > getQuadCount ( ) > VBO_SIZE )
{
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 " ) ;
//Draw batched quads if VBO is full
drawBatchedQuads ( ) ;
}
_batchedQuadCommands . push_back ( cmd ) ;
memcpy ( _quads + _numQuads , cmd - > getQuads ( ) , sizeof ( V3F_C4B_T2F_Quad ) * cmd - > getQuadCount ( ) ) ;
convertToWorldCoordinates ( _quads + _numQuads , cmd - > getQuadCount ( ) , cmd - > getModelView ( ) ) ;
_numQuads + = cmd - > getQuadCount ( ) ;
}
else if ( RenderCommand : : Type : : GROUP_COMMAND = = commandType )
{
flush ( ) ;
int renderQueueID = ( ( GroupCommand * ) command ) - > getRenderQueueID ( ) ;
visitRenderQueue ( _renderGroups [ renderQueueID ] ) ;
}
else if ( RenderCommand : : Type : : CUSTOM_COMMAND = = commandType )
{
flush ( ) ;
auto cmd = static_cast < CustomCommand * > ( command ) ;
cmd - > execute ( ) ;
}
else if ( RenderCommand : : Type : : BATCH_COMMAND = = commandType )
{
flush ( ) ;
auto cmd = static_cast < BatchCommand * > ( command ) ;
2014-08-05 15:08:01 +08:00
cmd - > execute ( ) ;
}
else if ( RenderCommand : : Type : : PRIMITIVE_COMMAND = = commandType )
{
flush ( ) ;
auto cmd = static_cast < PrimitiveCommand * > ( command ) ;
2014-04-07 22:51:32 +08:00
cmd - > execute ( ) ;
}
2014-05-19 05:49:16 +08:00
else if ( RenderCommand : : Type : : MESH_COMMAND = = commandType )
{
2014-06-23 23:58:45 +08:00
flush2D ( ) ;
2014-05-19 05:49:16 +08:00
auto cmd = static_cast < MeshCommand * > ( command ) ;
2014-06-24 09:27:10 +08:00
if ( _lastBatchedMeshCommand = = nullptr | | _lastBatchedMeshCommand - > getMaterialID ( ) ! = cmd - > getMaterialID ( ) )
{
flush3D ( ) ;
2014-06-24 19:45:51 +08:00
cmd - > preBatchDraw ( ) ;
cmd - > batchDraw ( ) ;
2014-06-25 17:36:55 +08:00
_lastBatchedMeshCommand = cmd ;
2014-06-24 09:27:10 +08:00
}
else
{
2014-06-24 19:45:51 +08:00
cmd - > batchDraw ( ) ;
2014-06-24 09:27:10 +08:00
}
2014-05-19 05:49:16 +08:00
}
2014-04-07 22:51:32 +08:00
else
{
CCLOGERROR ( " Unknown commands in renderQueue " ) ;
}
}
}
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
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
{
2014-02-08 11:37:44 +08:00
// cleanup
_drawnBatches = _drawnVertices = 0 ;
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 ] ) ;
flush ( ) ;
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
// Clear batch quad commands
_batchedQuadCommands . clear ( ) ;
_numQuads = 0 ;
2013-11-11 16:14:29 +08:00
_lastMaterialID = 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
2014-05-15 01:07:09 +08:00
void Renderer : : convertToWorldCoordinates ( V3F_C4B_T2F_Quad * quads , ssize_t quantity , const Mat4 & modelView )
2014-01-16 06:35:26 +08:00
{
2014-01-17 13:35:58 +08:00
// kmMat4 matrixP, mvp;
// kmGLGetMatrix(KM_GL_PROJECTION, &matrixP);
// kmMat4Multiply(&mvp, &matrixP, &modelView);
2014-04-09 14:21:41 +08:00
for ( ssize_t i = 0 ; i < quantity ; + + i )
{
2014-01-16 06:35:26 +08:00
V3F_C4B_T2F_Quad * q = & quads [ i ] ;
2014-05-15 01:07:09 +08:00
Vec3 * vec1 = ( Vec3 * ) & q - > bl . vertices ;
2014-04-10 22:38:57 +08:00
modelView . transformPoint ( vec1 ) ;
2014-01-16 06:35:26 +08:00
2014-05-15 01:07:09 +08:00
Vec3 * vec2 = ( Vec3 * ) & q - > br . vertices ;
2014-04-10 22:38:57 +08:00
modelView . transformPoint ( vec2 ) ;
2014-01-16 11:10:40 +08:00
2014-05-15 01:07:09 +08:00
Vec3 * vec3 = ( Vec3 * ) & q - > tr . vertices ;
2014-04-10 22:38:57 +08:00
modelView . transformPoint ( vec3 ) ;
2014-01-16 11:10:40 +08:00
2014-05-15 01:07:09 +08:00
Vec3 * vec4 = ( Vec3 * ) & q - > tl . vertices ;
2014-04-10 22:38:57 +08:00
modelView . transformPoint ( vec4 ) ;
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 18:24:23 +08:00
if ( _numQuads < = 0 | | _batchedQuadCommands . empty ( ) )
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
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 ] ) ;
}
2013-11-11 16:14:29 +08:00
2013-11-12 03:54:08 +08:00
//Start drawing verties in batch
2014-01-22 18:24:23 +08:00
for ( const auto & cmd : _batchedQuadCommands )
2013-11-11 16:14:29 +08:00
{
2014-05-13 10:12:56 +08:00
auto newMaterialID = cmd - > getMaterialID ( ) ;
2014-05-13 14:51:37 +08:00
if ( _lastMaterialID ! = newMaterialID | | newMaterialID = = QuadCommand : : MATERIAL_ID_DO_NOT_BATCH )
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 ] ) ) ) ;
2014-02-08 11:37:44 +08:00
_drawnBatches + + ;
_drawnVertices + = quadsToDraw * 6 ;
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 ( ) ;
2014-05-13 10:12:56 +08:00
_lastMaterialID = newMaterialID ;
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 ] ) ) ) ;
2014-02-08 11:37:44 +08:00
_drawnBatches + + ;
_drawnVertices + = quadsToDraw * 6 ;
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 ( )
2014-06-23 23:58:45 +08:00
{
flush2D ( ) ;
flush3D ( ) ;
}
void Renderer : : flush2D ( )
2013-11-09 04:06:39 +08:00
{
2013-11-12 03:54:08 +08:00
drawBatchedQuads ( ) ;
2013-11-09 04:06:39 +08:00
_lastMaterialID = 0 ;
}
2014-06-23 23:58:45 +08:00
void Renderer : : flush3D ( )
{
if ( _lastBatchedMeshCommand )
{
2014-06-24 19:45:51 +08:00
_lastBatchedMeshCommand - > postBatchDraw ( ) ;
2014-06-23 23:58:45 +08:00
_lastBatchedMeshCommand = nullptr ;
}
}
2014-04-15 07:46:19 +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
{
// half size of the screen
Size screen_half = Director : : getInstance ( ) - > getWinSize ( ) ;
screen_half . width / = 2 ;
screen_half . height / = 2 ;
float hSizeX = size . width / 2 ;
float hSizeY = size . height / 2 ;
2014-05-15 01:07:09 +08:00
Vec4 v4world , v4local ;
2014-04-15 22:35:35 +08:00
v4local . set ( hSizeX , hSizeY , 0 , 1 ) ;
transform . transformVector ( v4local , & v4world ) ;
2014-04-15 07:46:19 +08:00
// center of screen is (0,0)
v4world . x - = screen_half . width ;
v4world . y - = screen_half . height ;
// 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 ] ) ) ;
2014-04-15 07:46:19 +08:00
// compare if it in the positive quadrant of the screen
float tmpx = ( fabsf ( v4world . x ) - wshw ) ;
float tmpy = ( fabsf ( v4world . y ) - wshh ) ;
bool ret = ( tmpx < screen_half . width & & tmpy < screen_half . height ) ;
return ret ;
}
2014-01-17 13:49:14 +08:00
NS_CC_END