feat(renderer): 添加形状和文本批处理支持
扩展渲染器功能,新增形状批处理(ShapeBatcher)和文本批处理(TextBatcher)支持。重构批处理状态管理,将单一inBatch标志拆分为inSpriteBatch、inShapeBatch和inTextBatch三个独立标志。添加对应的开始/结束批处理方法,并实现相关绘制功能的批处理集成。
This commit is contained in:
parent
0999644a71
commit
481d4c8f9d
|
|
@ -5,6 +5,8 @@
|
||||||
#include <extra2d/core/module.h>
|
#include <extra2d/core/module.h>
|
||||||
#include <extra2d/core/types.h>
|
#include <extra2d/core/types.h>
|
||||||
#include <extra2d/render/batch/sprite_batcher.h>
|
#include <extra2d/render/batch/sprite_batcher.h>
|
||||||
|
#include <extra2d/render/batch/shape_batcher.h>
|
||||||
|
#include <extra2d/render/batch/text_batcher.h>
|
||||||
#include <extra2d/render/camera/camera.h>
|
#include <extra2d/render/camera/camera.h>
|
||||||
#include <extra2d/render/camera/viewport_adapter.h>
|
#include <extra2d/render/camera/viewport_adapter.h>
|
||||||
#include <extra2d/render/core/render_queue.h>
|
#include <extra2d/render/core/render_queue.h>
|
||||||
|
|
@ -305,6 +307,16 @@ public:
|
||||||
// 批处理控制
|
// 批处理控制
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 开始所有批处理
|
||||||
|
*/
|
||||||
|
void beginBatch();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 结束所有批处理
|
||||||
|
*/
|
||||||
|
void endBatch();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 开始精灵批处理
|
* @brief 开始精灵批处理
|
||||||
*/
|
*/
|
||||||
|
|
@ -315,6 +327,26 @@ public:
|
||||||
*/
|
*/
|
||||||
void endSpriteBatch();
|
void endSpriteBatch();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 开始形状批处理
|
||||||
|
*/
|
||||||
|
void beginShapeBatch();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 结束形状批处理
|
||||||
|
*/
|
||||||
|
void endShapeBatch();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 开始文本批处理
|
||||||
|
*/
|
||||||
|
void beginTextBatch();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 结束文本批处理
|
||||||
|
*/
|
||||||
|
void endTextBatch();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 刷新当前批次
|
* @brief 刷新当前批次
|
||||||
*/
|
*/
|
||||||
|
|
@ -455,6 +487,8 @@ private:
|
||||||
|
|
||||||
Ptr<rhi::RHIDevice> device_;
|
Ptr<rhi::RHIDevice> device_;
|
||||||
UniquePtr<SpriteBatcher> spriteBatcher_;
|
UniquePtr<SpriteBatcher> spriteBatcher_;
|
||||||
|
UniquePtr<ShapeBatcher> shapeBatcher_;
|
||||||
|
UniquePtr<TextBatcher> textBatcher_;
|
||||||
UniquePtr<RenderQueue> renderQueue_;
|
UniquePtr<RenderQueue> renderQueue_;
|
||||||
|
|
||||||
ViewportAdapter viewportAdapter_;
|
ViewportAdapter viewportAdapter_;
|
||||||
|
|
@ -472,7 +506,9 @@ private:
|
||||||
uint64_t sortKey_;
|
uint64_t sortKey_;
|
||||||
int layer_;
|
int layer_;
|
||||||
rhi::BlendState blendState_;
|
rhi::BlendState blendState_;
|
||||||
bool inBatch_;
|
bool inSpriteBatch_;
|
||||||
|
bool inShapeBatch_;
|
||||||
|
bool inTextBatch_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace extra2d
|
} // namespace extra2d
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,13 @@ Renderer::Renderer()
|
||||||
: window_(nullptr), config_(), width_(0), height_(0), initialized_(false),
|
: window_(nullptr), config_(), width_(0), height_(0), initialized_(false),
|
||||||
projectionMatrix_(1.0f), viewMatrix_(1.0f), stats_(),
|
projectionMatrix_(1.0f), viewMatrix_(1.0f), stats_(),
|
||||||
sortKey_(0), layer_(0), blendState_(rhi::BlendState::alphaBlend()),
|
sortKey_(0), layer_(0), blendState_(rhi::BlendState::alphaBlend()),
|
||||||
inBatch_(false) {}
|
inSpriteBatch_(false), inShapeBatch_(false), inTextBatch_(false) {}
|
||||||
|
|
||||||
Renderer::Renderer(const RendererConfig &config)
|
Renderer::Renderer(const RendererConfig &config)
|
||||||
: window_(nullptr), config_(config), width_(0), height_(0), initialized_(false),
|
: window_(nullptr), config_(config), width_(0), height_(0), initialized_(false),
|
||||||
projectionMatrix_(1.0f), viewMatrix_(1.0f), stats_(),
|
projectionMatrix_(1.0f), viewMatrix_(1.0f), stats_(),
|
||||||
sortKey_(0), layer_(0), blendState_(rhi::BlendState::alphaBlend()),
|
sortKey_(0), layer_(0), blendState_(rhi::BlendState::alphaBlend()),
|
||||||
inBatch_(false) {}
|
inSpriteBatch_(false), inShapeBatch_(false), inTextBatch_(false) {}
|
||||||
|
|
||||||
Renderer::~Renderer() { shutdown(); }
|
Renderer::~Renderer() { shutdown(); }
|
||||||
|
|
||||||
|
|
@ -49,12 +49,26 @@ bool Renderer::init(IWindow *window, const RendererConfig &config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
spriteBatcher_ = makeUnique<SpriteBatcher>();
|
spriteBatcher_ = makeUnique<SpriteBatcher>();
|
||||||
SpriteBatcherConfig batcherConfig;
|
SpriteBatcherConfig spriteConfig;
|
||||||
batcherConfig.maxBatchSize = config.maxBatchSize;
|
spriteConfig.maxBatchSize = config.maxBatchSize;
|
||||||
if (!spriteBatcher_->init(device_)) {
|
if (!spriteBatcher_->init(device_)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shapeBatcher_ = makeUnique<ShapeBatcher>();
|
||||||
|
ShapeBatcherConfig shapeConfig;
|
||||||
|
shapeConfig.maxBatchSize = config.maxBatchSize / 2;
|
||||||
|
if (!shapeBatcher_->init(device_)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
textBatcher_ = makeUnique<TextBatcher>();
|
||||||
|
TextBatcherConfig textConfig;
|
||||||
|
textConfig.maxBatchSize = config.maxBatchSize / 2;
|
||||||
|
if (!textBatcher_->init(device_)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
renderQueue_ = makeUnique<RenderQueue>();
|
renderQueue_ = makeUnique<RenderQueue>();
|
||||||
|
|
||||||
projectionMatrix_ = glm::ortho(0.0f, static_cast<float>(width_),
|
projectionMatrix_ = glm::ortho(0.0f, static_cast<float>(width_),
|
||||||
|
|
@ -78,6 +92,16 @@ void Renderer::shutdown() {
|
||||||
spriteBatcher_.reset();
|
spriteBatcher_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shapeBatcher_) {
|
||||||
|
shapeBatcher_->shutdown();
|
||||||
|
shapeBatcher_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textBatcher_) {
|
||||||
|
textBatcher_->shutdown();
|
||||||
|
textBatcher_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
if (renderQueue_) {
|
if (renderQueue_) {
|
||||||
renderQueue_.reset();
|
renderQueue_.reset();
|
||||||
}
|
}
|
||||||
|
|
@ -118,10 +142,18 @@ void Renderer::endFrame() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inBatch_) {
|
if (inSpriteBatch_) {
|
||||||
endSpriteBatch();
|
endSpriteBatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inShapeBatch_) {
|
||||||
|
endShapeBatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inTextBatch_) {
|
||||||
|
endTextBatch();
|
||||||
|
}
|
||||||
|
|
||||||
device_->endFrame();
|
device_->endFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -201,12 +233,22 @@ void Renderer::drawSprite(Ptr<rhi::RHITexture> texture, const Rect &destRect,
|
||||||
|
|
||||||
stats_.spriteCount++;
|
stats_.spriteCount++;
|
||||||
|
|
||||||
if (!inBatch_) {
|
if (!inSpriteBatch_) {
|
||||||
beginSpriteBatch();
|
beginSpriteBatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rect adjustedSrcRect = srcRect;
|
||||||
|
if (flipX) {
|
||||||
|
adjustedSrcRect.origin.x += adjustedSrcRect.size.width;
|
||||||
|
adjustedSrcRect.size.width = -adjustedSrcRect.size.width;
|
||||||
|
}
|
||||||
|
if (flipY) {
|
||||||
|
adjustedSrcRect.origin.y += adjustedSrcRect.size.height;
|
||||||
|
adjustedSrcRect.size.height = -adjustedSrcRect.size.height;
|
||||||
|
}
|
||||||
|
|
||||||
Vec2 anchor(0.5f, 0.5f);
|
Vec2 anchor(0.5f, 0.5f);
|
||||||
spriteBatcher_->draw(texture, destRect, srcRect, color, rotation, anchor, blendState_);
|
spriteBatcher_->draw(texture, destRect, adjustedSrcRect, color, rotation, anchor, blendState_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::drawSprite(Ptr<rhi::RHITexture> texture,
|
void Renderer::drawSprite(Ptr<rhi::RHITexture> texture,
|
||||||
|
|
@ -218,7 +260,7 @@ void Renderer::drawSprite(Ptr<rhi::RHITexture> texture,
|
||||||
|
|
||||||
stats_.spriteCount++;
|
stats_.spriteCount++;
|
||||||
|
|
||||||
if (!inBatch_) {
|
if (!inSpriteBatch_) {
|
||||||
beginSpriteBatch();
|
beginSpriteBatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -264,92 +306,208 @@ Vec2 Renderer::measureText(const std::u32string &text, float fontSize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::drawRect(const Rect &rect, const Color &color, float lineWidth) {
|
void Renderer::drawRect(const Rect &rect, const Color &color, float lineWidth) {
|
||||||
if (!initialized_) {
|
if (!initialized_ || !shapeBatcher_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!inShapeBatch_) {
|
||||||
|
beginShapeBatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
shapeBatcher_->drawRect(rect, color, lineWidth);
|
||||||
stats_.shapeCount++;
|
stats_.shapeCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::fillRect(const Rect &rect, const Color &color) {
|
void Renderer::fillRect(const Rect &rect, const Color &color) {
|
||||||
if (!initialized_) {
|
if (!initialized_ || !shapeBatcher_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!inShapeBatch_) {
|
||||||
|
beginShapeBatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
shapeBatcher_->drawFilledRect(rect, color);
|
||||||
stats_.shapeCount++;
|
stats_.shapeCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::drawCircle(const Vec2 ¢er, float radius, const Color &color,
|
void Renderer::drawCircle(const Vec2 ¢er, float radius, const Color &color,
|
||||||
float lineWidth, uint32_t segments) {
|
float lineWidth, uint32_t segments) {
|
||||||
if (!initialized_) {
|
if (!initialized_ || !shapeBatcher_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!inShapeBatch_) {
|
||||||
|
beginShapeBatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
shapeBatcher_->drawCircle(center, radius, color, static_cast<int>(segments), lineWidth);
|
||||||
stats_.shapeCount++;
|
stats_.shapeCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::fillCircle(const Vec2 ¢er, float radius, const Color &color,
|
void Renderer::fillCircle(const Vec2 ¢er, float radius, const Color &color,
|
||||||
uint32_t segments) {
|
uint32_t segments) {
|
||||||
if (!initialized_) {
|
if (!initialized_ || !shapeBatcher_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!inShapeBatch_) {
|
||||||
|
beginShapeBatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
shapeBatcher_->drawFilledCircle(center, radius, color, static_cast<int>(segments));
|
||||||
stats_.shapeCount++;
|
stats_.shapeCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
|
void Renderer::drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
|
||||||
float lineWidth) {
|
float lineWidth) {
|
||||||
if (!initialized_) {
|
if (!initialized_ || !shapeBatcher_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!inShapeBatch_) {
|
||||||
|
beginShapeBatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
shapeBatcher_->drawLine(start, end, color, lineWidth);
|
||||||
stats_.shapeCount++;
|
stats_.shapeCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::drawPolygon(const Vec2 *points, size_t count, const Color &color,
|
void Renderer::drawPolygon(const Vec2 *points, size_t count, const Color &color,
|
||||||
float lineWidth) {
|
float lineWidth) {
|
||||||
if (!initialized_ || !points || count < 3) {
|
if (!initialized_ || !points || count < 3 || !shapeBatcher_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!inShapeBatch_) {
|
||||||
|
beginShapeBatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Vec2> pointVec(points, points + count);
|
||||||
|
shapeBatcher_->drawPolygon(pointVec, color, lineWidth);
|
||||||
stats_.shapeCount++;
|
stats_.shapeCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::fillPolygon(const Vec2 *points, size_t count,
|
void Renderer::fillPolygon(const Vec2 *points, size_t count,
|
||||||
const Color &color) {
|
const Color &color) {
|
||||||
if (!initialized_ || !points || count < 3) {
|
if (!initialized_ || !points || count < 3 || !shapeBatcher_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!inShapeBatch_) {
|
||||||
|
beginShapeBatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Vec2> pointVec(points, points + count);
|
||||||
|
shapeBatcher_->drawFilledPolygon(pointVec, color);
|
||||||
stats_.shapeCount++;
|
stats_.shapeCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::beginSpriteBatch() {
|
void Renderer::beginBatch() {
|
||||||
if (!initialized_ || !spriteBatcher_ || inBatch_) {
|
if (!initialized_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
inBatch_ = true;
|
beginSpriteBatch();
|
||||||
|
beginShapeBatch();
|
||||||
|
beginTextBatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::endBatch() {
|
||||||
|
if (!initialized_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
endSpriteBatch();
|
||||||
|
endShapeBatch();
|
||||||
|
endTextBatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::beginSpriteBatch() {
|
||||||
|
if (!initialized_ || !spriteBatcher_ || inSpriteBatch_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inSpriteBatch_ = true;
|
||||||
spriteBatcher_->begin(projectionMatrix_ * viewMatrix_);
|
spriteBatcher_->begin(projectionMatrix_ * viewMatrix_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::endSpriteBatch() {
|
void Renderer::endSpriteBatch() {
|
||||||
if (!initialized_ || !spriteBatcher_ || !inBatch_) {
|
if (!initialized_ || !spriteBatcher_ || !inSpriteBatch_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spriteBatcher_->end();
|
spriteBatcher_->end();
|
||||||
inBatch_ = false;
|
inSpriteBatch_ = false;
|
||||||
stats_.batchCount++;
|
stats_.batchCount++;
|
||||||
stats_.drawCalls += spriteBatcher_->getDrawCallCount();
|
stats_.drawCalls += spriteBatcher_->getDrawCallCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::flush() {
|
void Renderer::beginShapeBatch() {
|
||||||
if (!initialized_ || !spriteBatcher_) {
|
if (!initialized_ || !shapeBatcher_ || inShapeBatch_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inShapeBatch_ = true;
|
||||||
|
shapeBatcher_->begin(projectionMatrix_ * viewMatrix_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::endShapeBatch() {
|
||||||
|
if (!initialized_ || !shapeBatcher_ || !inShapeBatch_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
shapeBatcher_->end();
|
||||||
|
inShapeBatch_ = false;
|
||||||
stats_.batchCount++;
|
stats_.batchCount++;
|
||||||
|
stats_.drawCalls += shapeBatcher_->getDrawCallCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::beginTextBatch() {
|
||||||
|
if (!initialized_ || !textBatcher_ || inTextBatch_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inTextBatch_ = true;
|
||||||
|
textBatcher_->begin(projectionMatrix_ * viewMatrix_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::endTextBatch() {
|
||||||
|
if (!initialized_ || !textBatcher_ || !inTextBatch_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
textBatcher_->end();
|
||||||
|
inTextBatch_ = false;
|
||||||
|
stats_.batchCount++;
|
||||||
|
stats_.drawCalls += textBatcher_->getDrawCallCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::flush() {
|
||||||
|
if (!initialized_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spriteBatcher_ && inSpriteBatch_) {
|
||||||
|
spriteBatcher_->end();
|
||||||
|
spriteBatcher_->begin(projectionMatrix_ * viewMatrix_);
|
||||||
|
stats_.batchCount++;
|
||||||
|
stats_.drawCalls += spriteBatcher_->getDrawCallCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shapeBatcher_ && inShapeBatch_) {
|
||||||
|
shapeBatcher_->end();
|
||||||
|
shapeBatcher_->begin(projectionMatrix_ * viewMatrix_);
|
||||||
|
stats_.batchCount++;
|
||||||
|
stats_.drawCalls += shapeBatcher_->getDrawCallCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textBatcher_ && inTextBatch_) {
|
||||||
|
textBatcher_->end();
|
||||||
|
textBatcher_->begin(projectionMatrix_ * viewMatrix_);
|
||||||
|
stats_.batchCount++;
|
||||||
|
stats_.drawCalls += textBatcher_->getDrawCallCount();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::setSortKey(uint64_t key) {
|
void Renderer::setSortKey(uint64_t key) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue