2019-11-23 20:27:39 +08:00
/****************************************************************************
Copyright ( c ) 2013 - 2016 Chukong Technologies Inc .
Copyright ( c ) 2017 - 2018 Xiamen Yaji Software Co . , Ltd .
2020-02-23 21:27:14 +08:00
Copyright ( c ) 2020 c4games . com .
2019-11-23 20:27:39 +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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "renderer/CCRenderer.h"
# include <algorithm>
# include "renderer/CCTrianglesCommand.h"
# include "renderer/CCCustomCommand.h"
# include "renderer/CCCallbackCommand.h"
# include "renderer/CCGroupCommand.h"
# include "renderer/CCMeshCommand.h"
# include "renderer/CCMaterial.h"
# include "renderer/CCTechnique.h"
# include "renderer/CCPass.h"
# include "renderer/CCTexture2D.h"
# include "base/CCConfiguration.h"
# include "base/CCDirector.h"
# include "base/CCEventDispatcher.h"
# include "base/CCEventListenerCustom.h"
# include "base/CCEventType.h"
# include "2d/CCCamera.h"
# include "2d/CCScene.h"
# include "xxhash.h"
# include "renderer/backend/Backend.h"
NS_CC_BEGIN
// helper
static bool compareRenderCommand ( RenderCommand * a , RenderCommand * b )
{
return a - > getGlobalOrder ( ) < b - > getGlobalOrder ( ) ;
}
static bool compare3DCommand ( RenderCommand * a , RenderCommand * b )
{
return a - > getDepth ( ) > b - > getDepth ( ) ;
}
// queue
RenderQueue : : RenderQueue ( )
{
}
void RenderQueue : : push_back ( RenderCommand * command )
{
float z = command - > getGlobalOrder ( ) ;
if ( z < 0 )
{
_commands [ QUEUE_GROUP : : GLOBALZ_NEG ] . push_back ( command ) ;
}
else if ( z > 0 )
{
_commands [ QUEUE_GROUP : : GLOBALZ_POS ] . push_back ( command ) ;
}
else
{
if ( command - > is3D ( ) )
{
if ( command - > isTransparent ( ) )
{
_commands [ QUEUE_GROUP : : TRANSPARENT_3D ] . push_back ( command ) ;
}
else
{
_commands [ QUEUE_GROUP : : OPAQUE_3D ] . push_back ( command ) ;
}
}
else
{
_commands [ QUEUE_GROUP : : GLOBALZ_ZERO ] . push_back ( command ) ;
}
}
}
ssize_t RenderQueue : : size ( ) const
{
ssize_t result ( 0 ) ;
for ( int index = 0 ; index < QUEUE_GROUP : : QUEUE_COUNT ; + + index )
{
result + = _commands [ index ] . size ( ) ;
}
return result ;
}
void RenderQueue : : sort ( )
{
// Don't sort _queue0, it already comes sorted
std : : stable_sort ( std : : begin ( _commands [ QUEUE_GROUP : : TRANSPARENT_3D ] ) , std : : end ( _commands [ QUEUE_GROUP : : TRANSPARENT_3D ] ) , compare3DCommand ) ;
std : : stable_sort ( std : : begin ( _commands [ QUEUE_GROUP : : GLOBALZ_NEG ] ) , std : : end ( _commands [ QUEUE_GROUP : : GLOBALZ_NEG ] ) , compareRenderCommand ) ;
std : : stable_sort ( std : : begin ( _commands [ QUEUE_GROUP : : GLOBALZ_POS ] ) , std : : end ( _commands [ QUEUE_GROUP : : GLOBALZ_POS ] ) , compareRenderCommand ) ;
}
RenderCommand * RenderQueue : : operator [ ] ( ssize_t index ) const
{
for ( int queIndex = 0 ; queIndex < QUEUE_GROUP : : QUEUE_COUNT ; + + queIndex )
{
if ( index < static_cast < ssize_t > ( _commands [ queIndex ] . size ( ) ) )
return _commands [ queIndex ] [ index ] ;
else
{
index - = _commands [ queIndex ] . size ( ) ;
}
}
CCASSERT ( false , " invalid index " ) ;
return nullptr ;
}
void RenderQueue : : clear ( )
{
for ( int i = 0 ; i < QUEUE_GROUP : : QUEUE_COUNT ; + + i )
{
_commands [ i ] . clear ( ) ;
}
}
void RenderQueue : : realloc ( size_t reserveSize )
{
for ( int i = 0 ; i < QUEUE_GROUP : : QUEUE_COUNT ; + + i )
{
_commands [ i ] = std : : vector < RenderCommand * > ( ) ;
_commands [ i ] . reserve ( reserveSize ) ;
}
}
//
//
//
static const int DEFAULT_RENDER_QUEUE = 0 ;
//
// constructors, destructor, init
//
Renderer : : Renderer ( )
{
_groupCommandManager = new ( std : : nothrow ) GroupCommandManager ( ) ;
_commandGroupStack . push ( DEFAULT_RENDER_QUEUE ) ;
RenderQueue defaultRenderQueue ;
_renderGroups . push_back ( defaultRenderQueue ) ;
_queuedTriangleCommands . reserve ( BATCH_TRIAGCOMMAND_RESERVED_SIZE ) ;
// for the batched TriangleCommand
_triBatchesToDraw = ( TriBatchToDraw * ) malloc ( sizeof ( _triBatchesToDraw [ 0 ] ) * _triBatchesToDrawCapacity ) ;
}
Renderer : : ~ Renderer ( )
{
_renderGroups . clear ( ) ;
_groupCommandManager - > release ( ) ;
free ( _triBatchesToDraw ) ;
CC_SAFE_RELEASE ( _commandBuffer ) ;
CC_SAFE_RELEASE ( _renderPipeline ) ;
}
void Renderer : : init ( )
{
// Should invoke _triangleCommandBufferManager.init() first.
_triangleCommandBufferManager . init ( ) ;
_vertexBuffer = _triangleCommandBufferManager . getVertexBuffer ( ) ;
_indexBuffer = _triangleCommandBufferManager . getIndexBuffer ( ) ;
auto device = backend : : Device : : getInstance ( ) ;
_commandBuffer = device - > newCommandBuffer ( ) ;
_renderPipeline = device - > newRenderPipeline ( ) ;
_commandBuffer - > setRenderPipeline ( _renderPipeline ) ;
}
void Renderer : : addCommand ( RenderCommand * command )
{
int renderQueueID = _commandGroupStack . top ( ) ;
addCommand ( command , renderQueueID ) ;
}
void Renderer : : addCommand ( RenderCommand * command , int renderQueueID )
{
CCASSERT ( ! _isRendering , " Cannot add command while rendering " ) ;
CCASSERT ( renderQueueID > = 0 , " Invalid render queue " ) ;
CCASSERT ( command - > getType ( ) ! = RenderCommand : : Type : : UNKNOWN_COMMAND , " Invalid Command Type " ) ;
_renderGroups [ renderQueueID ] . push_back ( command ) ;
}
void Renderer : : pushGroup ( int renderQueueID )
{
CCASSERT ( ! _isRendering , " Cannot change render queue while rendering " ) ;
_commandGroupStack . push ( renderQueueID ) ;
}
void Renderer : : popGroup ( )
{
CCASSERT ( ! _isRendering , " Cannot change render queue while rendering " ) ;
_commandGroupStack . pop ( ) ;
}
int Renderer : : createRenderQueue ( )
{
RenderQueue newRenderQueue ;
_renderGroups . push_back ( newRenderQueue ) ;
return ( int ) _renderGroups . size ( ) - 1 ;
}
void Renderer : : processGroupCommand ( GroupCommand * command )
{
flush ( ) ;
int renderQueueID = ( ( GroupCommand * ) command ) - > getRenderQueueID ( ) ;
pushStateBlock ( ) ;
//apply default state for all render queues
setDepthTest ( false ) ;
setDepthWrite ( false ) ;
setCullMode ( backend : : CullMode : : NONE ) ;
visitRenderQueue ( _renderGroups [ renderQueueID ] ) ;
popStateBlock ( ) ;
}
void Renderer : : processRenderCommand ( RenderCommand * command )
{
auto commandType = command - > getType ( ) ;
switch ( commandType )
{
case RenderCommand : : Type : : TRIANGLES_COMMAND :
{
// flush other queues
flush3D ( ) ;
auto cmd = static_cast < TrianglesCommand * > ( command ) ;
// flush own queue when buffer is full
if ( _queuedTotalVertexCount + cmd - > getVertexCount ( ) > VBO_SIZE | | _queuedTotalIndexCount + cmd - > getIndexCount ( ) > INDEX_VBO_SIZE )
{
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 ( ) ;
_queuedTotalIndexCount = _queuedTotalVertexCount = 0 ;
# ifdef CC_USE_METAL
_queuedIndexCount = _queuedVertexCount = 0 ;
_triangleCommandBufferManager . prepareNextBuffer ( ) ;
_vertexBuffer = _triangleCommandBufferManager . getVertexBuffer ( ) ;
_indexBuffer = _triangleCommandBufferManager . getIndexBuffer ( ) ;
# endif
}
// queue it
_queuedTriangleCommands . push_back ( cmd ) ;
# ifdef CC_USE_METAL
_queuedIndexCount + = cmd - > getIndexCount ( ) ;
_queuedVertexCount + = cmd - > getVertexCount ( ) ;
# endif
_queuedTotalVertexCount + = cmd - > getVertexCount ( ) ;
_queuedTotalIndexCount + = cmd - > getIndexCount ( ) ;
}
break ;
case RenderCommand : : Type : : MESH_COMMAND :
flush2D ( ) ;
drawMeshCommand ( command ) ;
break ;
case RenderCommand : : Type : : GROUP_COMMAND :
processGroupCommand ( static_cast < GroupCommand * > ( command ) ) ;
break ;
case RenderCommand : : Type : : CUSTOM_COMMAND :
flush ( ) ;
drawCustomCommand ( command ) ;
break ;
case RenderCommand : : Type : : CALLBACK_COMMAND :
flush ( ) ;
static_cast < CallbackCommand * > ( command ) - > execute ( ) ;
break ;
case RenderCommand : : Type : : CAPTURE_SCREEN_COMMAND :
flush ( ) ;
captureScreen ( command ) ;
break ;
default :
assert ( false ) ;
break ;
}
}
void Renderer : : captureScreen ( RenderCommand * command )
{
_commandBuffer - > captureScreen ( static_cast < CaptureScreenCallbackCommand * > ( command ) - > func ) ;
}
void Renderer : : visitRenderQueue ( RenderQueue & queue )
{
//
//Process Global-Z < 0 Objects
//
doVisitRenderQueue ( queue . getSubQueue ( RenderQueue : : QUEUE_GROUP : : GLOBALZ_NEG ) ) ;
//
//Process Opaque Object
//
pushStateBlock ( ) ;
setDepthTest ( true ) ; //enable depth test in 3D queue by default
setDepthWrite ( true ) ;
setCullMode ( backend : : CullMode : : BACK ) ;
doVisitRenderQueue ( queue . getSubQueue ( RenderQueue : : QUEUE_GROUP : : OPAQUE_3D ) ) ;
//
//Process 3D Transparent object
//
setDepthWrite ( false ) ;
doVisitRenderQueue ( queue . getSubQueue ( RenderQueue : : QUEUE_GROUP : : TRANSPARENT_3D ) ) ;
popStateBlock ( ) ;
//
//Process Global-Z = 0 Queue
//
doVisitRenderQueue ( queue . getSubQueue ( RenderQueue : : QUEUE_GROUP : : GLOBALZ_ZERO ) ) ;
//
//Process Global-Z > 0 Queue
//
doVisitRenderQueue ( queue . getSubQueue ( RenderQueue : : QUEUE_GROUP : : GLOBALZ_POS ) ) ;
}
void Renderer : : doVisitRenderQueue ( const std : : vector < RenderCommand * > & renderCommands )
{
for ( const auto & command : renderCommands )
{
processRenderCommand ( command ) ;
}
flush ( ) ;
}
void Renderer : : render ( )
{
//TODO: setup camera or MVP
_isRendering = true ;
// if (_glViewAssigned)
{
//Process render commands
//1. Sort render commands based on ID
for ( auto & renderqueue : _renderGroups )
{
renderqueue . sort ( ) ;
}
visitRenderQueue ( _renderGroups [ 0 ] ) ;
}
clean ( ) ;
_isRendering = false ;
}
void Renderer : : beginFrame ( )
{
_commandBuffer - > beginFrame ( ) ;
}
void Renderer : : endFrame ( )
{
_commandBuffer - > endFrame ( ) ;
# ifdef CC_USE_METAL
_triangleCommandBufferManager . putbackAllBuffers ( ) ;
_vertexBuffer = _triangleCommandBufferManager . getVertexBuffer ( ) ;
_indexBuffer = _triangleCommandBufferManager . getIndexBuffer ( ) ;
# endif
_queuedTotalIndexCount = 0 ;
_queuedTotalVertexCount = 0 ;
}
void Renderer : : clean ( )
{
// Clear render group
for ( size_t j = 0 , size = _renderGroups . size ( ) ; j < size ; j + + )
{
//commands are owned by nodes
// for (const auto &cmd : _renderGroups[j])
// {
// cmd->releaseToCommandPool();
// }
_renderGroups [ j ] . clear ( ) ;
}
// Clear batch commands
_queuedTriangleCommands . clear ( ) ;
}
void Renderer : : setDepthTest ( bool value )
{
_depthStencilDescriptor . depthTestEnabled = value ;
_renderPassDescriptor . depthTestEnabled = value ;
}
void Renderer : : setDepthWrite ( bool value )
{
_depthStencilDescriptor . depthWriteEnabled = value ;
}
void Renderer : : setDepthCompareFunction ( backend : : CompareFunction func )
{
_depthStencilDescriptor . depthCompareFunction = func ;
}
backend : : CompareFunction Renderer : : getDepthCompareFunction ( ) const
{
return _depthStencilDescriptor . depthCompareFunction ;
}
bool Renderer : : Renderer : : getDepthTest ( ) const
{
return _depthStencilDescriptor . depthTestEnabled ;
}
bool Renderer : : getDepthWrite ( ) const
{
return _depthStencilDescriptor . depthWriteEnabled ;
}
void Renderer : : setStencilTest ( bool value )
{
_depthStencilDescriptor . stencilTestEnabled = value ;
_renderPassDescriptor . stencilTestEnabled = value ;
}
void Renderer : : setStencilCompareFunction ( backend : : CompareFunction func , unsigned int ref , unsigned int readMask )
{
_depthStencilDescriptor . frontFaceStencil . stencilCompareFunction = func ;
_depthStencilDescriptor . backFaceStencil . stencilCompareFunction = func ;
_depthStencilDescriptor . frontFaceStencil . readMask = readMask ;
_depthStencilDescriptor . backFaceStencil . readMask = readMask ;
_stencilRef = ref ;
}
void Renderer : : setStencilOperation ( backend : : StencilOperation stencilFailureOp ,
backend : : StencilOperation depthFailureOp ,
backend : : StencilOperation stencilDepthPassOp )
{
_depthStencilDescriptor . frontFaceStencil . stencilFailureOperation = stencilFailureOp ;
_depthStencilDescriptor . backFaceStencil . stencilFailureOperation = stencilFailureOp ;
_depthStencilDescriptor . frontFaceStencil . depthFailureOperation = depthFailureOp ;
_depthStencilDescriptor . backFaceStencil . depthFailureOperation = depthFailureOp ;
_depthStencilDescriptor . frontFaceStencil . depthStencilPassOperation = stencilDepthPassOp ;
_depthStencilDescriptor . backFaceStencil . depthStencilPassOperation = stencilDepthPassOp ;
}
void Renderer : : setStencilWriteMask ( unsigned int mask )
{
_depthStencilDescriptor . frontFaceStencil . writeMask = mask ;
_depthStencilDescriptor . backFaceStencil . writeMask = mask ;
}
bool Renderer : : getStencilTest ( ) const
{
return _depthStencilDescriptor . stencilTestEnabled ;
}
backend : : StencilOperation Renderer : : getStencilFailureOperation ( ) const
{
return _depthStencilDescriptor . frontFaceStencil . stencilFailureOperation ;
}
backend : : StencilOperation Renderer : : getStencilPassDepthFailureOperation ( ) const
{
return _depthStencilDescriptor . frontFaceStencil . depthFailureOperation ;
}
backend : : StencilOperation Renderer : : getStencilDepthPassOperation ( ) const
{
return _depthStencilDescriptor . frontFaceStencil . depthStencilPassOperation ;
}
backend : : CompareFunction Renderer : : getStencilCompareFunction ( ) const
{
return _depthStencilDescriptor . depthCompareFunction ;
}
unsigned int Renderer : : getStencilReadMask ( ) const
{
return _depthStencilDescriptor . frontFaceStencil . readMask ;
}
unsigned int Renderer : : getStencilWriteMask ( ) const
{
return _depthStencilDescriptor . frontFaceStencil . writeMask ;
}
unsigned int Renderer : : getStencilReferenceValue ( ) const
{
return _stencilRef ;
}
void Renderer : : setViewPort ( int x , int y , unsigned int w , unsigned int h )
{
_viewport . x = x ;
_viewport . y = y ;
_viewport . w = w ;
_viewport . h = h ;
}
void Renderer : : fillVerticesAndIndices ( const TrianglesCommand * cmd , unsigned int vertexBufferOffset )
{
size_t vertexCount = cmd - > getVertexCount ( ) ;
memcpy ( & _verts [ _filledVertex ] , cmd - > getVertices ( ) , sizeof ( V3F_C4B_T2F ) * vertexCount ) ;
// fill vertex, and convert them to world coordinates
const Mat4 & modelView = cmd - > getModelView ( ) ;
for ( size_t i = 0 ; i < vertexCount ; + + i )
{
modelView . transformPoint ( & ( _verts [ i + _filledVertex ] . vertices ) ) ;
}
// fill index
const unsigned short * indices = cmd - > getIndices ( ) ;
size_t indexCount = cmd - > getIndexCount ( ) ;
for ( size_t i = 0 ; i < indexCount ; + + i )
{
_indices [ _filledIndex + i ] = vertexBufferOffset + _filledVertex + indices [ i ] ;
}
_filledVertex + = vertexCount ;
_filledIndex + = indexCount ;
}
void Renderer : : drawBatchedTriangles ( )
{
if ( _queuedTriangleCommands . empty ( ) )
return ;
/************** 1: Setup up vertices/indices *************/
# ifdef CC_USE_METAL
unsigned int vertexBufferFillOffset = _queuedTotalVertexCount - _queuedVertexCount ;
unsigned int indexBufferFillOffset = _queuedTotalIndexCount - _queuedIndexCount ;
# else
unsigned int vertexBufferFillOffset = 0 ;
unsigned int indexBufferFillOffset = 0 ;
# endif
_triBatchesToDraw [ 0 ] . offset = indexBufferFillOffset ;
_triBatchesToDraw [ 0 ] . indicesToDraw = 0 ;
_triBatchesToDraw [ 0 ] . cmd = nullptr ;
int batchesTotal = 0 ;
int prevMaterialID = - 1 ;
bool firstCommand = true ;
_filledVertex = 0 ;
_filledIndex = 0 ;
for ( const auto & cmd : _queuedTriangleCommands )
{
auto currentMaterialID = cmd - > getMaterialID ( ) ;
const bool batchable = ! cmd - > isSkipBatching ( ) ;
fillVerticesAndIndices ( cmd , vertexBufferFillOffset ) ;
// 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
{
2020-02-23 21:31:55 +08:00
// is this the first one?
if ( ! firstCommand )
{
batchesTotal + + ;
_triBatchesToDraw [ batchesTotal ] . offset = _triBatchesToDraw [ batchesTotal - 1 ] . offset + _triBatchesToDraw [ batchesTotal - 1 ] . indicesToDraw ;
}
2019-11-23 20:27:39 +08:00
_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 ;
}
batchesTotal + + ;
# ifdef CC_USE_METAL
_vertexBuffer - > updateSubData ( _verts , vertexBufferFillOffset * sizeof ( _verts [ 0 ] ) , _filledVertex * sizeof ( _verts [ 0 ] ) ) ;
_indexBuffer - > updateSubData ( _indices , indexBufferFillOffset * sizeof ( _indices [ 0 ] ) , _filledIndex * sizeof ( _indices [ 0 ] ) ) ;
# else
_vertexBuffer - > updateData ( _verts , _filledVertex * sizeof ( _verts [ 0 ] ) ) ;
_indexBuffer - > updateData ( _indices , _filledIndex * sizeof ( _indices [ 0 ] ) ) ;
# endif
/************** 2: Draw *************/
for ( int i = 0 ; i < batchesTotal ; + + i )
{
beginRenderPass ( _triBatchesToDraw [ i ] . cmd ) ;
_commandBuffer - > setVertexBuffer ( _vertexBuffer ) ;
_commandBuffer - > setIndexBuffer ( _indexBuffer ) ;
auto & pipelineDescriptor = _triBatchesToDraw [ i ] . cmd - > getPipelineDescriptor ( ) ;
_commandBuffer - > setProgramState ( pipelineDescriptor . programState ) ;
_commandBuffer - > drawElements ( backend : : PrimitiveType : : TRIANGLE ,
backend : : IndexFormat : : U_SHORT ,
_triBatchesToDraw [ i ] . indicesToDraw ,
_triBatchesToDraw [ i ] . offset * sizeof ( _indices [ 0 ] ) ) ;
_commandBuffer - > endRenderPass ( ) ;
_drawnBatches + + ;
_drawnVertices + = _triBatchesToDraw [ i ] . indicesToDraw ;
}
/************** 3: Cleanup *************/
_queuedTriangleCommands . clear ( ) ;
# ifdef CC_USE_METAL
_queuedIndexCount = 0 ;
_queuedVertexCount = 0 ;
# endif
}
void Renderer : : drawCustomCommand ( RenderCommand * command )
{
auto cmd = static_cast < CustomCommand * > ( command ) ;
if ( cmd - > getBeforeCallback ( ) ) cmd - > getBeforeCallback ( ) ( ) ;
beginRenderPass ( command ) ;
_commandBuffer - > setVertexBuffer ( cmd - > getVertexBuffer ( ) ) ;
_commandBuffer - > setProgramState ( cmd - > getPipelineDescriptor ( ) . programState ) ;
auto drawType = cmd - > getDrawType ( ) ;
_commandBuffer - > setLineWidth ( cmd - > getLineWidth ( ) ) ;
if ( CustomCommand : : DrawType : : ELEMENT = = drawType )
{
_commandBuffer - > setIndexBuffer ( cmd - > getIndexBuffer ( ) ) ;
_commandBuffer - > drawElements ( cmd - > getPrimitiveType ( ) ,
cmd - > getIndexFormat ( ) ,
cmd - > getIndexDrawCount ( ) ,
cmd - > getIndexDrawOffset ( ) ) ;
_drawnVertices + = cmd - > getIndexDrawCount ( ) ;
}
else
{
_commandBuffer - > drawArrays ( cmd - > getPrimitiveType ( ) ,
cmd - > getVertexDrawStart ( ) ,
cmd - > getVertexDrawCount ( ) ) ;
_drawnVertices + = cmd - > getVertexDrawCount ( ) ;
}
_drawnBatches + + ;
_commandBuffer - > endRenderPass ( ) ;
if ( cmd - > getAfterCallback ( ) ) cmd - > getAfterCallback ( ) ( ) ;
}
void Renderer : : drawMeshCommand ( RenderCommand * command )
{
//MeshCommand and CustomCommand are identical while rendering.
drawCustomCommand ( command ) ;
}
void Renderer : : flush ( )
{
flush2D ( ) ;
flush3D ( ) ;
}
void Renderer : : flush2D ( )
{
flushTriangles ( ) ;
}
void Renderer : : flush3D ( )
{
//TODO 3d batch rendering
}
void Renderer : : flushTriangles ( )
{
drawBatchedTriangles ( ) ;
}
// helpers
bool Renderer : : checkVisibility ( const Mat4 & transform , const Size & size )
{
auto director = Director : : getInstance ( ) ;
auto scene = director - > getRunningScene ( ) ;
//If draw to Rendertexture, return true directly.
// only cull the default camera. The culling algorithm is valid for default camera.
if ( ! scene | | ( scene & & scene - > _defaultCamera ! = Camera : : getVisitingCamera ( ) ) )
return true ;
Rect visibleRect ( director - > getVisibleOrigin ( ) , director - > getVisibleSize ( ) ) ;
// transform center point to screen space
float hSizeX = size . width / 2 ;
float hSizeY = size . height / 2 ;
Vec3 v3p ( hSizeX , hSizeY , 0 ) ;
transform . transformPoint ( & v3p ) ;
Vec2 v2p = Camera : : getVisitingCamera ( ) - > projectGL ( v3p ) ;
// convert content size to world coordinates
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 ] ) ) ;
// enlarge visible rect half size in screen coord
visibleRect . origin . x - = wshw ;
visibleRect . origin . y - = wshh ;
visibleRect . size . width + = wshw * 2 ;
visibleRect . size . height + = wshh * 2 ;
bool ret = visibleRect . containsPoint ( v2p ) ;
return ret ;
}
void Renderer : : setRenderPipeline ( const PipelineDescriptor & pipelineDescriptor , const backend : : RenderPassDescriptor & renderPassDescriptor )
{
auto device = backend : : Device : : getInstance ( ) ;
_renderPipeline - > update ( pipelineDescriptor , renderPassDescriptor ) ;
backend : : DepthStencilState * depthStencilState = nullptr ;
auto needDepthStencilAttachment = renderPassDescriptor . depthTestEnabled | | renderPassDescriptor . stencilTestEnabled ;
if ( needDepthStencilAttachment )
{
depthStencilState = device - > createDepthStencilState ( _depthStencilDescriptor ) ;
}
_commandBuffer - > setDepthStencilState ( depthStencilState ) ;
# ifdef CC_USE_METAL
_commandBuffer - > setRenderPipeline ( _renderPipeline ) ;
# endif
}
void Renderer : : beginRenderPass ( RenderCommand * cmd )
{
_commandBuffer - > beginRenderPass ( _renderPassDescriptor ) ;
_commandBuffer - > setViewport ( _viewport . x , _viewport . y , _viewport . w , _viewport . h ) ;
_commandBuffer - > setCullMode ( _cullMode ) ;
_commandBuffer - > setWinding ( _winding ) ;
_commandBuffer - > setScissorRect ( _scissorState . isEnabled , _scissorState . rect . x , _scissorState . rect . y , _scissorState . rect . width , _scissorState . rect . height ) ;
setRenderPipeline ( cmd - > getPipelineDescriptor ( ) , _renderPassDescriptor ) ;
_commandBuffer - > setStencilReferenceValue ( _stencilRef ) ;
}
void Renderer : : setRenderTarget ( RenderTargetFlag flags , Texture2D * colorAttachment , Texture2D * depthAttachment , Texture2D * stencilAttachment )
{
_renderTargetFlag = flags ;
2020-02-23 21:27:14 +08:00
if ( _Bitmask_includes ( RenderTargetFlag : : COLOR , flags ) )
2019-11-23 20:27:39 +08:00
{
_renderPassDescriptor . needColorAttachment = true ;
if ( colorAttachment )
_renderPassDescriptor . colorAttachmentsTexture [ 0 ] = colorAttachment - > getBackendTexture ( ) ;
else
_renderPassDescriptor . colorAttachmentsTexture [ 0 ] = nullptr ;
_colorAttachment = colorAttachment ;
}
else
{
_colorAttachment = nullptr ;
_renderPassDescriptor . needColorAttachment = false ;
_renderPassDescriptor . colorAttachmentsTexture [ 0 ] = nullptr ;
}
2020-02-23 21:27:14 +08:00
if ( _Bitmask_includes ( RenderTargetFlag : : DEPTH , flags ) )
2019-11-23 20:27:39 +08:00
{
_renderPassDescriptor . depthTestEnabled = true ;
if ( depthAttachment )
_renderPassDescriptor . depthAttachmentTexture = depthAttachment - > getBackendTexture ( ) ;
else
_renderPassDescriptor . depthAttachmentTexture = nullptr ;
_depthAttachment = depthAttachment ;
}
else
{
_renderPassDescriptor . depthTestEnabled = false ;
_renderPassDescriptor . depthAttachmentTexture = nullptr ;
_depthAttachment = nullptr ;
}
2020-02-23 21:27:14 +08:00
if ( _Bitmask_includes ( RenderTargetFlag : : STENCIL , flags ) )
2019-11-23 20:27:39 +08:00
{
_stencilAttachment = stencilAttachment ;
_renderPassDescriptor . stencilTestEnabled = true ;
if ( _stencilAttachment )
_renderPassDescriptor . stencilAttachmentTexture = stencilAttachment - > getBackendTexture ( ) ;
else
_renderPassDescriptor . stencilAttachmentTexture = nullptr ;
}
else
{
_stencilAttachment = nullptr ;
_renderPassDescriptor . stencilTestEnabled = false ;
_renderPassDescriptor . stencilAttachmentTexture = nullptr ;
}
}
void Renderer : : clear ( ClearFlag flags , const Color4F & color , float depth , unsigned int stencil , float globalOrder )
{
_clearFlag = flags ;
CallbackCommand * command = new CallbackCommand ( ) ;
command - > init ( globalOrder ) ;
command - > func = [ = ] ( ) - > void {
backend : : RenderPassDescriptor descriptor ;
2020-02-23 21:27:14 +08:00
if ( _Bitmask_includes ( ClearFlag : : COLOR , flags ) )
2019-11-23 20:27:39 +08:00
{
_clearColor = color ;
descriptor . clearColorValue = { color . r , color . g , color . b , color . a } ;
descriptor . needClearColor = true ;
descriptor . needColorAttachment = true ;
descriptor . colorAttachmentsTexture [ 0 ] = _renderPassDescriptor . colorAttachmentsTexture [ 0 ] ;
}
2020-02-23 21:27:14 +08:00
if ( _Bitmask_includes ( ClearFlag : : DEPTH , flags ) )
2019-11-23 20:27:39 +08:00
{
descriptor . clearDepthValue = depth ;
descriptor . needClearDepth = true ;
descriptor . depthTestEnabled = true ;
descriptor . depthAttachmentTexture = _renderPassDescriptor . depthAttachmentTexture ;
}
2020-02-23 21:27:14 +08:00
if ( _Bitmask_includes ( ClearFlag : : STENCIL , flags ) )
2019-11-23 20:27:39 +08:00
{
descriptor . clearStencilValue = stencil ;
descriptor . needClearStencil = true ;
descriptor . stencilTestEnabled = true ;
descriptor . stencilAttachmentTexture = _renderPassDescriptor . stencilAttachmentTexture ;
}
_commandBuffer - > beginRenderPass ( descriptor ) ;
_commandBuffer - > endRenderPass ( ) ;
delete command ;
} ;
addCommand ( command ) ;
}
Texture2D * Renderer : : getColorAttachment ( ) const
{
return _colorAttachment ;
}
Texture2D * Renderer : : getDepthAttachment ( ) const
{
return _depthAttachment ;
}
Texture2D * Renderer : : getStencilAttachment ( ) const
{
return _stencilAttachment ;
}
const Color4F & Renderer : : getClearColor ( ) const
{
return _clearColor ;
}
float Renderer : : getClearDepth ( ) const
{
return _renderPassDescriptor . clearDepthValue ;
}
unsigned int Renderer : : getClearStencil ( ) const
{
return _renderPassDescriptor . clearStencilValue ;
}
ClearFlag Renderer : : getClearFlag ( ) const
{
return _clearFlag ;
}
RenderTargetFlag Renderer : : getRenderTargetFlag ( ) const
{
return _renderTargetFlag ;
}
void Renderer : : setScissorTest ( bool enabled )
{
_scissorState . isEnabled = enabled ;
}
bool Renderer : : getScissorTest ( ) const
{
return _scissorState . isEnabled ;
}
const ScissorRect & Renderer : : getScissorRect ( ) const
{
return _scissorState . rect ;
}
void Renderer : : setScissorRect ( float x , float y , float width , float height )
{
_scissorState . rect . x = x ;
_scissorState . rect . y = y ;
_scissorState . rect . width = width ;
_scissorState . rect . height = height ;
}
// TriangleCommandBufferManager
Renderer : : TriangleCommandBufferManager : : ~ TriangleCommandBufferManager ( )
{
for ( auto & vertexBuffer : _vertexBufferPool )
vertexBuffer - > release ( ) ;
for ( auto & indexBuffer : _indexBufferPool )
indexBuffer - > release ( ) ;
}
void Renderer : : TriangleCommandBufferManager : : init ( )
{
createBuffer ( ) ;
}
void Renderer : : TriangleCommandBufferManager : : putbackAllBuffers ( )
{
_currentBufferIndex = 0 ;
}
void Renderer : : TriangleCommandBufferManager : : prepareNextBuffer ( )
{
if ( _currentBufferIndex < ( int ) _vertexBufferPool . size ( ) - 1 )
{
+ + _currentBufferIndex ;
return ;
}
createBuffer ( ) ;
+ + _currentBufferIndex ;
}
backend : : Buffer * Renderer : : TriangleCommandBufferManager : : getVertexBuffer ( ) const
{
return _vertexBufferPool [ _currentBufferIndex ] ;
}
backend : : Buffer * Renderer : : TriangleCommandBufferManager : : getIndexBuffer ( ) const
{
return _indexBufferPool [ _currentBufferIndex ] ;
}
void Renderer : : TriangleCommandBufferManager : : createBuffer ( )
{
auto device = backend : : Device : : getInstance ( ) ;
# ifdef CC_USE_METAL
// Metal doesn't need to update buffer to make sure it has the correct size.
auto vertexBuffer = device - > newBuffer ( Renderer : : VBO_SIZE * sizeof ( _verts [ 0 ] ) , backend : : BufferType : : VERTEX , backend : : BufferUsage : : DYNAMIC ) ;
if ( ! vertexBuffer )
return ;
auto indexBuffer = device - > newBuffer ( Renderer : : INDEX_VBO_SIZE * sizeof ( _indices [ 0 ] ) , backend : : BufferType : : INDEX , backend : : BufferUsage : : DYNAMIC ) ;
if ( ! indexBuffer )
{
vertexBuffer - > release ( ) ;
return ;
}
# else
auto tmpData = malloc ( Renderer : : VBO_SIZE * sizeof ( V3F_C4B_T2F ) ) ;
if ( ! tmpData )
return ;
auto vertexBuffer = device - > newBuffer ( Renderer : : VBO_SIZE * sizeof ( V3F_C4B_T2F ) , backend : : BufferType : : VERTEX , backend : : BufferUsage : : DYNAMIC ) ;
if ( ! vertexBuffer )
{
free ( tmpData ) ;
return ;
}
vertexBuffer - > updateData ( tmpData , Renderer : : VBO_SIZE * sizeof ( V3F_C4B_T2F ) ) ;
auto indexBuffer = device - > newBuffer ( Renderer : : INDEX_VBO_SIZE * sizeof ( unsigned short ) , backend : : BufferType : : INDEX , backend : : BufferUsage : : DYNAMIC ) ;
if ( ! indexBuffer )
{
free ( tmpData ) ;
vertexBuffer - > release ( ) ;
return ;
}
indexBuffer - > updateData ( tmpData , Renderer : : INDEX_VBO_SIZE * sizeof ( unsigned short ) ) ;
free ( tmpData ) ;
# endif
_vertexBufferPool . push_back ( vertexBuffer ) ;
_indexBufferPool . push_back ( indexBuffer ) ;
}
void Renderer : : pushStateBlock ( )
{
StateBlock block ;
block . depthTest = getDepthTest ( ) ;
block . depthWrite = getDepthWrite ( ) ;
block . cullMode = getCullMode ( ) ;
_stateBlockStack . emplace_back ( block ) ;
}
void Renderer : : popStateBlock ( )
{
auto & block = _stateBlockStack . back ( ) ;
setDepthTest ( block . depthTest ) ;
setDepthWrite ( block . depthWrite ) ;
setCullMode ( block . cullMode ) ;
_stateBlockStack . pop_back ( ) ;
}
NS_CC_END