Need some input on BM font drawing using TriangleCommand

Need some input on BM font drawing using TriangleCommand
0

I’ve been trying to find ways to reduce the draw calls due to the usage of labels in certain places, like ui::ImageView with a child label added as ui::ListView items, where we can’t easily set the labels to a different global Z layer given that the ListView needs clipping enabled. What happens there is that it switches between the sprite sheet being used for the ImageView and the BM font texture for every single item in the ListView, which adds up to a considerable number of draw calls.

So, given that BM Labels are rendered using QuadCommand, I modified it to instead us TriangleCommand, so I can have the BM font texture embedded in the larger sprite sheet, in the hope that I can manage to get them batched together (assuming they’re using the same shader and such).

Anyhow, I don’t know enough about these things to see any possible issues, so if anyone has advice or suggestions, then please do mention them.

I modified the following code to change them to TriangleCommand:

CCLabel.c:

void Label::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
    ...
            const auto textureAtlas = _batchNodes.at(0)->getTextureAtlas();
            const auto totalQuads = textureAtlas->getTotalQuads();

            TrianglesCommand::Triangles triangles;
            triangles.indices = textureAtlas->getIndices();
            triangles.verts = (V3F_C4B_T2F*)textureAtlas->getQuads();
            triangles.vertCount = 4 * totalQuads;
            triangles.indexCount = 6 * totalQuads;
            _trianglesCommand.init(_globalZOrder, textureAtlas->getTexture()->getName(), getGLProgramState(), _blendFunc, triangles, transform, flags);
            renderer->addCommand(&_trianglesCommand);

            // The following is the QuadCommand that was replaced
            //auto textureAtlas = _batchNodes.at(0)->getTextureAtlas();
            //auto texture = textureAtlas->getTexture();
            //_quadCommand.init(_globalZOrder, texture, getGLProgramState(), 
            //    _blendFunc, textureAtlas->getQuads(), textureAtlas->getTotalQuads(), transform, flags);
            //renderer->addCommand(&_quadCommand);

    ....

CCTextureAtlas.h:

    GLushort* getIndices() { return _indices; }

The code above works, and renders the labels in their entirety. The next step is to figure out the best way to get the BM font to handle a texture in a larger sprite sheet.

I noticed another thread regarding this same issue, https://discuss.cocos2d-x.org/t/mixing-sprites-and-bitmap-fonts-on-a-single-texture-to-limit-draw-calls/26088/6, but the discussion seemed to stop without any results.

Is there any reason this wasn’t done previously, or any reason it shouldn’t be done this way?

EDIT:
There is some support in the current Cocos2d-x code for supplying a BM font texture that exists inside a bigger texture, so the following worked (went from 60+ draw calls to 2…):

const auto fontFrame = SpriteFrameCache::getInstance()->getSpriteFrameByName("arimo_40.png"); // This is in a larget texture
const auto label = Label::createWithBMFont("arimo_40.fnt", "TEXT", TextHAlignment::CENTER, 0, fontFrame->getRectInPixels().origin);

arimo_40.fnt is modified to reference the larger spritesheet name, which for this example is “spritesheet-0.png”:

info face="Arimo" size=40 bold=1 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1 outline=0
common lineHeight=40 base=32 scaleW=256 scaleH=256 pages=1 packed=0 alphaChnl=1 redChnl=0 greenChnl=0 blueChnl=0
page id=0 file="spritesheet-0.png"

The only thing it doesn’t seem to support is if the font texture is rotated inside the bigger sprite sheet, but that’s something that may be easy to fix.

OK, so after looking into this a bit more, it turns out that there is no need to render the bitmap font using TriangleCommand, since they’ll still be batched even if they use QuadCommand.

The only only thing that needs to be done is to set the image atlas name in the FNT file, and location of the font atlas inside the bigger image atlas, as shown at the end of my previous post.

Initial support for rotated atlas font textures has been added in this PR too.

2 Likes

@zhangxm @coulsonwang can you please take a look at this.

I managed to get it all working, but haven’t pushed the changes to the PR. I’ve added a comment in the PR with an example of how it would work. Nothing really changes, bitmap font labels can still be created the same way as before, but the new API allows for BM font atlases to be embedded into larger sprite atlases (with rotation support).

1 Like

For anyone interested, the full changes and sample usage are in PR 20309