improvement for fast tmx rendering

This commit is contained in:
Huabing.Xu 2014-06-27 11:50:44 +08:00
parent a04b5fc5d5
commit 6292ed05be
2 changed files with 75 additions and 43 deletions

View File

@ -141,16 +141,11 @@ FastTMXLayer::~FastTMXLayer()
} }
} }
bool sortQuadCommand(const V3F_C4B_T2F_Quad& a, const V3F_C4B_T2F_Quad& b)
{
return a.bl.vertices.z < b.bl.vertices.z;
}
void FastTMXLayer::draw(Renderer *renderer, const Mat4& transform, uint32_t flags) void FastTMXLayer::draw(Renderer *renderer, const Mat4& transform, uint32_t flags)
{ {
updateTotalQuads(); updateTotalQuads();
if( flags != 0 || _dirty ) if( flags != 0 || _dirty || _quadsDirty )
{ {
Size s = Director::getInstance()->getWinSize(); Size s = Director::getInstance()->getWinSize();
auto rect = Rect(0, 0, s.width, s.height); auto rect = Rect(0, 0, s.width, s.height);
@ -160,44 +155,47 @@ void FastTMXLayer::draw(Renderer *renderer, const Mat4& transform, uint32_t flag
rect = RectApplyTransform(rect, inv); rect = RectApplyTransform(rect, inv);
_verticesToDraw = updateTiles(rect); _verticesToDraw = updateTiles(rect);
updateIndexBuffer();
// don't draw more than 65535 vertices since we are using GL_UNSIGNED_SHORT for indices // don't draw more than 65535 vertices since we are using GL_UNSIGNED_SHORT for indices
_verticesToDraw = std::min(_verticesToDraw, 65535); _verticesToDraw = std::min(_verticesToDraw, 65535);
_dirty = false; _dirty = false;
} }
if(_renderCommands.size() < _quadsIndices.size()) if(_renderCommands.size() < _indicesVertexZNumber.size())
{ {
_renderCommands.resize(_quadsIndices.size()); _renderCommands.resize(_indicesVertexZNumber.size());
} }
int index = 0; int index = 0;
for(const auto& iter : _quadsIndices) for(const auto& iter : _indicesVertexZNumber)
{ {
auto& cmd = _renderCommands[index++]; auto& cmd = _renderCommands[index++];
cmd.init(iter.first); cmd.init(iter.first);
cmd.func = CC_CALLBACK_0(FastTMXLayer::onDraw, this, &iter.second); cmd.func = CC_CALLBACK_0(FastTMXLayer::onDraw, this, _indicesVertexZOffsets[iter.first], iter.second);
renderer->addCommand(&cmd); renderer->addCommand(&cmd);
} }
} }
void FastTMXLayer::onDraw(const std::vector<int> *indices) void FastTMXLayer::onDraw(int offset, int count)
{ {
GL::bindTexture2D(_texture->getName()); GL::bindTexture2D(_texture->getName());
getGLProgramState()->apply(_modelViewTransform); getGLProgramState()->apply(_modelViewTransform);
glBindVertexArray(0); glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]); glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _buffersVBO[1]);
glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_POSITION); glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_POSITION);
glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_COLOR); glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_COLOR);
glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_TEX_COORD); glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_TEX_COORD);
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, sizeof(V3F_C4B_T2F), &_totalQuads[0]); glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, sizeof(V3F_C4B_T2F), (GLvoid*)0);
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(V3F_C4B_T2F), ((char*)&_totalQuads[0]) + offsetof(V3F_C4B_T2F, colors)); glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(V3F_C4B_T2F), (GLvoid*)offsetof(V3F_C4B_T2F, colors));
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, sizeof(V3F_C4B_T2F), ((char*)&_totalQuads[0]) + offsetof(V3F_C4B_T2F, texCoords)); glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, sizeof(V3F_C4B_T2F), (GLvoid*)offsetof(V3F_C4B_T2F, texCoords));
glDrawElements(GL_TRIANGLES, (GLsizei)indices->size(), GL_UNSIGNED_INT, &(*indices)[0]); glDrawElements(GL_TRIANGLES, (GLsizei)count * 6, GL_UNSIGNED_INT, (GLvoid*)(offset * 6));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
} }
int FastTMXLayer::updateTiles(const Rect& culledRect) int FastTMXLayer::updateTiles(const Rect& culledRect)
@ -243,9 +241,12 @@ int FastTMXLayer::updateTiles(const Rect& culledRect)
tilesOverY = ceil(overTileRect.origin.y + overTileRect.size.height) - floor(overTileRect.origin.y); tilesOverY = ceil(overTileRect.origin.y + overTileRect.size.height) - floor(overTileRect.origin.y);
} }
_quadsIndices.clear(); _indicesVertexZNumber.clear();
//clear quadsNumber for(const auto& iter : _indicesVertexZOffsets)
{
_indicesVertexZNumber[iter.first] = iter.second;
}
int tilesUsed = 0; int tilesUsed = 0;
for (int y = visibleTiles.origin.y - tilesOverY; y < visibleTiles.origin.y + visibleTiles.size.height + tilesOverY; ++y) for (int y = visibleTiles.origin.y - tilesOverY; y < visibleTiles.origin.y + visibleTiles.size.height + tilesOverY; ++y)
@ -261,20 +262,19 @@ int FastTMXLayer::updateTiles(const Rect& culledRect)
if(_tiles[tileIndex] == 0) continue; if(_tiles[tileIndex] == 0) continue;
int vertexZ = getVertexZForPos(Vec2(x,y)); int vertexZ = getVertexZForPos(Vec2(x,y));
auto& indices = _quadsIndices[vertexZ]; auto iter = _indicesVertexZNumber.find(vertexZ);
if(indices.capacity() == indices.size()) int offset = iter->second;
{ iter->second++;
indices.reserve(indices.size() + 4096 * 6);
}
CC_ASSERT(_tileToQuadIndex.find(tileIndex) != _tileToQuadIndex.end() && _tileToQuadIndex[tileIndex] <= _totalQuads.size()-1); //CC_ASSERT(_tileToQuadIndex.find(tileIndex) != _tileToQuadIndex.end() && _tileToQuadIndex[tileIndex] <= _totalQuads.size()-1);
int quadIndex = (int)_tileToQuadIndex[tileIndex]; int quadIndex = (int)_tileToQuadIndex[tileIndex];
indices.push_back(quadIndex * 4);
indices.push_back(quadIndex * 4 + 1); _indices[6 * offset + 0] = quadIndex * 4 + 0;
indices.push_back(quadIndex * 4 + 2); _indices[6 * offset + 1] = quadIndex * 4 + 1;
indices.push_back(quadIndex * 4 + 3); _indices[6 * offset + 2] = quadIndex * 4 + 2;
indices.push_back(quadIndex * 4 + 2); _indices[6 * offset + 3] = quadIndex * 4 + 3;
indices.push_back(quadIndex * 4 + 1); _indices[6 * offset + 4] = quadIndex * 4 + 2;
_indices[6 * offset + 5] = quadIndex * 4 + 1;
if (tilesUsed >= MAX_QUADS_COUNT) if (tilesUsed >= MAX_QUADS_COUNT)
{ {
@ -287,7 +287,16 @@ int FastTMXLayer::updateTiles(const Rect& culledRect)
break; break;
} }
} // for y } // for y
for(const auto& iter : _indicesVertexZOffsets)
{
_indicesVertexZNumber[iter.first] -= iter.second;
if(_indicesVertexZNumber[iter.first] == 0)
{
_indicesVertexZNumber.erase(iter.first);
}
}
return tilesUsed * 6; return tilesUsed * 6;
} }
@ -300,13 +309,20 @@ void FastTMXLayer::updateVertexBuffer()
} }
glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]); glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(V3F_C4B_T2F_Quad) * _quads.size(), (GLvoid*)&_quads[0], GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(V3F_C4B_T2F_Quad) * _totalQuads.size(), (GLvoid*)&_totalQuads[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
} }
//void FastTMXLayer::updateIndexBuffer() void FastTMXLayer::updateIndexBuffer()
//{ {
//} if(!glIsBuffer(_buffersVBO[1]))
{
glGenBuffers(1, &_buffersVBO[1]);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _buffersVBO[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * _indices.size(), &_indices[0], GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
//void FastTMXLayer::setupVBO() //void FastTMXLayer::setupVBO()
//{ //{
@ -421,6 +437,8 @@ void FastTMXLayer::updateTotalQuads()
Size texSize = _tileSet->_imageSize; Size texSize = _tileSet->_imageSize;
_tileToQuadIndex.clear(); _tileToQuadIndex.clear();
_totalQuads.resize(int(_layerSize.width * _layerSize.height)); _totalQuads.resize(int(_layerSize.width * _layerSize.height));
_indices.resize(6 * int(_layerSize.width * _layerSize.height));
_indicesVertexZOffsets.clear();
int quadIndex = 0; int quadIndex = 0;
for(int y = 0; y < _layerSize.height; ++y) for(int y = 0; y < _layerSize.height; ++y)
@ -442,7 +460,15 @@ void FastTMXLayer::updateTotalQuads()
float left, right, top, bottom, z; float left, right, top, bottom, z;
z = getVertexZForPos(Vec2(x, y)); z = getVertexZForPos(Vec2(x, y));
auto iter = _indicesVertexZOffsets.find(z);
if(iter == _indicesVertexZOffsets.end())
{
_indicesVertexZOffsets[z] = 1;
}
else
{
iter->second++;
}
// vertices // vertices
if (tileGID & kTMXTileDiagonalFlag) if (tileGID & kTMXTileDiagonalFlag)
{ {
@ -521,6 +547,12 @@ void FastTMXLayer::updateTotalQuads()
} }
} }
int offset = 0;
for(auto iter = _indicesVertexZOffsets.begin(); iter != _indicesVertexZOffsets.end(); ++iter)
{
std::swap(offset, iter->second);
offset += iter->second;
}
updateVertexBuffer(); updateVertexBuffer();
_quadsDirty = false; _quadsDirty = false;

View File

@ -205,12 +205,12 @@ protected:
// //
void updateTotalQuads(); void updateTotalQuads();
void onDraw(const std::vector<int>* indices); void onDraw(int offset, int count);
inline int getTileIndexByPos(int x, int y) const { return x + y * (int) _layerSize.width; } inline int getTileIndexByPos(int x, int y) const { return x + y * (int) _layerSize.width; }
void updateVertexBuffer(); void updateVertexBuffer();
//void updateIndexBuffer(); void updateIndexBuffer();
protected: protected:
//! name of the layer //! name of the layer
@ -248,11 +248,11 @@ protected:
Mat4 _tileToNodeTransform; Mat4 _tileToNodeTransform;
/** quads to be rendered */ /** quads to be rendered */
bool _quadsDirty; bool _quadsDirty;
std::map<ssize_t, ssize_t> _tileToQuadIndex; std::unordered_map<ssize_t, ssize_t> _tileToQuadIndex;
std::vector<V3F_C4B_T2F_Quad> _totalQuads; std::vector<V3F_C4B_T2F_Quad> _totalQuads;
std::map<int/*zorder*/, std::vector<int>> _quadsIndices; std::vector<int> _indices;
std::vector<V3F_C4B_T2F_Quad> _quads; std::map<int/*vertexZ*/, int/*offset to _indices by quads*/> _indicesVertexZOffsets;
std::map<int/*zorder*/, ssize_t/*number*/> _quadsNumber; std::unordered_map<int/*vertexZ*/, int/*number to quads*/> _indicesVertexZNumber;
std::vector<CustomCommand> _renderCommands; std::vector<CustomCommand> _renderCommands;
bool _dirty; bool _dirty;
}; };