diff --git a/cocos/2d/CustomCommand.cpp b/cocos/2d/CustomCommand.cpp index ee92cd6bd2..86befadde6 100644 --- a/cocos/2d/CustomCommand.cpp +++ b/cocos/2d/CustomCommand.cpp @@ -27,8 +27,7 @@ int64_t CustomCommand::generateID() _id = (int64_t)_viewport << 61 | (int64_t)1 << 60 // translucent - | (int64_t)0 << 59 // is command - | (int64_t)_depth << 35; + | (int64_t)_depth << 36; return _id; } diff --git a/cocos/2d/CustomCommand.h b/cocos/2d/CustomCommand.h index a0f3bcd8ff..bc6dc99684 100644 --- a/cocos/2d/CustomCommand.h +++ b/cocos/2d/CustomCommand.h @@ -20,8 +20,8 @@ public: // +----------+----------+-----+-----------------------------------+ // | | | | | | - // | ViewPort | Transluc | Cmd | Depth | | - // | 3 bits | 1 bit | 1 | 24 bits | | + // | ViewPort | Transluc | | Depth | | + // | 3 bits | 1 bit | | 24 bits | | // +----------+----------+-----+----------------+------------------+ virtual int64_t generateID(); @@ -29,9 +29,6 @@ public: inline bool isTranslucent() { return true; } - //TODO support non-graphical command - inline bool isCommand() { return false; } - public: function func; diff --git a/cocos/2d/renderer/QuadCommand.cpp b/cocos/2d/renderer/QuadCommand.cpp index 391664148d..95a65f28f2 100644 --- a/cocos/2d/renderer/QuadCommand.cpp +++ b/cocos/2d/renderer/QuadCommand.cpp @@ -18,6 +18,7 @@ QuadCommand::QuadCommand(int viewport, int32_t depth, GLuint textureID, GLProgra { _type = QUAD_COMMAND; _shader = shader; + _quadCount = 1; } QuadCommand::~QuadCommand() @@ -65,8 +66,7 @@ int64_t QuadCommand::generateID() //Generate RenderCommandID _id = (int64_t)_viewport << 61 | (int64_t)1 << 60 //translucent - | (int64_t)0 << 59 //is command - | (int64_t)_depth << 35; + | (int64_t)_depth << 36; return _id; } diff --git a/cocos/2d/renderer/QuadCommand.h b/cocos/2d/renderer/QuadCommand.h index fb1ec48328..6b984b322f 100644 --- a/cocos/2d/renderer/QuadCommand.h +++ b/cocos/2d/renderer/QuadCommand.h @@ -21,8 +21,8 @@ public: // +----------+----------+-----+-----------------------------------+ // | | | | | | - // | ViewPort | Transluc | Cmd | Depth | Material ID | - // | 3 bits | 1 bit | 1 | 24 bits | 24 bit2 | + // | ViewPort | Transluc | | Depth | Material ID | + // | 3 bits | 1 bit | | 24 bits | 24 bit2 | // +----------+----------+-----+----------------+------------------+ virtual int64_t generateID(); @@ -31,14 +31,14 @@ public: //TODO use material to decide if it is translucent inline bool isTranslucent() { return true; } - inline bool isCommand() { return false; } - inline int32_t getMaterialID() { return _materialID; } inline GLuint getTextureID() { return _textureID; } inline V3F_C4B_T2F_Quad* getQuad() { return &_quad; } + inline int getQuadCount() { return _quadCount; } + inline GLProgram* getShader() { return _shader; } inline BlendFunc getBlendType() { return _blendType; } @@ -61,6 +61,7 @@ protected: BlendFunc _blendType; V3F_C4B_T2F_Quad _quad; + int _quadCount; }; NS_CC_END diff --git a/cocos/2d/renderer/Renderer.cpp b/cocos/2d/renderer/Renderer.cpp index 867c2ac8f5..dbb8450da4 100644 --- a/cocos/2d/renderer/Renderer.cpp +++ b/cocos/2d/renderer/Renderer.cpp @@ -36,27 +36,18 @@ void Renderer::destroyInstance() Renderer::Renderer() :_lastMaterialID(0) ,_numQuads(0) +,_firstCommand(0) +,_lastCommand(0) { } Renderer::~Renderer() { - free(_quads); } bool Renderer::init() { - _quads = (V3F_C4B_T2F_Quad*)malloc(sizeof(V3F_C4B_T2F_Quad) * VBO_SIZE); - _indices = (GLushort*) malloc(sizeof(GLushort) * 6 * VBO_SIZE); - if( ! ( _quads && _indices) ) - { - //not enough memory - CC_SAFE_FREE(_quads); - CC_SAFE_FREE(_indices); - return false; - } - setupIndices(); setupVBOAndVAO(); @@ -132,57 +123,145 @@ void Renderer::render() //1. Sort render commands based on ID stable_sort(_renderQueue.begin(), _renderQueue.end(), compareRenderCommand); - //2. Process commands - for(auto it = _renderQueue.begin(); it != _renderQueue.end(); ++it) + size_t len = _renderQueue.size(); + + for (size_t i = 0; i < len; i++) { - //TODO: Perform Sprite batching here - auto command = *it; + auto command = _renderQueue[i]; - switch(command->getType()) + if( command->getType() == QUAD_COMMAND ) { - case QUAD_COMMAND: + QuadCommand* cmd = static_cast(command); + + // + if(_numQuads + cmd->getQuadCount() < VBO_SIZE) { - QuadCommand* cmd = static_cast(command); - - if(_lastMaterialID != cmd->getMaterialID() || _numQuads >= VBO_SIZE) - { - //Draw batched data - drawQuads(); - } - - //Reset material if needed. - if(_lastMaterialID != cmd->getMaterialID()) - { - //Set new material - _lastMaterialID = cmd->getMaterialID(); - - //Set Shader - cmd->useMaterial(); - } - - - batchQuads(cmd); - - break; + memcpy(_quads + _numQuads - 1, cmd->getQuad(), sizeof(V3F_C4B_T2F_Quad) * cmd->getQuadCount()); + _numQuads += cmd->getQuadCount(); + _lastCommand = i; } - case CUSTOM_COMMAND: + else { - flush(); - CustomCommand* cmd = static_cast(command); - cmd->execute(); - - break; + //Draw batched quads if VBO is full + drawBatchedQuads(); } - default: - break; + + } + else + { + //Draw batched quads if we encountered a different command + drawBatchedQuads(); } - - delete command; } - drawQuads(); + //Draw the batched quads + drawBatchedQuads(); + _firstCommand = _lastCommand = 0; + _lastMaterialID = 0; _renderQueue.clear(); + +// //2. Process commands +// for(auto it = _renderQueue.begin(); it != _renderQueue.end(); ++it) +// { +// //TODO: Perform Sprite batching here +// auto command = *it; +// +// switch(command->getType()) +// { +// case QUAD_COMMAND: +// { +// QuadCommand* cmd = static_cast(command); +// +// if(_lastMaterialID != cmd->getMaterialID() || _numQuads >= VBO_SIZE) +// { +// //Draw batched data +// drawQuads(); +// } +// +// //Reset material if needed. +// if(_lastMaterialID != cmd->getMaterialID()) +// { +// //Set new material +// _lastMaterialID = cmd->getMaterialID(); +// +// //Set Shader +// cmd->useMaterial(); +// } +// +// batchQuads(cmd); +// +// break; +// } +// case CUSTOM_COMMAND: +// { +// flush(); +// CustomCommand* cmd = static_cast(command); +// cmd->execute(); +// +// break; +// } +// default: +// break; +// } +// +// delete command; +// } +// +// drawQuads(); +// +// _renderQueue.clear(); +} + +void Renderer::drawBatchedQuads() +{ + int quadsToDraw = 0; + int startQuad = 0; + + //Upload buffer to VBO + if(_numQuads <= 0) + return; + + //Set VBO data + glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]); + + glBufferData(GL_ARRAY_BUFFER, sizeof(_quads[0]) * (_numQuads), NULL, GL_DYNAMIC_DRAW); + void *buf = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); + memcpy(buf, _quads, sizeof(_quads[0])* (_numQuads)); + glUnmapBuffer(GL_ARRAY_BUFFER); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + + //Bind VAO + GL::bindVAO(_VAOname); + + for(size_t i = _firstCommand; i <= _lastCommand; i++) + { + RenderCommand* command = _renderQueue[i]; + if (command->getType() == QUAD_COMMAND) + { + QuadCommand* cmd = static_cast(command); + if(_lastMaterialID != cmd->getMaterialID()) + { + //Draw quads + if(quadsToDraw > 0) + { + glDrawElements(GL_TRIANGLES, (GLsizei) quadsToDraw*6, GL_UNSIGNED_SHORT, (GLvoid*) (startQuad*6*sizeof(_indices[0])) ); + startQuad += quadsToDraw; + quadsToDraw = 0; + } + + //Use new material + cmd->useMaterial(); + _lastMaterialID = cmd->getMaterialID(); + } + + quadsToDraw += cmd->getQuadCount(); + } + } + + _firstCommand = _lastCommand; + _numQuads = 0; } void Renderer::drawQuads() diff --git a/cocos/2d/renderer/Renderer.h b/cocos/2d/renderer/Renderer.h index 53f0f0ae2f..d8c85e6836 100644 --- a/cocos/2d/renderer/Renderer.h +++ b/cocos/2d/renderer/Renderer.h @@ -47,12 +47,17 @@ protected: vector _renderQueue; int _lastMaterialID; - V3F_C4B_T2F_Quad*_quads; - GLushort* _indices; + size_t _firstCommand; + size_t _lastCommand; + + V3F_C4B_T2F_Quad _quads[VBO_SIZE]; + GLushort _indices[6 * VBO_SIZE]; GLuint _VAOname; GLuint _buffersVBO[2]; //0: vertex 1: indices int _numQuads; + + void drawBatchedQuads(); }; NS_CC_END