[√]如何拿到label的绘制批次

简介: [√]如何拿到label的绘制批次

label的绘制是在onDraw完成的

void Label::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
    if (!_shadowEnabled && (_currentLabelType == LabelType::BMFONT || _currentLabelType == LabelType::CHARMAP))
    {
    }
    else
    {
        // 项目中使用的是TTF,label绘制走的是CustomCommand
        _customCommand.init(_globalZOrder, transform, flags);
        _customCommand.func = CC_CALLBACK_0(Label::onDraw, this, transform, transformUpdated);
        renderer->addCommand(&_customCommand);
    }
}
// 处理渲染命令时,碰到CustomCommand的逻辑
void Renderer::processRenderCommand(RenderCommand* command)
{
    if(RenderCommand::Type::CUSTOM_COMMAND == commandType)
    {
        flush();
        auto cmd = static_cast<CustomCommand*>(command);
        CCGL_DEBUG_INSERT_EVENT_MARKER("RENDERER_CUSTOM_COMMAND");
        cmd->execute();// 执行绑定的渲染函数: cmd.func()
    }
}
// 进行label的绘制
void Label::onDraw(const Mat4& transform, bool /*transformUpdated*/)
{
    // 最终的绘制结果都会放在BatchNode里面
    for (auto&& batchNode : _batchNodes)
    {
        //          ↓ 借用了Atlas进行渲染
        batchNode->getTextureAtlas()->drawQuads();
    }
}
void TextureAtlas::drawQuads()
{
    this->drawNumberOfQuads(_totalQuads, 0);
}
void TextureAtlas::drawNumberOfQuads(ssize_t numberOfQuads, ssize_t start)
{
    // 完成实际的绘制
    glDrawElements(GL_TRIANGLES, (GLsizei)numberOfQuads*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(_indices[0])));
    CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,numberOfQuads*6);// 告诉统计增加绘制批次
}

经过以上的分析,那如何知道label的绘制批次呢?也就是label要保存最后调用统计时的dcIndex

label.batchNode身上有BatchCommand,但是label没有使用这个BatchCommand,这个BatchCommand是给Sprite准备的

void Renderer::processRenderCommand(RenderCommand* command)
{
    if(RenderCommand::Type::BATCH_COMMAND == commandType)
    {
        flush();
        auto cmd = static_cast<BatchCommand*>(command);
        CCGL_DEBUG_INSERT_EVENT_MARKER("RENDERER_BATCH_COMMAND");
        cmd->execute();
    }
}
void BatchCommand::execute()
{
    // Set material
    _shader->use();
    _shader->setUniformsForBuiltins(_mv);
    GL::bindTexture2D(_textureID);
    GL::blendFunc(_blendType.src, _blendType.dst);
    // Draw 可以观察到最后还是使用Atlas进行了渲染
    _textureAtlas->drawQuads();
}

既然都是借用了Atlas,那么这个dcIndex还是存在Atlas上比较合适,在执行Atlas->drawQuads()的时候,更新dcIndex,然后统一从Atlas获取这个dcIndex就可以了。

所以最后label获取dcIndex的逻辑就变成这样子

// 我一直认为是基于RenderCommand的,所以架构是基于RenderCommand
cocos2d::RenderCommand* Label::getRenderCommand()
{
    SpriteBatchNode* batchNode = this->_batchNodes.front();
    // 这样就能直接拿到laebl的dcIndex,但是很明显和架构不符
    batchNode->getTextureAtlas()->drawCallIndex;
}

很明显,我们需要将这个dcIndex放到label绑定的CustomCommand。

能直接想到的就是,如果要更新cmd.dcIndex,只能从调用cmd.func的地方下手,2个思路:

// 方式1:在执行渲染回调的时候`cmd.func()`,通过返回值更新cmd.dcIndx
// 这种方式能直观的看到dcIndex的修改逻辑,但是改动func会带来一些未知问题
cmd.dcIndex = cmd.func(); 
// 方式2:传递指针,让fuc内部修改cmd.dcIndex
// 因为fuc可能实现差异很大,所以需要func内部自己处理dcIndex的赋值
cmd.func(cmd); 

这里我采用第二种方式,仔细分析后,我发现

void Label::onDraw(const Mat4& transform, bool /*transformUpdated*/)
{
    // 在执行这个Render的时候,很明显就是_customCommand导致的
    // .... 渲染逻辑
    // 在最后,修改_customCommand的dcIndex即可
    if (_batchNodes.size() > 0)
    {
        unsigned int dcIndex = _batchNodes.front()->getTextureAtlas()->drawCallIndex;
        this->_customCommand.setDrawCallIndex(dcIndex);
    }
}
cocos2d::RenderCommand* Label::getRenderCommand()
{
    if (!_shadowEnabled && (_currentLabelType == LabelType::BMFONT || _currentLabelType == LabelType::CHARMAP))
    {
        return &(this->_quadCommand);
    }
    else
    {
        unsigned int size = this->_batchNodes.size();
        if (size == 0)
        {
            return nullptr;
        }
        else
        {
            return &(this->_customCommand); // 在draw的时候已经正确赋值dcIndex了
        }
    }
    return Node::getRenderCommand();
}

至此就完美拿到ttf的label绘制批次了

std::function绑定的小细节

//                                                                                      ↓可变参数绑定的方式
#define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__)
//  _customCommand.func的函数是无参的: std::function<void()> func;
_customCommand.func = CC_CALLBACK_0(Label::onDraw, this, transform, transformUpdated);
// 但是绑定的onDraw函数是有参数的,原因是可变参数绑定
void Label::onDraw(const Mat4& transform, bool /*transformUpdated*/){}
// 可以看到其他的onDraw函数参数类型不同
void DrawNode::onDraw(const Mat4 &transform, uint32_t /*flags*/) 

std::bind 是 C++ 标准库中的函数对象绑定器,用于将函数和其参数绑定为一个可调用的对象。

在给定的代码片段中,std::bind 函数被使用,它接受一个函数指针或可调用对象(如函数、函数对象、成员函数等),并将其与一组参数绑定在一起。这些参数可以是直接传递的值,也可以是占位符(_1_2_3 等)。

  • &__selector__ 是要绑定的函数或可调用对象的名称(或地址)。
  • __target__ 是绑定的目标对象。
  • ##__VA_ARGS__ 是可变参数,可以是一系列要绑定的参数。

这样的绑定操作旨在创建一个可调用的对象,使得在调用该对象时,被绑定的函数会以预先指定的目标对象和参数进行调用。这种方式在一些场景中非常有用,例如回调函数、事件处理等。

目录
相关文章
|
小程序
Qt 在Label上面绘制罗盘
自己写的一个小小的电子罗盘的一个小程序,不过是项目的一部分,只可以贴绘制部分代码
305 0
Qt 在Label上面绘制罗盘
|
7月前
125Echarts - 关系图(Force Layout)
125Echarts - 关系图(Force Layout)
26 0
|
11月前
|
JavaScript
DOM ------ input框查询的放大效果
DOM ------ input框查询的放大效果
【pyqt5】line edit实时获取输入值
【pyqt5】line edit实时获取输入值
|
存储
使用Dynamic Data Display控件绘图时无法删除已经画好的曲线
最近在使用Dynamic Data Display画图的时候发现,多次画图时,之前画的图无法清除,造成图像混乱。找了好久发现这样可以消除。 在调用AddLineGraph时,使用一个全局的变量来存储这个方法返回的对象(LineGraph), 点击...
859 0
|
Windows
KPI tile在launchpad里正常显示number,但是进不了detail view
KPI tile在launchpad里正常显示number,但是进不了detail view
KPI tile在launchpad里正常显示number,但是进不了detail view