Slice9 Sprite with triangles, not quads (#17105)

* sprites: use triangles instead of quads

uses less memory

* oops, color should be white by default

* works with flipped sprites

* none for xcode
This commit is contained in:
Ricardo Quesada 2017-01-04 17:27:13 -08:00 committed by minggo
parent 93d193dfcc
commit ff8e622b7a
2 changed files with 96 additions and 17 deletions

View File

@ -313,7 +313,8 @@ Sprite::Sprite(void)
, _insideBounds(true)
, _centerRectNormalized(0,0,1,1)
, _numberOfSlices(1)
, _quads(nullptr)
, _trianglesVertex(nullptr)
, _trianglesIndex(nullptr)
, _strechFactor(Vec2::ONE)
, _originalContentSize(Size::ZERO)
, _strechEnabled(true)
@ -326,7 +327,8 @@ Sprite::Sprite(void)
Sprite::~Sprite()
{
CC_SAFE_FREE(_quads);
CC_SAFE_FREE(_trianglesVertex);
CC_SAFE_FREE(_trianglesIndex);
CC_SAFE_RELEASE(_spriteFrame);
CC_SAFE_RELEASE(_texture);
}
@ -438,7 +440,6 @@ void Sprite::updatePoly()
// C) 9-sliced, streched
// the sprite is 9-sliced and streched.
if (_numberOfSlices == 1) {
setTextureCoords(_rect, &_quad);
Rect copyRect;
if (_strechEnabled) {
// case B)
@ -451,12 +452,13 @@ void Sprite::updatePoly()
_rect.size.width,
_rect.size.height);
}
setTextureCoords(_rect, &_quad);
setVertexCoords(copyRect, &_quad);
_polyInfo.setQuad(&_quad);
} else {
// case C)
// in theory it can support 3 slices as well, but let's stick to 9 only
// in theory it can support 3 or 6 slices as well, but let's stick to 9 only
CCASSERT(_numberOfSlices == 9, "Invalid number of slices");
@ -647,11 +649,23 @@ void Sprite::updatePoly()
Rect(x2, y2, x2_s, y2_s), // top-right
};
// needed in order to get color from "_quad"
V3F_C4B_T2F_Quad tmpQuad = _quad;
for (int i=0; i<_numberOfSlices; ++i) {
setTextureCoords(texRects[i], &_quads[i]);
setVertexCoords(verticesRects[i], &_quads[i]);
setTextureCoords(texRects[i], &tmpQuad);
setVertexCoords(verticesRects[i], &tmpQuad);
populateTriangle(i, tmpQuad);
}
_polyInfo.setQuads(_quads, _numberOfSlices);
TrianglesCommand::Triangles triangles;
triangles.verts = _trianglesVertex;
triangles.vertCount = 16;
triangles.indices = _trianglesIndex;
triangles.indexCount = 6 * 9; // 9 quads, each needs 6 vertices
// probably we can update the _trianglesCommand directly
// to avoid memcpy'ing stuff
_polyInfo.setTriangles(triangles);
}
}
@ -667,21 +681,29 @@ void Sprite::setCenterRectNormalized(const cocos2d::Rect &rectTopLeft)
// convert it to 1-slice
if (rect.equals(Rect(0,0,1,1))) {
_numberOfSlices = 1;
free(_quads);
_quads = nullptr;
free(_trianglesVertex);
free(_trianglesIndex);
_trianglesVertex = nullptr;
_trianglesIndex = nullptr;
}
else
{
// convert it to 9-slice if it isn't already
if (_numberOfSlices != 9) {
_numberOfSlices = 9;
_quads = (V3F_C4B_T2F_Quad*) malloc(sizeof(*_quads) * 9);
// 9 quads + 7 exterior points = 16
_trianglesVertex = (V3F_C4B_T2F*) malloc(sizeof(*_trianglesVertex) * (9 + 3 + 4));
// 9 quads, each needs 6 vertices = 54
_trianglesIndex = (unsigned short*) malloc(sizeof(*_trianglesIndex) * 6 * 9);
// populate indices in CCW direction
for (int i=0; i<9; ++i) {
_quads[i].bl.colors = Color4B::WHITE;
_quads[i].br.colors = Color4B::WHITE;
_quads[i].tl.colors = Color4B::WHITE;
_quads[i].tr.colors = Color4B::WHITE;
_trianglesIndex[i * 6 + 0] = (i * 4 / 3) + 4;
_trianglesIndex[i * 6 + 1] = (i * 4 / 3) + 0;
_trianglesIndex[i * 6 + 2] = (i * 4 / 3) + 5;
_trianglesIndex[i * 6 + 3] = (i * 4 / 3) + 1;
_trianglesIndex[i * 6 + 4] = (i * 4 / 3) + 5;
_trianglesIndex[i * 6 + 5] = (i * 4 / 3) + 0;
}
}
}
@ -779,12 +801,12 @@ void Sprite::setTextureCoords(const Rect& rectInPoints, V3F_C4B_T2F_Quad* outQua
#endif // CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
if ((_flippedX && !_rectRotated) || (_flippedY && _rectRotated))
if ((!_rectRotated && _flippedX) || (_rectRotated && _flippedY))
{
std::swap(left, right);
}
if ((_flippedY && !_rectRotated) || (_flippedX && _rectRotated))
if ((!_rectRotated && _flippedY) || (_rectRotated && _flippedX))
{
std::swap(top, bottom);
}
@ -862,6 +884,61 @@ void Sprite::setVertexCoords(const Rect& rect, V3F_C4B_T2F_Quad* outQuad)
}
}
void Sprite::populateTriangle(int quadIndex, const V3F_C4B_T2F_Quad& quad)
{
CCASSERT(quadIndex < 9, "Invalid quadIndex");
// convert Quad intro Triangle since it takes less memory
// Triangles are ordered like the following:
// Numbers: Quad Index
// Letters: triangles' vertices
//
// M-----N-----O-----P
// | | | |
// | 6 | 7 | 8 |
// | | | |
// I-----J-----K-----L
// | | | |
// | 3 | 4 | 5 |
// | | | |
// E-----F-----G-----H
// | | | |
// | 0 | 1 | 2 |
// | | | |
// A-----B-----C-----D
//
// So, if QuadIndex == 4, then it should update vertices J,K,F,G
// Optimization: I don't need to copy all the vertices all the time. just the 4 "quads" from the corners.
if (quadIndex == 0 || quadIndex == 2 || quadIndex == 6 || quadIndex == 8)
{
if (_flippedX) {
if (quadIndex % 3 == 0)
quadIndex += 2;
else
quadIndex -= 2;
}
if (_flippedY) {
if (quadIndex <= 2)
quadIndex += 6;
else
quadIndex -= 6;
}
const int index_bl = quadIndex * 4 / 3;
const int index_br = index_bl + 1;
const int index_tl = index_bl + 4;
const int index_tr = index_bl + 5;
_trianglesVertex[index_tr] = quad.tr;
_trianglesVertex[index_br] = quad.br;
_trianglesVertex[index_tl] = quad.tl;
_trianglesVertex[index_bl] = quad.bl;
}
}
// MARK: visit, draw, transform

View File

@ -631,6 +631,7 @@ protected:
virtual void setTextureCoords(const Rect& rect);
virtual void setTextureCoords(const Rect& rect, V3F_C4B_T2F_Quad* outQuad);
virtual void setVertexCoords(const Rect& rect, V3F_C4B_T2F_Quad* outQuad);
void populateTriangle(int quadIndex, const V3F_C4B_T2F_Quad& quad);
virtual void updateBlendFunc();
virtual void setReorderChildDirtyRecursively();
virtual void setDirtyRecursively(bool value);
@ -680,7 +681,8 @@ protected:
// vertex coords, texture coords and color info
V3F_C4B_T2F_Quad _quad;
V3F_C4B_T2F_Quad* _quads;
V3F_C4B_T2F* _trianglesVertex;
unsigned short* _trianglesIndex;
PolygonInfo _polyInfo;
// opacity and RGB protocol