diff --git a/Extra2D/src/graphics/backends/opengl/gl_renderer.cpp b/Extra2D/src/graphics/backends/opengl/gl_renderer.cpp index 93720ef..548bcd2 100644 --- a/Extra2D/src/graphics/backends/opengl/gl_renderer.cpp +++ b/Extra2D/src/graphics/backends/opengl/gl_renderer.cpp @@ -1,13 +1,13 @@ #include #include #include -#include #include #include #include #include -#include +#include #include +#include #include #include #include @@ -340,10 +340,8 @@ void GLRenderer::drawSprite(const Texture &texture, const Rect &destRect, float v1 = srcRect.origin.y / texH; float v2 = (srcRect.origin.y + srcRect.size.height) / texH; - data.uvRect = Rect( - Vec2(glm::min(u1, u2), glm::min(v1, v2)), - Size(glm::abs(u2 - u1), glm::abs(v2 - v1)) - ); + data.uvRect = Rect(Vec2(glm::min(u1, u2), glm::min(v1, v2)), + Size(glm::abs(u2 - u1), glm::abs(v2 - v1))); data.color = tint; data.rotation = rotation * 3.14159f / 180.0f; @@ -366,10 +364,8 @@ void GLRenderer::drawSprite(const Texture &texture, const Rect &destRect, float v1 = srcRect.origin.y / texH; float v2 = (srcRect.origin.y + srcRect.size.height) / texH; - data.uvRect = Rect( - Vec2(glm::min(u1, u2), glm::min(v1, v2)), - Size(glm::abs(u2 - u1), glm::abs(v2 - v1)) - ); + data.uvRect = Rect(Vec2(glm::min(u1, u2), glm::min(v1, v2)), + Size(glm::abs(u2 - u1), glm::abs(v2 - v1))); data.color = tint; data.rotation = rotation * 3.14159f / 180.0f; @@ -688,6 +684,15 @@ void GLRenderer::drawText(const FontAtlas &font, const std::string &text, ensureBatchActive(); } + // 检查纹理变化,如果纹理不同则先提交当前批次 + if (autoBatchEnabled_ && currentBatchTexture_ != nullptr && + currentBatchTexture_ != font.getTexture()) { + submitPendingSprites(); + } + if (autoBatchEnabled_) { + currentBatchTexture_ = font.getTexture(); + } + // 收集所有字符数据用于批处理 std::vector sprites; sprites.reserve(text.size()); // 预分配空间 @@ -695,9 +700,15 @@ void GLRenderer::drawText(const FontAtlas &font, const std::string &text, for (char c : text) { char32_t codepoint = static_cast(static_cast(c)); if (codepoint == '\n') { - // 提交当前批次(换行时) - if (autoBatchEnabled_ && !sprites.empty()) { - spriteBatch_.drawBatch(*font.getTexture(), sprites); + // 换行时,将当前行添加到待处理列表 + if (!sprites.empty()) { + if (autoBatchEnabled_) { + pendingSprites_.insert(pendingSprites_.end(), sprites.begin(), + sprites.end()); + } else { + // 手动模式直接提交 + spriteBatch_.drawBatch(*font.getTexture(), sprites); + } sprites.clear(); } cursorX = x; @@ -725,12 +736,11 @@ void GLRenderer::drawText(const FontAtlas &font, const std::string &text, SpriteData data; // 设置精灵中心位置(精灵批处理使用中心点) - data.position = Vec2(xPos + glyph->width * 0.5f, yPos + glyph->height * 0.5f); + data.position = + Vec2(xPos + glyph->width * 0.5f, yPos + glyph->height * 0.5f); data.size = Vec2(glyph->width, glyph->height); - data.uvRect = Rect( - Vec2(glyph->u0, glyph->v0), - Size(glyph->u1 - glyph->u0, glyph->v1 - glyph->v0) - ); + data.uvRect = Rect(Vec2(glyph->u0, glyph->v0), + Size(glyph->u1 - glyph->u0, glyph->v1 - glyph->v0)); data.color = color; data.rotation = 0.0f; // pivot (0.5, 0.5) 表示中心点,这样 position 就是精灵中心 @@ -740,7 +750,8 @@ void GLRenderer::drawText(const FontAtlas &font, const std::string &text, // 自动批处理:如果缓冲区满,先提交当前批次 if (autoBatchEnabled_ && sprites.size() >= MAX_BATCH_SPRITES) { - spriteBatch_.drawBatch(*font.getTexture(), sprites); + pendingSprites_.insert(pendingSprites_.end(), sprites.begin(), + sprites.end()); sprites.clear(); } } @@ -749,14 +760,11 @@ void GLRenderer::drawText(const FontAtlas &font, const std::string &text, // 提交剩余的字符 if (!sprites.empty()) { if (autoBatchEnabled_) { - spriteBatch_.drawBatch(*font.getTexture(), sprites); + pendingSprites_.insert(pendingSprites_.end(), sprites.begin(), + sprites.end()); } else { - // 手动模式下,添加到待处理列表 - if (currentBatchTexture_ != font.getTexture()) { - submitPendingSprites(); - currentBatchTexture_ = font.getTexture(); - } - pendingSprites_.insert(pendingSprites_.end(), sprites.begin(), sprites.end()); + // 手动模式下直接提交 + spriteBatch_.drawBatch(*font.getTexture(), sprites); } } } diff --git a/examples/image_display/main.cpp b/examples/image_display/main.cpp index 293415c..972e58d 100644 --- a/examples/image_display/main.cpp +++ b/examples/image_display/main.cpp @@ -6,53 +6,46 @@ * 此示例不依赖任何特定渲染后端(如 OpenGL) */ -#include #include -#include -#include -#include -#include -#include -#include -#include #include using namespace extra2d; class ImageDisplayScene : public Scene { public: - void onEnter() override { - // 加载图片 - // 注意:请确保有图片文件在 assets/images/ 目录下 - try { - texture_ = renderer_->loadTexture("assets/images/demo.jpg"); - std::cout << "Image loaded successfully!" << std::endl; - std::cout << " Size: " << texture_->getWidth() << "x" << texture_->getHeight() << std::endl; - } catch (...) { - std::cerr << "Failed to load image from assets/images/demo.jpg" << std::endl; - // 尝试使用备用路径 - try { - texture_ = renderer_->loadTexture("examples/image_display/assets/images/demo.jpg"); - std::cout << "Image loaded from alternate path!" << std::endl; - } catch (...) { - std::cerr << "Failed to load image from alternate path!" << std::endl; - texture_ = nullptr; - } - } + void onEnter() override { + // 加载图片 + // 注意:请确保有图片文件在 assets/images/ 目录下 + try { + texture_ = renderer_->loadTexture("assets/images/demo.jpg"); + std::cout << "Image loaded successfully!" << std::endl; + std::cout << " Size: " << texture_->getWidth() << "x" + << texture_->getHeight() << std::endl; + } catch (...) { + std::cerr << "Failed to load image from assets/images/demo.jpg" + << std::endl; + // 尝试使用备用路径 + try { + texture_ = renderer_->loadTexture( + "examples/image_display/assets/images/demo.jpg"); + std::cout << "Image loaded from alternate path!" << std::endl; + } catch (...) { + std::cerr << "Failed to load image from alternate path!" << std::endl; + texture_ = nullptr; + } + } + } + + void onExit() override { texture_.reset(); } + + void onRender(RenderBackend &renderer) override { + Scene::onRender(renderer); + + if (!texture_) { + return; } - void onExit() override { - texture_.reset(); - } - - void onRender(RenderBackend& renderer) override { - Scene::onRender(renderer); - - if (!texture_) { - return; - } - - // 使用 RenderBackend 的抽象接口绘制图片 + // 使用 RenderBackend 的抽象接口绘制图片 // 不依赖任何特定后端(如 OpenGL) // 自动批处理:无需手动调用 begin/endSpriteBatch @@ -79,102 +72,102 @@ public: // 参数:纹理、目标矩形、源矩形、颜色、旋转角度、锚点 Rect destRect(x, y, displayWidth, displayHeight); Rect srcRect(0, 0, imgWidth, imgHeight); - renderer.drawSprite(*texture_, destRect, srcRect, Colors::White, 0.0f, Vec2(0, 0)); + renderer.drawSprite(*texture_, destRect, srcRect, Colors::White, 0.0f, + Vec2(0, 0)); // 注意:无需手动调用 renderer.endSpriteBatch(),帧结束时会自动刷新 - } + } - void setRenderer(RenderBackend* renderer) { - renderer_ = renderer; - } + void setRenderer(RenderBackend *renderer) { renderer_ = renderer; } private: - Ptr texture_; - RenderBackend* renderer_ = nullptr; + Ptr texture_; + RenderBackend *renderer_ = nullptr; }; -int main(int argc, char* argv[]) { - (void)argc; - (void)argv; +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; - std::cout << "Extra2D Image Display Demo - Starting..." << std::endl; + std::cout << "Extra2D Image Display Demo - Starting..." << std::endl; - Application& app = Application::get(); + Application &app = Application::get(); - // 注册模块 - app.use([](auto& cfg) { - cfg.w = 1280; - cfg.h = 720; - cfg.title = "Extra2D Image Display Demo"; - cfg.priority = 0; - cfg.backend = "glfw"; + // 注册模块 + app.use([](auto &cfg) { + cfg.w = 1280; + cfg.h = 720; + cfg.title = "Extra2D Image Display Demo"; + cfg.priority = 0; + cfg.backend = "glfw"; + }); + + app.use([](auto &cfg) { cfg.priority = 10; }); + + app.use([](auto &cfg) { cfg.priority = 20; }); + + std::cout << "Initializing application..." << std::endl; + if (!app.init()) { + std::cerr << "Failed to initialize application!" << std::endl; + return -1; + } + + std::cout << "Application initialized successfully!" << std::endl; + + auto *win = app.window(); + if (win) { + std::cout << "Window: " << win->width() << "x" << win->height() + << std::endl; + } + + // 设置事件监听 + auto eventService = ServiceLocator::instance().getService(); + if (eventService) { + eventService->addListener(EventType::KeyPressed, [](Event &e) { + auto &keyEvent = std::get(e.data); + if (keyEvent.keyCode == static_cast(Key::Escape)) { + e.handled = true; + Application::get().quit(); + } }); + } - app.use([](auto& cfg) { cfg.priority = 10; }); - - app.use([](auto& cfg) { cfg.priority = 20; }); - - std::cout << "Initializing application..." << std::endl; - if (!app.init()) { - std::cerr << "Failed to initialize application!" << std::endl; - return -1; - } - - std::cout << "Application initialized successfully!" << std::endl; - - auto* win = app.window(); - if (win) { - std::cout << "Window: " << win->width() << "x" << win->height() << std::endl; - } - - // 设置事件监听 - auto eventService = ServiceLocator::instance().getService(); - if (eventService) { - eventService->addListener(EventType::KeyPressed, [](Event& e) { - auto& keyEvent = std::get(e.data); - if (keyEvent.keyCode == static_cast(Key::Escape)) { - e.handled = true; - Application::get().quit(); - } - }); - } - - // 获取渲染器 - RenderBackend* renderer = app.renderer(); + // 获取渲染器 + RenderBackend *renderer = app.renderer(); // 创建并配置场景 auto scene = makeShared(); scene->setRenderer(renderer); - scene->setBackgroundColor(Color(0.1f, 0.1f, 0.15f, 1.0f)); + scene->setBackgroundColor(Color(0.1f, 0.1f, 0.15f, 1.0f)); - if (win) { - scene->setViewportSize(static_cast(win->width()), - static_cast(win->height())); - } + if (win) { + scene->setViewportSize(static_cast(win->width()), + static_cast(win->height())); + } - // 配置相机 - auto cameraService = ServiceLocator::instance().getService(); - if (cameraService && win) { - ViewportConfig vpConfig; - vpConfig.logicWidth = static_cast(win->width()); - vpConfig.logicHeight = static_cast(win->height()); - vpConfig.mode = ViewportMode::AspectRatio; - cameraService->setViewportConfig(vpConfig); - cameraService->updateViewport(win->width(), win->height()); - cameraService->applyViewportAdapter(); - } + // 配置相机 + auto cameraService = ServiceLocator::instance().getService(); + if (cameraService && win) { + ViewportConfig vpConfig; + vpConfig.logicWidth = static_cast(win->width()); + vpConfig.logicHeight = static_cast(win->height()); + vpConfig.mode = ViewportMode::AspectRatio; + cameraService->setViewportConfig(vpConfig); + cameraService->updateViewport(win->width(), win->height()); + cameraService->applyViewportAdapter(); + } - app.enterScene(scene); + app.enterScene(scene); - std::cout << "\nControls:" << std::endl; - std::cout << " ESC - Exit" << std::endl; - std::cout << "\nRunning main loop...\n" << std::endl; + std::cout << "\nControls:" << std::endl; + std::cout << " ESC - Exit" << std::endl; + std::cout << "\nRunning main loop...\n" << std::endl; - app.run(); + app.run(); - std::cout << "Shutting down..." << std::endl; - app.shutdown(); + std::cout << "Shutting down..." << std::endl; + app.shutdown(); - std::cout << "Goodbye!" << std::endl; - return 0; + std::cout << "Goodbye!" << std::endl; + return 0; }