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
|
|
|
|
2013-12-18 10:41:09 +08:00
|
|
|
#include "CCRenderer.h"
|
2013-11-05 01:14:22 +08:00
|
|
|
#include "CCShaderCache.h"
|
|
|
|
#include "ccGLStateCache.h"
|
2013-12-18 10:41:09 +08:00
|
|
|
#include "CCCustomCommand.h"
|
2013-12-26 16:36:03 +08:00
|
|
|
#include "renderer/CCQuadCommand.h"
|
2013-12-18 10:41:09 +08:00
|
|
|
#include "CCGroupCommand.h"
|
2013-12-05 09:02:02 +08:00
|
|
|
#include "CCConfiguration.h"
|
2013-12-31 10:54:37 +08:00
|
|
|
#include "CCDirector.h"
|
|
|
|
#include "CCEventDispatcher.h"
|
|
|
|
#include "CCEventListenerCustom.h"
|
2013-12-17 14:18:41 +08:00
|
|
|
#include "CCEventType.h"
|
|
|
|
#include <algorithm> // for std::stable_sort
|
2013-11-05 01:14:22 +08:00
|
|
|
|
|
|
|
NS_CC_BEGIN
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
|
2013-12-18 09:50:17 +08:00
|
|
|
#define DEFAULT_RENDER_QUEUE 0
|
2013-11-05 01:14:22 +08:00
|
|
|
|
|
|
|
Renderer::Renderer()
|
2013-11-08 02:09:53 +08:00
|
|
|
:_lastMaterialID(0)
|
2013-11-11 16:14:29 +08:00
|
|
|
,_firstCommand(0)
|
|
|
|
,_lastCommand(0)
|
2013-12-27 15:06:16 +08:00
|
|
|
,_numQuads(0)
|
2013-11-22 08:36:19 +08:00
|
|
|
,_glViewAssigned(false)
|
2013-12-31 11:02:01 +08:00
|
|
|
#if CC_ENABLE_CACHE_TEXTURE_DATA
|
2013-12-31 10:54:37 +08:00
|
|
|
,_cacheTextureListener(nullptr)
|
2013-12-31 11:02:01 +08:00
|
|
|
#endif
|
2013-11-08 07:48:37 +08:00
|
|
|
{
|
2013-11-21 03:05:01 +08:00
|
|
|
_commandGroupStack.push(DEFAULT_RENDER_QUEUE);
|
|
|
|
|
2013-11-14 09:31:12 +08:00
|
|
|
RenderQueue defaultRenderQueue;
|
|
|
|
_renderGroups.push_back(defaultRenderQueue);
|
2013-12-18 14:36:49 +08:00
|
|
|
RenderStackElement elelment = {DEFAULT_RENDER_QUEUE, 0};
|
|
|
|
_renderStack.push(elelment);
|
2013-11-08 07:48:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Renderer::~Renderer()
|
2013-11-05 01:14:22 +08:00
|
|
|
{
|
2013-11-14 09:31:12 +08:00
|
|
|
_renderGroups.clear();
|
2013-11-22 08:36:19 +08:00
|
|
|
|
|
|
|
glDeleteBuffers(2, _buffersVBO);
|
|
|
|
|
2013-12-05 09:02:02 +08:00
|
|
|
if (Configuration::getInstance()->supportsShareableVAO())
|
|
|
|
{
|
2013-11-23 02:24:52 +08:00
|
|
|
glDeleteVertexArrays(1, &_quadVAO);
|
2013-11-22 08:36:19 +08:00
|
|
|
GL::bindVAO(0);
|
2013-12-05 09:02:02 +08:00
|
|
|
}
|
2013-12-27 11:56:56 +08:00
|
|
|
#if CC_ENABLE_CACHE_TEXTURE_DATA
|
2013-12-31 10:54:37 +08:00
|
|
|
Director::getInstance()->getEventDispatcher()->removeEventListener(_cacheTextureListener);
|
2013-12-27 11:56:56 +08:00
|
|
|
#endif
|
2013-11-08 08:50:53 +08:00
|
|
|
}
|
|
|
|
|
2013-11-22 08:36:19 +08:00
|
|
|
void Renderer::initGLView()
|
|
|
|
{
|
2013-12-27 11:56:56 +08:00
|
|
|
#if CC_ENABLE_CACHE_TEXTURE_DATA
|
2013-12-31 10:54:37 +08:00
|
|
|
_cacheTextureListener = EventListenerCustom::create(EVENT_COME_TO_FOREGROUND, [this](EventCustom* event){
|
|
|
|
/** listen the event that coming to foreground on Android */
|
|
|
|
this->setupBuffer();
|
|
|
|
});
|
|
|
|
|
|
|
|
Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(_cacheTextureListener, -1);
|
2013-12-05 09:02:02 +08:00
|
|
|
#endif
|
|
|
|
|
2013-11-22 08:36:19 +08:00
|
|
|
setupIndices();
|
|
|
|
|
2013-12-05 09:02:02 +08:00
|
|
|
setupBuffer();
|
2013-11-22 08:36:19 +08:00
|
|
|
|
|
|
|
_glViewAssigned = true;
|
2013-11-08 08:50:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer::setupIndices()
|
|
|
|
{
|
2013-12-19 05:52:10 +08:00
|
|
|
for( int i=0; i < VBO_SIZE; i++)
|
2013-11-08 08:50:53 +08:00
|
|
|
{
|
|
|
|
_indices[i*6+0] = (GLushort) (i*4+0);
|
|
|
|
_indices[i*6+1] = (GLushort) (i*4+1);
|
|
|
|
_indices[i*6+2] = (GLushort) (i*4+2);
|
|
|
|
_indices[i*6+3] = (GLushort) (i*4+3);
|
|
|
|
_indices[i*6+4] = (GLushort) (i*4+2);
|
|
|
|
_indices[i*6+5] = (GLushort) (i*4+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-05 09:02:02 +08:00
|
|
|
void Renderer::setupBuffer()
|
|
|
|
{
|
|
|
|
if(Configuration::getInstance()->supportsShareableVAO())
|
|
|
|
{
|
|
|
|
setupVBOAndVAO();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setupVBO();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-08 08:50:53 +08:00
|
|
|
void Renderer::setupVBOAndVAO()
|
|
|
|
{
|
2013-11-23 02:24:52 +08:00
|
|
|
glGenVertexArrays(1, &_quadVAO);
|
|
|
|
GL::bindVAO(_quadVAO);
|
2013-11-08 08:50:53 +08:00
|
|
|
|
|
|
|
glGenBuffers(2, &_buffersVBO[0]);
|
|
|
|
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]);
|
2013-12-19 05:52:10 +08:00
|
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(_quads[0]) * VBO_SIZE, _quads, GL_DYNAMIC_DRAW);
|
2013-11-08 08:50:53 +08:00
|
|
|
|
|
|
|
// vertices
|
|
|
|
glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_POSITION);
|
|
|
|
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, sizeof(V3F_C4B_T2F), (GLvoid*) offsetof( V3F_C4B_T2F, vertices));
|
|
|
|
|
|
|
|
// colors
|
|
|
|
glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_COLOR);
|
|
|
|
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(V3F_C4B_T2F), (GLvoid*) offsetof( V3F_C4B_T2F, colors));
|
|
|
|
|
|
|
|
// tex coords
|
|
|
|
glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_TEX_COORDS);
|
|
|
|
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORDS, 2, GL_FLOAT, GL_FALSE, sizeof(V3F_C4B_T2F), (GLvoid*) offsetof( V3F_C4B_T2F, texCoords));
|
|
|
|
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _buffersVBO[1]);
|
2013-12-19 05:52:10 +08:00
|
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(_indices[0]) * VBO_SIZE * 6, _indices, GL_STATIC_DRAW);
|
2013-11-08 08:50:53 +08:00
|
|
|
|
|
|
|
// Must unbind the VAO before changing the element buffer.
|
|
|
|
GL::bindVAO(0);
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
|
|
|
|
|
CHECK_GL_ERROR_DEBUG();
|
2013-11-05 01:14:22 +08:00
|
|
|
}
|
|
|
|
|
2013-12-05 09:02:02 +08:00
|
|
|
void Renderer::setupVBO()
|
|
|
|
{
|
|
|
|
glGenBuffers(2, &_buffersVBO[0]);
|
|
|
|
|
|
|
|
mapBuffers();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer::mapBuffers()
|
|
|
|
{
|
|
|
|
// Avoid changing the element buffer for whatever VAO might be bound.
|
|
|
|
GL::bindVAO(0);
|
|
|
|
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]);
|
2013-12-19 05:52:10 +08:00
|
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(_quads[0]) * VBO_SIZE, _quads, GL_DYNAMIC_DRAW);
|
2013-12-05 09:02:02 +08:00
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
|
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _buffersVBO[1]);
|
2013-12-19 05:52:10 +08:00
|
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(_indices[0]) * VBO_SIZE * 6, _indices, GL_STATIC_DRAW);
|
2013-12-05 09:02:02 +08:00
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
|
|
|
|
|
|
CHECK_GL_ERROR_DEBUG();
|
|
|
|
}
|
|
|
|
|
2013-11-16 09:32:29 +08:00
|
|
|
void Renderer::addCommand(RenderCommand* command)
|
|
|
|
{
|
|
|
|
command->generateID();
|
2013-11-21 03:05:01 +08:00
|
|
|
_renderGroups[_commandGroupStack.top()].push_back(command);
|
2013-11-16 09:32:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer::addCommand(RenderCommand* command, int renderQueue)
|
2013-11-05 01:14:22 +08:00
|
|
|
{
|
2013-11-06 09:00:34 +08:00
|
|
|
command->generateID();
|
2013-11-14 09:31:12 +08:00
|
|
|
_renderGroups[renderQueue].push_back(command);
|
2013-11-05 01:14:22 +08:00
|
|
|
}
|
|
|
|
|
2013-11-21 03:05:01 +08:00
|
|
|
void Renderer::pushGroup(int renderQueueID)
|
|
|
|
{
|
|
|
|
_commandGroupStack.push(renderQueueID);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer::popGroup()
|
|
|
|
{
|
|
|
|
_commandGroupStack.pop();
|
|
|
|
}
|
|
|
|
|
2013-11-16 03:29:11 +08:00
|
|
|
int Renderer::createRenderQueue()
|
|
|
|
{
|
|
|
|
RenderQueue newRenderQueue;
|
|
|
|
_renderGroups.push_back(newRenderQueue);
|
2013-11-21 03:05:01 +08:00
|
|
|
return (int)_renderGroups.size() - 1;
|
2013-11-16 03:29:11 +08:00
|
|
|
}
|
|
|
|
|
2013-11-06 09:00:34 +08:00
|
|
|
bool compareRenderCommand(RenderCommand* a, RenderCommand* b)
|
|
|
|
{
|
|
|
|
return a->getID() < b->getID();
|
|
|
|
}
|
|
|
|
|
2013-11-05 01:14:22 +08:00
|
|
|
void Renderer::render()
|
|
|
|
{
|
2013-11-07 06:57:42 +08:00
|
|
|
//Uncomment this once everything is rendered by new renderer
|
2013-11-05 01:14:22 +08:00
|
|
|
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
|
2013-11-07 08:39:20 +08:00
|
|
|
//TODO setup camera or MVP
|
|
|
|
|
2013-11-22 08:36:19 +08:00
|
|
|
if (_glViewAssigned)
|
2013-11-14 09:31:12 +08:00
|
|
|
{
|
2013-11-22 08:36:19 +08:00
|
|
|
//Process render commands
|
|
|
|
//1. Sort render commands based on ID
|
|
|
|
for (auto it = _renderGroups.begin(); it != _renderGroups.end(); ++it)
|
2013-11-14 09:31:12 +08:00
|
|
|
{
|
2013-12-17 14:18:41 +08:00
|
|
|
std::stable_sort((*it).begin(), (*it).end(), compareRenderCommand);
|
2013-11-22 08:36:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
while(!_renderStack.empty())
|
|
|
|
{
|
|
|
|
RenderQueue currRenderQueue = _renderGroups[_renderStack.top().renderQueueID];
|
|
|
|
size_t len = currRenderQueue.size();
|
|
|
|
|
|
|
|
//Refresh the batch command index in case the renderStack has changed.
|
|
|
|
_firstCommand = _lastCommand = _renderStack.top().currentIndex;
|
|
|
|
|
|
|
|
//Process RenderQueue
|
|
|
|
for(size_t i = _renderStack.top().currentIndex; i < len; i++)
|
2013-11-14 09:31:12 +08:00
|
|
|
{
|
2013-11-22 08:36:19 +08:00
|
|
|
_renderStack.top().currentIndex = _lastCommand = i;
|
|
|
|
auto command = currRenderQueue[i];
|
2013-12-18 10:12:15 +08:00
|
|
|
|
|
|
|
auto commandType = command->getType();
|
2013-11-22 08:36:19 +08:00
|
|
|
|
2013-12-18 10:12:15 +08:00
|
|
|
if(commandType == RenderCommand::Type::QUAD_COMMAND)
|
2013-11-14 09:31:12 +08:00
|
|
|
{
|
2013-11-22 08:36:19 +08:00
|
|
|
QuadCommand* cmd = static_cast<QuadCommand*>(command);
|
2013-12-18 10:12:15 +08:00
|
|
|
ssize_t cmdQuadCount = cmd->getQuadCount();
|
|
|
|
|
2013-11-22 08:36:19 +08:00
|
|
|
//Batch quads
|
2013-12-19 05:52:10 +08:00
|
|
|
if(_numQuads + cmdQuadCount > VBO_SIZE)
|
2013-11-22 08:36:19 +08:00
|
|
|
{
|
2013-12-19 05:52:10 +08:00
|
|
|
CCASSERT(cmdQuadCount < VBO_SIZE, "VBO is not big enough for quad data, please break the quad data down or use customized render command");
|
2013-12-05 11:05:17 +08:00
|
|
|
|
2013-11-22 08:36:19 +08:00
|
|
|
//Draw batched quads if VBO is full
|
|
|
|
drawBatchedQuads();
|
|
|
|
}
|
2013-12-06 06:25:45 +08:00
|
|
|
|
2013-12-18 10:12:15 +08:00
|
|
|
memcpy(_quads + _numQuads, cmd->getQuad(), sizeof(V3F_C4B_T2F_Quad) * cmdQuadCount);
|
|
|
|
_numQuads += cmdQuadCount;
|
2013-11-22 08:36:19 +08:00
|
|
|
}
|
2013-12-18 10:12:15 +08:00
|
|
|
else if(commandType == RenderCommand::Type::CUSTOM_COMMAND)
|
2013-11-22 08:36:19 +08:00
|
|
|
{
|
|
|
|
flush();
|
|
|
|
CustomCommand* cmd = static_cast<CustomCommand*>(command);
|
|
|
|
cmd->execute();
|
|
|
|
}
|
2013-12-18 10:12:15 +08:00
|
|
|
else if(commandType == RenderCommand::Type::GROUP_COMMAND)
|
2013-11-22 08:36:19 +08:00
|
|
|
{
|
|
|
|
flush();
|
|
|
|
GroupCommand* cmd = static_cast<GroupCommand*>(command);
|
|
|
|
|
|
|
|
_renderStack.top().currentIndex = i + 1;
|
|
|
|
|
|
|
|
//push new renderQueue to renderStack
|
2013-12-18 14:36:49 +08:00
|
|
|
RenderStackElement element = {cmd->getRenderQueueID(), 0};
|
|
|
|
_renderStack.push(element);
|
2013-11-22 08:36:19 +08:00
|
|
|
|
|
|
|
//Exit current loop
|
|
|
|
break;
|
2013-11-14 09:31:12 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-11-22 08:36:19 +08:00
|
|
|
flush();
|
2013-11-14 09:31:12 +08:00
|
|
|
}
|
|
|
|
}
|
2013-11-22 08:36:19 +08:00
|
|
|
|
|
|
|
//Draw the batched quads
|
|
|
|
drawBatchedQuads();
|
|
|
|
|
|
|
|
currRenderQueue = _renderGroups[_renderStack.top().renderQueueID];
|
|
|
|
len = currRenderQueue.size();
|
|
|
|
//If pop the render stack if we already processed all the commands
|
|
|
|
if(_renderStack.top().currentIndex + 1 >= len)
|
2013-11-14 09:31:12 +08:00
|
|
|
{
|
2013-11-22 08:36:19 +08:00
|
|
|
_renderStack.pop();
|
2013-11-14 09:31:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-11-05 01:14:22 +08:00
|
|
|
|
2013-11-15 02:35:28 +08:00
|
|
|
for (size_t j = 0 ; j < _renderGroups.size(); j++)
|
2013-11-05 01:14:22 +08:00
|
|
|
{
|
2013-12-27 14:02:17 +08:00
|
|
|
//commands are owned by nodes
|
|
|
|
// for (const auto &cmd : _renderGroups[j])
|
|
|
|
// {
|
|
|
|
// cmd->releaseToCommandPool();
|
|
|
|
// }
|
2013-11-15 02:35:28 +08:00
|
|
|
_renderGroups[j].clear();
|
2013-11-11 16:14:29 +08:00
|
|
|
}
|
2013-11-22 08:36:19 +08:00
|
|
|
|
|
|
|
//Clear the stack incase gl view hasn't been initialized yet
|
|
|
|
while(!_renderStack.empty())
|
|
|
|
{
|
|
|
|
_renderStack.pop();
|
|
|
|
}
|
2013-12-18 14:36:49 +08:00
|
|
|
RenderStackElement element = {DEFAULT_RENDER_QUEUE, 0};
|
|
|
|
_renderStack.push(element);
|
2013-11-11 16:14:29 +08:00
|
|
|
_firstCommand = _lastCommand = 0;
|
|
|
|
_lastMaterialID = 0;
|
|
|
|
}
|
2013-11-09 04:06:39 +08:00
|
|
|
|
2013-11-11 16:14:29 +08:00
|
|
|
void Renderer::drawBatchedQuads()
|
|
|
|
{
|
2013-11-19 07:52:47 +08:00
|
|
|
//TODO we can improve the draw performance by insert material switching command before hand.
|
2013-11-14 02:26:26 +08:00
|
|
|
|
2013-11-11 16:14:29 +08:00
|
|
|
int quadsToDraw = 0;
|
|
|
|
int startQuad = 0;
|
2013-11-05 01:14:22 +08:00
|
|
|
|
2013-11-11 16:14:29 +08:00
|
|
|
//Upload buffer to VBO
|
|
|
|
if(_numQuads <= 0)
|
2013-11-19 07:52:47 +08:00
|
|
|
{
|
|
|
|
_firstCommand = _lastCommand;
|
2013-11-11 16:14:29 +08:00
|
|
|
return;
|
2013-11-19 07:52:47 +08:00
|
|
|
}
|
2013-11-11 16:14:29 +08:00
|
|
|
|
2013-12-05 09:02:02 +08:00
|
|
|
if (Configuration::getInstance()->supportsShareableVAO())
|
|
|
|
{
|
|
|
|
//Set VBO data
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]);
|
2013-11-11 16:14:29 +08:00
|
|
|
|
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]);
|
|
|
|
|
|
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(_quads[0]) * _numQuads , _quads);
|
|
|
|
|
|
|
|
GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POS_COLOR_TEX);
|
|
|
|
|
|
|
|
// vertices
|
|
|
|
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof(V3F_C4B_T2F, vertices));
|
|
|
|
|
|
|
|
// colors
|
|
|
|
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (GLvoid*) offsetof(V3F_C4B_T2F, colors));
|
|
|
|
|
|
|
|
// tex coords
|
|
|
|
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORDS, 2, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof(V3F_C4B_T2F, texCoords));
|
|
|
|
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _buffersVBO[1]);
|
|
|
|
}
|
2013-11-11 16:14:29 +08:00
|
|
|
|
2013-11-12 03:54:08 +08:00
|
|
|
//Start drawing verties in batch
|
2013-11-11 16:14:29 +08:00
|
|
|
for(size_t i = _firstCommand; i <= _lastCommand; i++)
|
|
|
|
{
|
2013-11-15 04:17:54 +08:00
|
|
|
RenderCommand* command = _renderGroups[_renderStack.top().renderQueueID][i];
|
2013-12-18 10:02:11 +08:00
|
|
|
if (command->getType() == RenderCommand::Type::QUAD_COMMAND)
|
2013-11-11 16:14:29 +08:00
|
|
|
{
|
|
|
|
QuadCommand* cmd = static_cast<QuadCommand*>(command);
|
|
|
|
if(_lastMaterialID != cmd->getMaterialID())
|
2013-11-09 04:06:39 +08:00
|
|
|
{
|
2013-11-11 16:14:29 +08:00
|
|
|
//Draw quads
|
|
|
|
if(quadsToDraw > 0)
|
|
|
|
{
|
|
|
|
glDrawElements(GL_TRIANGLES, (GLsizei) quadsToDraw*6, GL_UNSIGNED_SHORT, (GLvoid*) (startQuad*6*sizeof(_indices[0])) );
|
2013-11-23 09:14:24 +08:00
|
|
|
CC_INCREMENT_GL_DRAWS(1);
|
2013-11-22 08:36:19 +08:00
|
|
|
|
2013-11-11 16:14:29 +08:00
|
|
|
startQuad += quadsToDraw;
|
|
|
|
quadsToDraw = 0;
|
|
|
|
}
|
2013-11-09 04:06:39 +08:00
|
|
|
|
2013-11-11 16:14:29 +08:00
|
|
|
//Use new material
|
|
|
|
cmd->useMaterial();
|
|
|
|
_lastMaterialID = cmd->getMaterialID();
|
2013-11-09 04:06:39 +08:00
|
|
|
}
|
2013-11-05 01:14:22 +08:00
|
|
|
|
2013-11-11 16:14:29 +08:00
|
|
|
quadsToDraw += cmd->getQuadCount();
|
|
|
|
}
|
2013-11-05 01:14:22 +08:00
|
|
|
}
|
|
|
|
|
2013-11-12 03:54:08 +08:00
|
|
|
//Draw any remaining quad
|
|
|
|
if(quadsToDraw > 0)
|
|
|
|
{
|
|
|
|
glDrawElements(GL_TRIANGLES, (GLsizei) quadsToDraw*6, GL_UNSIGNED_SHORT, (GLvoid*) (startQuad*6*sizeof(_indices[0])) );
|
2013-11-23 09:14:24 +08:00
|
|
|
CC_INCREMENT_GL_DRAWS(1);
|
2013-11-12 03:54:08 +08:00
|
|
|
}
|
2013-11-08 07:48:37 +08:00
|
|
|
|
2013-12-05 09:02:02 +08:00
|
|
|
if (Configuration::getInstance()->supportsShareableVAO())
|
|
|
|
{
|
|
|
|
//Unbind VAO
|
|
|
|
GL::bindVAO(0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
|
|
}
|
|
|
|
|
2013-11-21 12:39:32 +08:00
|
|
|
|
2013-11-12 03:54:08 +08:00
|
|
|
_firstCommand = _lastCommand;
|
2013-11-08 07:48:37 +08:00
|
|
|
_numQuads = 0;
|
|
|
|
}
|
|
|
|
|
2013-11-09 04:06:39 +08:00
|
|
|
void Renderer::flush()
|
|
|
|
{
|
2013-11-12 03:54:08 +08:00
|
|
|
drawBatchedQuads();
|
2013-11-09 04:06:39 +08:00
|
|
|
_lastMaterialID = 0;
|
|
|
|
}
|
|
|
|
|
2013-11-05 01:14:22 +08:00
|
|
|
NS_CC_END
|