use custom command for rendering

This commit is contained in:
Huabing.Xu 2014-06-26 20:45:08 +08:00
parent 87e5e1460e
commit 81aa9c2c74
2 changed files with 195 additions and 134 deletions

View File

@ -79,6 +79,7 @@ bool FastTMXLayer::initWithTilesetInfo(TMXTilesetInfo *tilesetInfo, TMXLayerInfo
_layerName = layerInfo->_name;
_layerSize = layerInfo->_layerSize;
_tiles = layerInfo->_tiles;
_quadsDirty = true;
setOpacity( layerInfo->_opacity );
setProperties(layerInfo->getProperties());
@ -119,6 +120,7 @@ FastTMXLayer::FastTMXLayer()
,_vertexZvalue(0)
,_useAutomaticVertexZ(false)
,_dirty(true)
, _quadsDirty(true)
{
}
@ -136,6 +138,8 @@ bool sortQuadCommand(const V3F_C4B_T2F_Quad& a, const V3F_C4B_T2F_Quad& b)
void FastTMXLayer::draw(Renderer *renderer, const Mat4& transform, uint32_t flags)
{
updateTotalQuads();
if( flags != 0 || _dirty )
{
Size s = Director::getInstance()->getWinSize();
@ -146,28 +150,50 @@ void FastTMXLayer::draw(Renderer *renderer, const Mat4& transform, uint32_t flag
rect = RectApplyTransform(rect, inv);
_verticesToDraw = updateTiles(rect);
std::stable_sort(_quads.begin(), _quads.end(), sortQuadCommand);
// don't draw more than 65535 vertices since we are using GL_UNSIGNED_SHORT for indices
_verticesToDraw = std::min(_verticesToDraw, 65535);
_dirty = false;
}
auto glprogramState = GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR);
int index = 0;
for(const auto& quadNumberIter : _quadsNumber)
if(_renderCommands.size() < _quadsIndices.size())
{
int z = quadNumberIter.first;
auto& quadCommand = _renderCommands2[quadNumberIter.first];
quadCommand.init(z, _texture->getName(), glprogramState, BlendFunc::ALPHA_PREMULTIPLIED, &_quads[index], quadNumberIter.second, transform);
index += quadNumberIter.second;
renderer->addCommand(&quadCommand);
_renderCommands.resize(_quadsIndices.size());
}
int index = 0;
for(const auto& iter : _quadsIndices)
{
auto& cmd = _renderCommands[index++];
cmd.init(iter.first);
printf("in draw function of FastTMXLayer %d\n", iter.second.size());
cmd.func = CC_CALLBACK_0(FastTMXLayer::onDraw, this, &iter.second);
renderer->addCommand(&cmd);
}
}
void FastTMXLayer::onDraw(const std::vector<int> *indices)
{
GL::bindTexture2D(_texture->getName());
getGLProgramState()->apply(_modelViewTransform);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_POSITION);
glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_COLOR);
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_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(V3F_C4B_T2F), ((char*)&_totalQuads[0]) + 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));
printf("in onDraw function of FastTMXLayer %d\n", indices->size());
glDrawElements(GL_TRIANGLES, (GLsizei)indices->size(), GL_UNSIGNED_INT, &(*indices)[0]);
}
int FastTMXLayer::updateTiles(const Rect& culledRect)
{
int tilesUsed = 0;
Rect visibleTiles = culledRect;
Size mapTileSize = CC_SIZE_PIXELS_TO_POINTS(_mapTileSize);
@ -209,17 +235,11 @@ int FastTMXLayer::updateTiles(const Rect& culledRect)
tilesOverY = ceil(overTileRect.origin.y + overTileRect.size.height) - floor(overTileRect.origin.y);
}
// doesn't support VBO
int quadsNeed = std::min(static_cast<int>((visibleTiles.size.width + 2 *tilesOverX) * (visibleTiles.size.height + 2 * tilesOverY)), MAX_QUADS_COUNT);
if (_quads.size() < quadsNeed)
{
_quads.resize(quadsNeed);
}
_quadsIndices.clear();
//clear quadsNumber
_quadsNumber.clear();
Size texSize = _tileSet->_imageSize;
int tilesUsed = 0;
for (int y = visibleTiles.origin.y - tilesOverY; y < visibleTiles.origin.y + visibleTiles.size.height + tilesOverY; ++y)
{
if(y<0 || y >= _layerSize.height)
@ -228,110 +248,26 @@ int FastTMXLayer::updateTiles(const Rect& culledRect)
{
if(x<0 || x >= _layerSize.width)
continue;
int tileGID = _tiles[x + y * (int)_layerSize.width];
// GID==0 empty tile
if(tileGID!=0)
int tileIndex = getTileIndexByPos(x, y);
if(_tiles[tileIndex] == 0) continue;
int vertexZ = getVertexZForPos(Vec2(x,y));
auto& indices = _quadsIndices[vertexZ];
if(indices.capacity() == indices.size())
{
V3F_C4B_T2F_Quad *quad = &_quads[tilesUsed];
Vec3 nodePos(static_cast<float>(x), static_cast<float>(y), 0);
_tileToNodeTransform.transformPoint(&nodePos);
float left, right, top, bottom, z;
z = getVertexZForPos(Vec2(x, y));
//add quadsNumber
auto quadsNumberIter = _quadsNumber.find(z);
if(quadsNumberIter == _quadsNumber.end())
{
_quadsNumber.insert(std::make_pair(z, 1));
}
else
{
quadsNumberIter->second += 1;
}
// vertices
if (tileGID & kTMXTileDiagonalFlag)
{
left = nodePos.x;
right = nodePos.x + tileSize.height;
bottom = nodePos.y + tileSize.width;
top = nodePos.y;
}
else
{
left = nodePos.x;
right = nodePos.x + tileSize.width;
bottom = nodePos.y + tileSize.height;
top = nodePos.y;
}
if(tileGID & kTMXTileVerticalFlag)
std::swap(top, bottom);
if(tileGID & kTMXTileHorizontalFlag)
std::swap(left, right);
if(tileGID & kTMXTileDiagonalFlag)
{
// XXX: not working correcly
quad->bl.vertices.x = left;
quad->bl.vertices.y = bottom;
quad->bl.vertices.z = z;
quad->br.vertices.x = left;
quad->br.vertices.y = top;
quad->br.vertices.z = z;
quad->tl.vertices.x = right;
quad->tl.vertices.y = bottom;
quad->tl.vertices.z = z;
quad->tr.vertices.x = right;
quad->tr.vertices.y = top;
quad->tr.vertices.z = z;
}
else
{
quad->bl.vertices.x = left;
quad->bl.vertices.y = bottom;
quad->bl.vertices.z = z;
quad->br.vertices.x = right;
quad->br.vertices.y = bottom;
quad->br.vertices.z = z;
quad->tl.vertices.x = left;
quad->tl.vertices.y = top;
quad->tl.vertices.z = z;
quad->tr.vertices.x = right;
quad->tr.vertices.y = top;
quad->tr.vertices.z = z;
}
// texcoords
Rect tileTexture = _tileSet->getRectForGID(tileGID);
left = (tileTexture.origin.x / texSize.width);
right = left + (tileTexture.size.width / texSize.width);
bottom = (tileTexture.origin.y / texSize.height);
top = bottom + (tileTexture.size.height / texSize.height);
quad->bl.texCoords.u = left;
quad->bl.texCoords.v = bottom;
quad->br.texCoords.u = right;
quad->br.texCoords.v = bottom;
quad->tl.texCoords.u = left;
quad->tl.texCoords.v = top;
quad->tr.texCoords.u = right;
quad->tr.texCoords.v = top;
quad->bl.colors = Color4B::WHITE;
quad->br.colors = Color4B::WHITE;
quad->tl.colors = Color4B::WHITE;
quad->tr.colors = Color4B::WHITE;
tilesUsed++;
indices.reserve(indices.size() + 4096 * 6);
}
CC_ASSERT(_tileToQuadIndex.find(tileIndex) != _tileToQuadIndex.end() && _tileToQuadIndex[tileIndex] <= _totalQuads.size()-1);
int quadIndex = (int)_tileToQuadIndex[tileIndex];
indices.push_back(quadIndex * 4);
indices.push_back(quadIndex * 4 + 1);
indices.push_back(quadIndex * 4 + 2);
indices.push_back(quadIndex * 4 + 3);
indices.push_back(quadIndex * 4 + 2);
indices.push_back(quadIndex * 4 + 1);
if (tilesUsed >= MAX_QUADS_COUNT)
{
break;
@ -453,6 +389,120 @@ Mat4 FastTMXLayer::tileToNodeTransform()
}
void FastTMXLayer::updateTotalQuads()
{
if(_quadsDirty)
{
Size tileSize = CC_SIZE_PIXELS_TO_POINTS(_tileSet->_tileSize);
Size texSize = _tileSet->_imageSize;
_tileToQuadIndex.clear();
_totalQuads.resize(int(_layerSize.width * _layerSize.height));
int quadIndex = 0;
for(int y = 0; y < _layerSize.height; ++y)
{
for(int x =0; x < _layerSize.width; ++x)
{
int tileIndex = getTileIndexByPos(x, y);
int tileGID = _tiles[tileIndex];
if(tileGID == 0) continue;
_tileToQuadIndex[tileIndex] = quadIndex;
auto& quad = _totalQuads[quadIndex];
Vec3 nodePos(float(x), float(y), 0);
_tileToNodeTransform.transformPoint(&nodePos);
float left, right, top, bottom, z;
z = getVertexZForPos(Vec2(x, y));
// vertices
if (tileGID & kTMXTileDiagonalFlag)
{
left = nodePos.x;
right = nodePos.x + tileSize.height;
bottom = nodePos.y + tileSize.width;
top = nodePos.y;
}
else
{
left = nodePos.x;
right = nodePos.x + tileSize.width;
bottom = nodePos.y + tileSize.height;
top = nodePos.y;
}
if(tileGID & kTMXTileVerticalFlag)
std::swap(top, bottom);
if(tileGID & kTMXTileHorizontalFlag)
std::swap(left, right);
if(tileGID & kTMXTileDiagonalFlag)
{
// XXX: not working correcly
quad.bl.vertices.x = left;
quad.bl.vertices.y = bottom;
quad.bl.vertices.z = z;
quad.br.vertices.x = left;
quad.br.vertices.y = top;
quad.br.vertices.z = z;
quad.tl.vertices.x = right;
quad.tl.vertices.y = bottom;
quad.tl.vertices.z = z;
quad.tr.vertices.x = right;
quad.tr.vertices.y = top;
quad.tr.vertices.z = z;
}
else
{
quad.bl.vertices.x = left;
quad.bl.vertices.y = bottom;
quad.bl.vertices.z = z;
quad.br.vertices.x = right;
quad.br.vertices.y = bottom;
quad.br.vertices.z = z;
quad.tl.vertices.x = left;
quad.tl.vertices.y = top;
quad.tl.vertices.z = z;
quad.tr.vertices.x = right;
quad.tr.vertices.y = top;
quad.tr.vertices.z = z;
}
// texcoords
Rect tileTexture = _tileSet->getRectForGID(tileGID);
left = (tileTexture.origin.x / texSize.width);
right = left + (tileTexture.size.width / texSize.width);
bottom = (tileTexture.origin.y / texSize.height);
top = bottom + (tileTexture.size.height / texSize.height);
quad.bl.texCoords.u = left;
quad.bl.texCoords.v = bottom;
quad.br.texCoords.u = right;
quad.br.texCoords.v = bottom;
quad.tl.texCoords.u = left;
quad.tl.texCoords.v = top;
quad.tr.texCoords.u = right;
quad.tr.texCoords.v = top;
quad.bl.colors = Color4B::WHITE;
quad.br.colors = Color4B::WHITE;
quad.tl.colors = Color4B::WHITE;
quad.tr.colors = Color4B::WHITE;
++quadIndex;
}
}
//TODO: update VBOs
_quadsDirty = false;
}
}
// removing / getting tiles
Sprite* FastTMXLayer::getTileAt(const Vec2& tileCoordinate)
{
@ -488,7 +538,7 @@ Sprite* FastTMXLayer::getTileAt(const Vec2& tileCoordinate)
_spriteContainer.insert(std::pair<int, std::pair<Sprite*, int> >(index, std::pair<Sprite*, int>(tile, gid)));
// tile is converted to sprite.
setTileForGID(index, 0);
setFlaggedTileGIDByIndex(index, 0);
}
}
return tile;
@ -568,7 +618,7 @@ void FastTMXLayer::removeTileAt(const Vec2& tileCoordinate)
int z = tileCoordinate.x + tileCoordinate.y * _layerSize.width;
// remove tile from GID map
setTileForGID(z, 0);
setFlaggedTileGIDByIndex(z, 0);
// remove it from sprites
auto it = _spriteContainer.find(z);
@ -579,9 +629,11 @@ void FastTMXLayer::removeTileAt(const Vec2& tileCoordinate)
}
}
void FastTMXLayer::setTileForGID(int index, int gid)
void FastTMXLayer::setFlaggedTileGIDByIndex(int index, int gid)
{
if(gid == _tiles[index]) return;
_tiles[index] = gid;
_quadsDirty = true;
_dirty = true;
}
@ -682,7 +734,7 @@ void FastTMXLayer::setTileGID(int gid, const Vec2& tileCoordinate, TMXTileFlags
else if (currentGID == 0)
{
int z = tileCoordinate.x + tileCoordinate.y * _layerSize.width;
setTileForGID(z, gidAndFlags);
setFlaggedTileGIDByIndex(z, gidAndFlags);
}
// modifying an existing tile with a non-empty tile
else
@ -706,7 +758,7 @@ void FastTMXLayer::setTileGID(int gid, const Vec2& tileCoordinate, TMXTileFlags
}
else
{
setTileForGID(z, gidAndFlags);
setFlaggedTileGIDByIndex(z, gidAndFlags);
}
}
}

View File

@ -145,8 +145,8 @@ public:
* @js NA
* @lua NA
*/
uint32_t* getTiles() const { return _tiles; };
void setTiles(uint32_t* tiles) { _tiles = tiles; };
const uint32_t* getTiles() const { return _tiles; };
void setTiles(uint32_t* tiles) { _tiles = tiles; _quadsDirty = true;};
/** Tileset information for the layer */
inline TMXTilesetInfo* getTileSet() const { return _tileSet; };
@ -163,7 +163,8 @@ public:
/** properties from the layer. They can be added using Tiled */
inline const ValueMap& getProperties() const { return _properties; };
inline ValueMap& getProperties() { return _properties; };
inline void setProperties(const ValueMap& properties) {
inline void setProperties(const ValueMap& properties)
{
_properties = properties;
};
@ -174,8 +175,6 @@ public:
- layer->removeChild(sprite, cleanup);
*/
Sprite* getTileAt(const Vec2& tileCoordinate);
Sprite* updateTileForGID(int gid, const Vec2& pos);
void setupTileSprite(Sprite* sprite, Vec2 pos, int gid);
@ -201,9 +200,15 @@ protected:
int getVertexZForPos(const Vec2& pos);
void insertTileForGID(int gid, const Vec2& pos);
void setTileForGID(int index, int gid);
//Flip flags is packed into gid
void setFlaggedTileGIDByIndex(int index, int gid);
//
void updateTotalQuads();
void onDraw(const std::vector<int>* indices);
inline int getTileIndexByPos(int x, int y) const { return x + y * (int) _layerSize.width; }
protected:
//! name of the layer
@ -240,9 +245,13 @@ protected:
/** tile coordinate to node coordinate transform */
Mat4 _tileToNodeTransform;
/** quads to be rendered */
bool _quadsDirty;
std::map<ssize_t, ssize_t> _tileToQuadIndex;
std::vector<V3F_C4B_T2F_Quad> _totalQuads;
std::map<int/*zorder*/, std::vector<int>> _quadsIndices;
std::vector<V3F_C4B_T2F_Quad> _quads;
std::map<int/*zorder*/, ssize_t/*number*/> _quadsNumber;
std::unordered_map<int/*zorder*/, NopreMultiplyMVQuadCommand> _renderCommands2;
std::vector<CustomCommand> _renderCommands;
bool _dirty;
};