diff --git a/Extra2D/include/extra2d/render/core/render_module.h b/Extra2D/include/extra2d/render/core/render_module.h index 4480c18..b3165be 100644 --- a/Extra2D/include/extra2d/render/core/render_module.h +++ b/Extra2D/include/extra2d/render/core/render_module.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace extra2d { @@ -14,43 +15,44 @@ class Renderer; * @brief 渲染模块配置 */ struct RenderModuleConfig { - rhi::GraphicsAPI api = rhi::GraphicsAPI::OpenGL; - bool vsync = true; - uint32_t maxBatchSize = 10000; - bool enableDebug = false; - float designWidth = 1280.0f; - float designHeight = 720.0f; + rhi::GraphicsAPI api = rhi::GraphicsAPI::OpenGL; + bool vsync = true; + uint32_t maxBatchSize = 10000; + bool enableDebug = false; + float designWidth = 1280.0f; + float designHeight = 720.0f; + int priority = 10; - RenderModuleConfig() = default; + RenderModuleConfig() = default; - /** - * @brief 创建 OpenGL 配置 - */ - static RenderModuleConfig opengl() { - RenderModuleConfig config; - config.api = rhi::GraphicsAPI::OpenGL; - return config; - } + /** + * @brief 创建 OpenGL 配置 + */ + static RenderModuleConfig opengl() { + RenderModuleConfig config; + config.api = rhi::GraphicsAPI::OpenGL; + return config; + } - /** - * @brief 创建 HD 配置 (1280x720) - */ - static RenderModuleConfig hd() { - RenderModuleConfig config; - config.designWidth = 1280.0f; - config.designHeight = 720.0f; - return config; - } + /** + * @brief 创建 HD 配置 (1280x720) + */ + static RenderModuleConfig hd() { + RenderModuleConfig config; + config.designWidth = 1280.0f; + config.designHeight = 720.0f; + return config; + } - /** - * @brief 创建 Full HD 配置 (1920x1080) - */ - static RenderModuleConfig fullHd() { - RenderModuleConfig config; - config.designWidth = 1920.0f; - config.designHeight = 1080.0f; - return config; - } + /** + * @brief 创建 Full HD 配置 (1920x1080) + */ + static RenderModuleConfig fullHd() { + RenderModuleConfig config; + config.designWidth = 1920.0f; + config.designHeight = 1080.0f; + return config; + } }; /** @@ -61,85 +63,96 @@ struct RenderModuleConfig { */ class RenderModule : public Module { public: - RenderModule(); - explicit RenderModule(const RenderModuleConfig& config); - ~RenderModule() override; + /** + * @brief 构造函数(Lambda 配置) + * @param configFn 配置函数 + */ + explicit RenderModule(std::function configFn); - // ======================================================================== - // Module 接口实现 - // ======================================================================== + RenderModule(); + explicit RenderModule(const RenderModuleConfig &config); + ~RenderModule() override; - /** - * @brief 初始化模块 - */ - bool init() override; + // ======================================================================== + // Module 接口实现 + // ======================================================================== - /** - * @brief 关闭模块 - */ - void shutdown() override; + /** + * @brief 初始化模块 + */ + bool init() override; - /** - * @brief 检查模块是否就绪 - */ - bool ok() const override { return initialized_; } + /** + * @brief 关闭模块 + */ + void shutdown() override; - /** - * @brief 获取模块名称 - */ - const char* name() const override { return "RenderModule"; } + /** + * @brief 检查模块是否就绪 + */ + bool ok() const override { return initialized_; } - /** - * @brief 获取模块优先级 - */ - int priority() const override { return 10; } + /** + * @brief 获取模块名称 + */ + const char *name() const override { return "RenderModule"; } - /** - * @brief 获取模块依赖 - */ - std::vector deps() const override; + /** + * @brief 获取模块优先级 + */ + int priority() const override { return config_.priority; } - // ======================================================================== - // 渲染器访问 - // ======================================================================== + /** + * @brief 获取模块依赖 + */ + std::vector deps() const override; - /** - * @brief 获取渲染器 - */ - class Renderer* getRenderer() const { return renderer_.get(); } + /** + * @brief 禁用并行初始化(OpenGL 上下文需要在主线程) + */ + bool allowParallelInit() const override { return false; } - /** - * @brief 获取渲染器(智能指针) - */ - Ptr getRendererPtr() const { return renderer_; } + // ======================================================================== + // 渲染器访问 + // ======================================================================== - // ======================================================================== - // 配置 - // ======================================================================== + /** + * @brief 获取渲染器 + */ + class Renderer *getRenderer() const { return renderer_.get(); } - /** - * @brief 获取配置 - */ - const RenderModuleConfig& getConfig() const { return config_; } + /** + * @brief 获取渲染器(智能指针) + */ + Ptr getRendererPtr() const { return renderer_; } - /** - * @brief 设置配置 - */ - void setConfig(const RenderModuleConfig& config); + // ======================================================================== + // 配置 + // ======================================================================== - // ======================================================================== - // 静态工厂 - // ======================================================================== + /** + * @brief 获取配置 + */ + const RenderModuleConfig &getConfig() const { return config_; } - /** - * @brief 创建渲染模块 - */ - static Ptr create(const RenderModuleConfig& config = {}); + /** + * @brief 设置配置 + */ + void setConfig(const RenderModuleConfig &config); + + // ======================================================================== + // 静态工厂 + // ======================================================================== + + /** + * @brief 创建渲染模块 + */ + static Ptr create(const RenderModuleConfig &config = {}); private: - RenderModuleConfig config_; - Ptr renderer_; - bool initialized_; + RenderModuleConfig config_; + Ptr renderer_; + bool initialized_; }; } // namespace extra2d diff --git a/Extra2D/shaders/backends/opengl/builtin/sdf_font.frag b/Extra2D/shaders/backends/opengl/builtin/sdf_font.frag index 2bfb3d2..5320ed5 100644 --- a/Extra2D/shaders/backends/opengl/builtin/sdf_font.frag +++ b/Extra2D/shaders/backends/opengl/builtin/sdf_font.frag @@ -1,5 +1,4 @@ -#version 300 es -precision highp float; +#version 450 core in vec2 v_texCoord; in vec4 v_color; @@ -13,26 +12,19 @@ uniform vec2 u_textureSize; out vec4 fragColor; void main() { - // 采样 SDF 纹理(SDF 值存储在 alpha 通道,范围 0-255 已映射到 0-1) float sdfValue = texture(u_texture, v_texCoord).a; - // 使用 fwidth 计算屏幕空间的变化率 float fw = fwidth(sdfValue); - // 平衡的抗锯齿:根据屏幕空间变化率调整平滑范围 - // 在放大时更平滑,缩小时更锐利 float smoothRange = max(u_sdfSmoothness, fw * 0.5); - // 使用 smoothstep 进行抗锯齿 float alpha = smoothstep(u_sdfThreshold - smoothRange, u_sdfThreshold + smoothRange, sdfValue); - // 应用颜色和透明度 fragColor = v_color; fragColor.a *= alpha * u_opacity; - // 丢弃完全透明的像素 if (fragColor.a < 0.001) { discard; } diff --git a/Extra2D/shaders/backends/opengl/builtin/shape.frag b/Extra2D/shaders/backends/opengl/builtin/shape.frag index 1986612..37eb852 100644 --- a/Extra2D/shaders/backends/opengl/builtin/shape.frag +++ b/Extra2D/shaders/backends/opengl/builtin/shape.frag @@ -1,5 +1,4 @@ -#version 300 es -precision highp float; +#version 450 core in vec4 v_color; diff --git a/Extra2D/shaders/backends/opengl/builtin/shape.vert b/Extra2D/shaders/backends/opengl/builtin/shape.vert index b010cde..0a335dc 100644 --- a/Extra2D/shaders/backends/opengl/builtin/shape.vert +++ b/Extra2D/shaders/backends/opengl/builtin/shape.vert @@ -1,5 +1,4 @@ -#version 300 es -precision highp float; +#version 450 core layout(location = 0) in vec2 a_position; layout(location = 1) in vec4 a_color; diff --git a/Extra2D/shaders/backends/opengl/builtin/sprite.frag b/Extra2D/shaders/backends/opengl/builtin/sprite.frag index 0767df0..ab8e454 100644 --- a/Extra2D/shaders/backends/opengl/builtin/sprite.frag +++ b/Extra2D/shaders/backends/opengl/builtin/sprite.frag @@ -1,5 +1,4 @@ -#version 300 es -precision highp float; +#version 450 core in vec2 v_texCoord; in vec4 v_color; diff --git a/Extra2D/shaders/backends/opengl/builtin/sprite.vert b/Extra2D/shaders/backends/opengl/builtin/sprite.vert index f7a9adb..9c2c99c 100644 --- a/Extra2D/shaders/backends/opengl/builtin/sprite.vert +++ b/Extra2D/shaders/backends/opengl/builtin/sprite.vert @@ -1,5 +1,4 @@ -#version 300 es -precision highp float; +#version 450 core layout(location = 0) in vec2 a_position; layout(location = 1) in vec2 a_texCoord; diff --git a/Extra2D/src/platform/backends/sdl2/sdl2_window.cpp b/Extra2D/src/platform/backends/sdl2/sdl2_window.cpp index 3db155e..88727f7 100644 --- a/Extra2D/src/platform/backends/sdl2/sdl2_window.cpp +++ b/Extra2D/src/platform/backends/sdl2/sdl2_window.cpp @@ -30,9 +30,9 @@ bool SDL2Window::create(const std::string &title, int width, int height, flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; #endif - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); @@ -56,8 +56,8 @@ bool SDL2Window::create(const std::string &title, int width, int height, return false; } - if (!gladLoadGLES2Loader((GLADloadproc)SDL_GL_GetProcAddress)) { - E2D_LOG_ERROR("初始化 GLAD GLES2 失败"); + if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) { + E2D_LOG_ERROR("初始化 GLAD 失败"); SDL_GL_DeleteContext(glContext_); glContext_ = nullptr; SDL_DestroyWindow(sdlWindow_); diff --git a/Extra2D/src/render/core/render_context.cpp b/Extra2D/src/render/core/render_context.cpp index bbe3f01..8aa033d 100644 --- a/Extra2D/src/render/core/render_context.cpp +++ b/Extra2D/src/render/core/render_context.cpp @@ -282,4 +282,11 @@ void RenderContext::initDefaultState() { scissorEnabled_ = false; } +void RenderContext::resetStats() { + stats_.reset(); + if (device_) { + device_->resetStats(); + } +} + } // namespace extra2d diff --git a/Extra2D/src/render/render_module.cpp b/Extra2D/src/render/render_module.cpp index 75c0716..852fff3 100644 --- a/Extra2D/src/render/render_module.cpp +++ b/Extra2D/src/render/render_module.cpp @@ -8,6 +8,13 @@ namespace extra2d { +RenderModule::RenderModule(std::function configFn) + : initialized_(false) { + if (configFn) { + configFn(config_); + } +} + RenderModule::RenderModule() : initialized_(false) {} RenderModule::RenderModule(const RenderModuleConfig &config) @@ -24,7 +31,15 @@ bool RenderModule::init() { return false; } - IWindow *window = nullptr; + auto *winModule = app_->get(); + if (!winModule) { + return false; + } + + IWindow *window = winModule->win(); + if (!window) { + return false; + } renderer_ = Renderer::create(); @@ -40,7 +55,10 @@ bool RenderModule::init() { rendererConfig.viewportConfig = ViewportConfig(config_.designWidth, config_.designHeight); - renderer_->setConfig(rendererConfig); + if (!renderer_->init(window, rendererConfig)) { + renderer_.reset(); + return false; + } initialized_ = true; return true; diff --git a/Extra2D/src/render/renderer.cpp b/Extra2D/src/render/renderer.cpp index 388dbe4..cc4ad38 100644 --- a/Extra2D/src/render/renderer.cpp +++ b/Extra2D/src/render/renderer.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include namespace extra2d { @@ -57,6 +58,13 @@ bool Renderer::init(IWindow *window, const RendererConfig &config) { return false; } + auto& shaderManager = ShaderManager::getInstance(); + if (!shaderManager.isInitialized()) { + if (!shaderManager.init(context_->getDevice(), "shaders")) { + return false; + } + } + if (!createBatchers()) { return false; } diff --git a/Extra2D/src/resources/shader_manager.cpp b/Extra2D/src/resources/shader_manager.cpp index 67e7e9d..8e2a15c 100644 --- a/Extra2D/src/resources/shader_manager.cpp +++ b/Extra2D/src/resources/shader_manager.cpp @@ -156,9 +156,8 @@ ResourceHandle ShaderManager::loadFromMetadata(const std::string& js metadata.name = name; metadataCache_[name] = metadata; - fs::path jsonDir = fs::path(jsonPath).parent_path(); - fs::path fullVertPath = jsonDir / vertPath; - fs::path fullFragPath = jsonDir / fragPath; + fs::path fullVertPath = fs::path(shaderDir_) / vertPath; + fs::path fullFragPath = fs::path(shaderDir_) / fragPath; auto handle = loadFromFiles(name, fullVertPath.string(), fullFragPath.string()); if (handle) { diff --git a/examples/text_rendering/main.cpp b/examples/text_rendering/main.cpp index c3017d5..92e68f1 100644 --- a/examples/text_rendering/main.cpp +++ b/examples/text_rendering/main.cpp @@ -2,8 +2,7 @@ * @file main.cpp * @brief Extra2D 文字渲染示例 * - * 演示如何使用 RenderBackend 抽象接口渲染文字 - * 此示例不依赖任何特定渲染后端(如 OpenGL) + * 演示如何使用 RenderModule 渲染文字 */ #include @@ -14,99 +13,118 @@ using namespace extra2d; class TextRenderingScene : public Scene { public: void onEnter() override { - // 加载字体 - // 注意:请确保有字体文件在 assets/fonts/ 目录下 - // 如果没有,可以使用系统字体路径 - if (!renderer_) { + auto &fontManager = FontManager::getInstance(); + auto *renderMod = Application::get().get(); + if (!renderMod) { + std::cerr << "RenderModule not available!" << std::endl; + return; + } + + auto *renderer = renderMod->getRenderer(); + if (!renderer) { std::cerr << "Renderer not available!" << std::endl; return; } - try { - font_ = renderer_->createFontAtlas("assets/fonts/fonts.ttf", 26, true); - } catch (...) { + auto *context = renderer->getContext(); + if (!context) { + std::cerr << "RenderContext not available!" << std::endl; + return; + } + + if (!fontManager.isInitialized()) { + fontManager.init(context->getDevice()); + } + + fontHandle_ = fontManager.load("assets/fonts/fonts.ttf", + {.fontSize = 26, .useSDF = true}); + if (fontHandle_) { + fontAtlas_ = fontManager.getAtlas(fontHandle_, 26); + if (fontAtlas_) { + std::cout << "Font loaded successfully!" << std::endl; + std::cout << " Font size: " << fontAtlas_->getFontSize() << std::endl; + std::cout << " Line height: " << fontAtlas_->getLineHeight() + << std::endl; + std::cout << " Ascent: " << fontAtlas_->getAscent() << std::endl; + std::cout << " Descent: " << fontAtlas_->getDescent() << std::endl; + } + } else { std::cerr << "Failed to load font from assets/fonts/fonts.ttf" << std::endl; } - - if (font_) { - std::cout << "Font loaded successfully!" << std::endl; - std::cout << " Font size: " << font_->getFontSize() << std::endl; - std::cout << " Line height: " << font_->getLineHeight() << std::endl; - std::cout << " Ascent: " << font_->getAscent() << std::endl; - std::cout << " Descent: " << font_->getDescent() << std::endl; - } } - void onExit() override { font_.reset(); } + void onExit() override { + fontAtlas_.reset(); + fontHandle_.reset(); + } void onRender(RenderBackend &renderer) override { Scene::onRender(renderer); - if (!font_) { + if (!fontAtlas_) { return; } float y = 100.0f; float x = 100.0f; + float fontSize = 26.0f; - renderText(renderer, "Extra2D Text Rendering Demo", x, y, + renderText(renderer, "Extra2D Text Rendering Demo", x, y, fontSize, Color(1.0f, 0.8f, 0.2f, 1.0f)); - y += font_->getLineHeight() * 2; + y += fontAtlas_->getLineHeight() * 2; - // 渲染不同颜色的文字 - renderText(renderer, "Red Text", x, y, Color(1.0f, 0.2f, 0.2f, 1.0f)); - y += font_->getLineHeight(); + renderText(renderer, "Red Text", x, y, fontSize, + Color(1.0f, 0.2f, 0.2f, 1.0f)); + y += fontAtlas_->getLineHeight(); - renderText(renderer, "Green Text", x, y, Color(0.2f, 1.0f, 0.2f, 1.0f)); - y += font_->getLineHeight(); + renderText(renderer, "Green Text", x, y, fontSize, + Color(0.2f, 1.0f, 0.2f, 1.0f)); + y += fontAtlas_->getLineHeight(); - renderText(renderer, "Blue Text", x, y, Color(0.2f, 0.2f, 1.0f, 1.0f)); - y += font_->getLineHeight() * 2; + renderText(renderer, "Blue Text", x, y, fontSize, + Color(0.2f, 0.2f, 1.0f, 1.0f)); + y += fontAtlas_->getLineHeight() * 2; - // 渲染多行文字 - renderText(renderer, "This is a multi-line text example.", x, y, + renderText(renderer, "This is a multi-line text example.", x, y, fontSize, Color(1.0f, 1.0f, 1.0f, 1.0f)); - y += font_->getLineHeight(); + y += fontAtlas_->getLineHeight(); renderText(renderer, "You can render text with different colors", x, y, - Color(0.8f, 0.8f, 0.8f, 1.0f)); - y += font_->getLineHeight(); - renderText(renderer, "and styles using FontAtlas.", x, y, + fontSize, Color(0.8f, 0.8f, 0.8f, 1.0f)); + y += fontAtlas_->getLineHeight(); + renderText(renderer, "and styles using FontAtlas.", x, y, fontSize, Color(0.6f, 0.6f, 0.6f, 1.0f)); - y += font_->getLineHeight() * 2; + y += fontAtlas_->getLineHeight() * 2; - // 渲染半透明文字 - renderText(renderer, "Semi-transparent text (50% opacity)", x, y, + renderText(renderer, "Semi-transparent text (50% opacity)", x, y, fontSize, Color(1.0f, 1.0f, 1.0f, 0.5f)); - y += font_->getLineHeight() * 2; + y += fontAtlas_->getLineHeight() * 2; - // 渲染操作提示 - renderText(renderer, "Press ESC to exit", x, y, + renderText(renderer, "Press ESC to exit", x, y, fontSize, Color(0.5f, 0.5f, 0.5f, 1.0f)); } - void setRenderer(RenderBackend *renderer) { renderer_ = renderer; } - private: + /** + * @brief 渲染文本 + */ void renderText(RenderBackend &renderer, const std::string &text, float x, - float y, const Color &color) { - if (!font_) { + float y, float fontSize, const Color &color) { + if (!fontAtlas_) { return; } - // 使用 RenderBackend 的 drawText 方法 - renderer.drawText(*font_, text, Vec2(x, y), color); + renderer.drawText(text, Vec2(x, y), fontSize, color); } - Ptr font_; - RenderBackend *renderer_ = nullptr; + FontHandle fontHandle_; + Ptr fontAtlas_; }; int main(int argc, char *argv[]) { Application &app = Application::get(); - // 注册模块 app.use([](auto &cfg) { cfg.w = 1280; cfg.h = 720; @@ -115,7 +133,7 @@ int main(int argc, char *argv[]) { cfg.backend = "sdl2"; }); - app.use([](auto &cfg) { cfg.priority = 10; }); + app.use([](auto &cfg) { cfg.api = rhi::GraphicsAPI::OpenGL; }); app.use([](auto &cfg) { cfg.priority = 20; }); @@ -129,7 +147,6 @@ int main(int argc, char *argv[]) { E2D_LOG_INFO("Window :{} x {}", win->width(), win->height()); } - // 设置事件监听 auto eventService = ServiceLocator::instance().getService(); if (eventService) { eventService->addListener(EventType::KeyPressed, [](Event &e) { @@ -141,12 +158,7 @@ int main(int argc, char *argv[]) { }); } - // 获取渲染器 - RenderBackend *renderer = app.renderer(); - - // 创建并配置场景 auto scene = makeShared(); - scene->setRenderer(renderer); scene->setBackgroundColor(Color(0.1f, 0.1f, 0.15f, 1.0f)); if (win) { @@ -154,13 +166,12 @@ int main(int argc, char *argv[]) { static_cast(win->height())); } - // 配置相机 auto cameraService = ServiceLocator::instance().getService(); if (cameraService && win) { cameraService->setViewportConfig([&](auto &cfg) { - cfg.logicWidth = static_cast(win->width()); - cfg.logicHeight = static_cast(win->height()); - cfg.mode = ViewportMode::AspectRatio; + cfg.designWidth = static_cast(win->width()); + cfg.designHeight = static_cast(win->height()); + cfg.scaleMode = ViewportScaleMode::Letterbox; }); cameraService->updateViewport(win->width(), win->height()); cameraService->applyViewportAdapter();