From e6007301051013f55c12f0cbbda60d3df0672f95 Mon Sep 17 00:00:00 2001 From: ChestnutYueyue <952134128@qq.com> Date: Mon, 23 Feb 2026 01:24:27 +0800 Subject: [PATCH] =?UTF-8?q?refactor(render):=20=E9=87=8D=E6=9E=84=E6=B8=B2?= =?UTF-8?q?=E6=9F=93=E7=B3=BB=E7=BB=9F=EF=BC=8C=E6=95=B4=E5=90=88=E7=BA=B9?= =?UTF-8?q?=E7=90=86=E3=80=81=E7=9B=B8=E6=9C=BA=E5=92=8C=E6=B8=B2=E6=9F=93?= =?UTF-8?q?=E5=99=A8=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat(render): 新增Texture类封装OpenGL纹理操作 feat(render): 新增Camera类提供2D视图投影矩阵计算 feat(render): 新增Renderer类整合图形和精灵渲染功能 refactor(window): 简化Window类实现,移除冗余功能 refactor(app): 重构Application类,简化主循环逻辑 refactor(scene): 重构场景和节点系统,适配新渲染接口 fix(assets): 修复资源管理相关头文件包含问题 chore(build): 更新xmake构建配置,移除调试宏定义 style: 统一代码格式,修复头文件合并冲突 --- Extra2D/include/extra2d/app/application.h | 117 +--- Extra2D/include/extra2d/extra2d.h | 26 +- Extra2D/include/extra2d/render/camera.h | 223 +++++++ .../include/extra2d/render/render_context.h | 8 +- .../include/extra2d/render/render_device.h | 298 +++++---- Extra2D/include/extra2d/render/render_types.h | 402 +++++------ Extra2D/include/extra2d/render/renderer.h | 153 +++++ Extra2D/include/extra2d/render/texture.h | 108 +++ Extra2D/include/extra2d/scene/node.h | 150 +---- Extra2D/include/extra2d/scene/scene.h | 123 ++-- Extra2D/include/extra2d/scene/scene_manager.h | 64 +- Extra2D/include/extra2d/scene/shape_node.h | 112 ++-- Extra2D/include/extra2d/scene/sprite.h | 60 +- .../include/extra2d/services/logger_service.h | 205 ++---- Extra2D/include/extra2d/utils/logger.h | 270 -------- Extra2D/include/extra2d/window/window.h | 76 +-- Extra2D/src/app/application.cpp | 168 ++--- Extra2D/src/audio/audio_engine.cpp | 2 +- Extra2D/src/audio/sound.cpp | 2 +- Extra2D/src/graphics/opengl/gl_font_atlas.cpp | 285 -------- Extra2D/src/graphics/opengl/gl_renderer.cpp | 629 ------------------ Extra2D/src/render/render_context.cpp | 286 ++++---- Extra2D/src/render/render_device.cpp | 548 ++++++++------- Extra2D/src/render/renderer.cpp | 219 ++++++ Extra2D/src/render/texture.cpp | 189 ++++++ Extra2D/src/scene/node.cpp | 619 ++++++++--------- Extra2D/src/scene/scene.cpp | 165 +++-- Extra2D/src/scene/scene_manager.cpp | 345 +++++----- Extra2D/src/scene/shape_node.cpp | 482 ++++++-------- Extra2D/src/scene/sprite.cpp | 211 +++--- Extra2D/src/services/logger_service.cpp | 397 ++++++----- Extra2D/src/utils/data.cpp | 2 +- Extra2D/src/utils/logger.cpp | 104 --- Extra2D/src/utils/object_pool.cpp | 9 - Extra2D/src/window/window.cpp | 118 +--- xmake/engine.lua | 2 +- 36 files changed, 3038 insertions(+), 4139 deletions(-) create mode 100644 Extra2D/include/extra2d/render/camera.h create mode 100644 Extra2D/include/extra2d/render/renderer.h create mode 100644 Extra2D/include/extra2d/render/texture.h delete mode 100644 Extra2D/include/extra2d/utils/logger.h delete mode 100644 Extra2D/src/graphics/opengl/gl_font_atlas.cpp delete mode 100644 Extra2D/src/graphics/opengl/gl_renderer.cpp create mode 100644 Extra2D/src/render/renderer.cpp create mode 100644 Extra2D/src/render/texture.cpp delete mode 100644 Extra2D/src/utils/logger.cpp delete mode 100644 Extra2D/src/utils/object_pool.cpp diff --git a/Extra2D/include/extra2d/app/application.h b/Extra2D/include/extra2d/app/application.h index 52774e5..ca3e549 100644 --- a/Extra2D/include/extra2d/app/application.h +++ b/Extra2D/include/extra2d/app/application.h @@ -1,113 +1,58 @@ #pragma once -#include -#include #include #include #include namespace extra2d { -class GLFWWindow; -class WindowModule; +class Window; /** * @brief 应用程序类 */ class Application { public: - static Application &get(); + static Application& instance(); - Application(const Application &) = delete; - Application &operator=(const Application &) = delete; + Application(const Application&) = delete; + Application& operator=(const Application&) = delete; - /** - * @brief 应用信息 - */ - std::string appName = "Extra2D App"; - std::string appVersion = "1.0.0"; - std::string organization = ""; + std::string name = "Extra2D App"; + std::string version = "1.0.0"; - /** - * @brief 注册模块 - * @tparam T 模块类型 - * @tparam Args 构造函数参数 - * @return 模块指针 - */ - template T *use(Args &&...args) { - return Registry::instance().use(std::forward(args)...); - } + bool init(); + void shutdown(); + void run(); + void quit(); - /** - * @brief 获取模块 - * @tparam T 模块类型 - * @return 模块指针 - */ - template T *get() const { return Registry::instance().get(); } + bool paused() const { return paused_; } + bool running() const { return running_; } + Window* window() const { return window_; } - /** - * @brief 初始化 - * @return 初始化成功返回 true - */ - bool init(); - - /** - * @brief 关闭 - */ - void shutdown(); - - /** - * @brief 运行主循环 - */ - void run(); - - /** - * @brief 请求退出 - */ - void quit(); - - /** - * @brief 暂停 - */ - void pause(); - - /** - * @brief 恢复 - */ - void resume(); - - bool paused() const { return paused_; } - bool running() const { return running_; } - - /** - * @brief 获取窗口 - * @return 窗口指针 - */ - GLFWWindow *window(); - - f32 dt() const { return dt_; } - f32 totalTime() const { return totalTime_; } - int fps() const { return fps_; } + f32 dt() const { return dt_; } + f32 totalTime() const { return totalTime_; } + int fps() const { return fps_; } private: - Application(); - ~Application(); + Application() = default; + ~Application(); - void mainLoop(); - void update(); - void render(); + void mainLoop(); - bool initialized_ = false; - bool running_ = false; - bool paused_ = false; - bool shouldQuit_ = false; + bool initialized_ = false; + bool running_ = false; + bool paused_ = false; + Window* window_ = nullptr; - f32 dt_ = 0.0f; - f32 totalTime_ = 0.0f; - f64 lastFrameTime_ = 0.0; - int frameCount_ = 0; - f32 fpsTimer_ = 0.0f; - int fps_ = 0; + f32 dt_ = 0.0f; + f32 totalTime_ = 0.0f; + u64 lastFrameTime_ = 0; + int frameCount_ = 0; + f32 fpsTimer_ = 0.0f; + int fps_ = 0; }; +#define E2D_APP() ::extra2d::Application::instance() + } // namespace extra2d diff --git a/Extra2D/include/extra2d/extra2d.h b/Extra2D/include/extra2d/extra2d.h index e0bfe3d..c5871f4 100644 --- a/Extra2D/include/extra2d/extra2d.h +++ b/Extra2D/include/extra2d/extra2d.h @@ -6,10 +6,16 @@ // Core #include #include -<<<<<<< HEAD +#include +#include #include #include +// Platform +#include +#include +#include + // Window - SDL2 + OpenGL #include @@ -31,22 +37,11 @@ #include #include #include -======= -#include -#include -#include - -// Platform -#include -#include -#include ->>>>>>> 9bf328b1dca01df84a07724394abc9a238739869 // Event #include #include #include -<<<<<<< HEAD #include // Audio @@ -55,7 +50,6 @@ // Utils #include -#include #include #include @@ -64,11 +58,6 @@ #include #include #include -======= - -// Utils -#include -#include // Services #include @@ -84,7 +73,6 @@ #include #include #include ->>>>>>> 9bf328b1dca01df84a07724394abc9a238739869 // Application #include diff --git a/Extra2D/include/extra2d/render/camera.h b/Extra2D/include/extra2d/render/camera.h new file mode 100644 index 0000000..80a7b49 --- /dev/null +++ b/Extra2D/include/extra2d/render/camera.h @@ -0,0 +1,223 @@ +#pragma once + +#include +#include +#include + +namespace extra2d { + +/** + * @brief 2D 摄像机类 + * + * 提供视图和投影矩阵,支持平移、缩放和旋转 + */ +class Camera { +public: + Camera() = default; + ~Camera() = default; + + /** + * @brief 设置视口 + */ + void setViewport(int x, int y, int width, int height) { + viewportX_ = x; + viewportY_ = y; + viewportWidth_ = width; + viewportHeight_ = height; + dirty_ = true; + } + + /** + * @brief 设置位置 + */ + void setPosition(const Vec2& pos) { + position_ = pos; + dirty_ = true; + } + + /** + * @brief 设置缩放 + */ + void setZoom(float zoom) { + zoom_ = zoom; + dirty_ = true; + } + + /** + * @brief 设置旋转角度(度数) + */ + void setRotation(float degrees) { + rotation_ = degrees; + dirty_ = true; + } + + /** + * @brief 移动摄像机 + */ + void move(const Vec2& delta) { + position_ += delta; + dirty_ = true; + } + + /** + * @brief 缩放摄像机 + */ + void zoom(float factor) { + zoom_ *= factor; + dirty_ = true; + } + + /** + * @brief 旋转摄像机 + */ + void rotate(float degrees) { + rotation_ += degrees; + dirty_ = true; + } + + /** + * @brief 获取位置 + */ + const Vec2& position() const { return position_; } + + /** + * @brief 获取缩放 + */ + float zoom() const { return zoom_; } + + /** + * @brief 获取旋转角度 + */ + float rotation() const { return rotation_; } + + /** + * @brief 获取视图矩阵 + */ + const glm::mat4& viewMatrix() const { + if (dirty_) { + updateMatrices(); + } + return viewMatrix_; + } + + /** + * @brief 获取投影矩阵 + */ + const glm::mat4& projectionMatrix() const { + if (dirty_) { + updateMatrices(); + } + return projectionMatrix_; + } + + /** + * @brief 获取视图投影矩阵 + */ + const glm::mat4& viewProjectionMatrix() const { + if (dirty_) { + updateMatrices(); + } + return viewProjectionMatrix_; + } + + /** + * @brief 获取视图投影矩阵(便捷方法) + */ + const glm::mat4& getViewProjectionMatrix() { + if (dirty_) { + updateMatrices(); + } + return viewProjectionMatrix_; + } + + /** + * @brief 屏幕坐标转世界坐标 + */ + Vec2 screenToWorld(const Vec2& screenPos) const { + if (dirty_) { + updateMatrices(); + } + + glm::vec4 ndc( + (screenPos.x - viewportX_) / viewportWidth_ * 2.0f - 1.0f, + 1.0f - (screenPos.y - viewportY_) / viewportHeight_ * 2.0f, + 0.0f, 1.0f + ); + + glm::mat4 invVP = glm::inverse(viewProjectionMatrix_); + glm::vec4 world = invVP * ndc; + + return Vec2(world.x, world.y); + } + + /** + * @brief 世界坐标转屏幕坐标 + */ + Vec2 worldToScreen(const Vec2& worldPos) const { + if (dirty_) { + updateMatrices(); + } + + glm::vec4 clip = viewProjectionMatrix_ * glm::vec4(worldPos.x, worldPos.y, 0.0f, 1.0f); + glm::vec3 ndc(clip.x / clip.w, clip.y / clip.w, clip.z / clip.w); + + return Vec2( + (ndc.x + 1.0f) * 0.5f * viewportWidth_ + viewportX_, + (1.0f - ndc.y) * 0.5f * viewportHeight_ + viewportY_ + ); + } + + /** + * @brief 获取视口宽度 + */ + int viewportWidth() const { return viewportWidth_; } + + /** + * @brief 获取视口高度 + */ + int viewportHeight() const { return viewportHeight_; } + +private: + void updateMatrices() const { + glm::vec3 eye(position_.x, position_.y, 0.0f); + glm::vec3 center(position_.x, position_.y, -1.0f); + glm::vec3 up(0.0f, 1.0f, 0.0f); + + viewMatrix_ = glm::lookAt(eye, center, up); + + if (rotation_ != 0.0f) { + glm::mat4 rot = glm::rotate(glm::mat4(1.0f), + rotation_ * 3.14159265f / 180.0f, + glm::vec3(0.0f, 0.0f, 1.0f)); + viewMatrix_ = rot * viewMatrix_; + } + + if (zoom_ != 1.0f) { + viewMatrix_ = glm::scale(glm::mat4(1.0f), + glm::vec3(zoom_, zoom_, 1.0f)) * viewMatrix_; + } + + float halfW = viewportWidth_ * 0.5f; + float halfH = viewportHeight_ * 0.5f; + projectionMatrix_ = glm::ortho(-halfW, halfW, -halfH, halfH, -1.0f, 1.0f); + + viewProjectionMatrix_ = projectionMatrix_ * viewMatrix_; + dirty_ = false; + } + + Vec2 position_; + float zoom_ = 1.0f; + float rotation_ = 0.0f; + + int viewportX_ = 0; + int viewportY_ = 0; + int viewportWidth_ = 800; + int viewportHeight_ = 600; + + mutable glm::mat4 viewMatrix_{1.0f}; + mutable glm::mat4 projectionMatrix_{1.0f}; + mutable glm::mat4 viewProjectionMatrix_{1.0f}; + mutable bool dirty_ = true; +}; + +} // namespace extra2d diff --git a/Extra2D/include/extra2d/render/render_context.h b/Extra2D/include/extra2d/render/render_context.h index 8c09a9a..1516f09 100644 --- a/Extra2D/include/extra2d/render/render_context.h +++ b/Extra2D/include/extra2d/render/render_context.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -21,8 +22,10 @@ public: /** * @brief 初始化渲染上下文 + * @param window SDL窗口指针 + * @param config 渲染设备配置 */ - bool init(); + bool init(SDL_Window *window, const RenderDeviceConfig &config = {}); /** * @brief 关闭渲染上下文 @@ -119,7 +122,7 @@ public: /** * @brief 获取渲染统计 */ - const RenderStats &stats() const { return stats_; } + const RenderStats &stats() const; /** * @brief 重置渲染统计 @@ -142,7 +145,6 @@ private: bool initialized_ = false; RenderDevice &device_ = RenderDevice::instance(); RenderQueue queue_; - RenderStats stats_; Viewport viewport_; ScissorRect scissor_; diff --git a/Extra2D/include/extra2d/render/render_device.h b/Extra2D/include/extra2d/render/render_device.h index b56f8e9..997fad2 100644 --- a/Extra2D/include/extra2d/render/render_device.h +++ b/Extra2D/include/extra2d/render/render_device.h @@ -1,7 +1,8 @@ #pragma once -#include +#include #include +#include #include #include #include @@ -12,170 +13,205 @@ namespace extra2d { * @brief 渲染能力信息 */ struct RenderCaps { - int32 maxTextureSize = 0; - int32 maxTextureUnits = 0; - int32 maxVertexAttribs = 0; - int32 maxUniformBlockBindings = 0; - int32 maxUniformBlockSize = 0; - int32 maxVertexUniformComponents = 0; - int32 maxFragmentUniformComponents = 0; - int32 maxDrawBuffers = 0; - int32 maxSamples = 0; - bool dsaSupported = false; - bool computeSupported = false; - bool tessellationSupported = false; - bool geometryShaderSupported = false; - String renderer; - String vendor; - String version; - String glslVersion; + int32 maxTextureSize = 0; + int32 maxTextureUnits = 0; + int32 maxVertexAttribs = 0; + int32 maxUniformBlockBindings = 0; + int32 maxUniformBlockSize = 0; + int32 maxVertexUniformComponents = 0; + int32 maxFragmentUniformComponents = 0; + int32 maxDrawBuffers = 0; + int32 maxSamples = 0; + bool dsaSupported = false; + bool computeSupported = false; + bool tessellationSupported = false; + bool geometryShaderSupported = false; + String renderer; + String vendor; + String version; + String glslVersion; +}; + +/** + * @brief 渲染设备配置 + */ +struct RenderDeviceConfig { + int glMajor = 4; + int glMinor = 5; + bool useES = false; + int redBits = 8; + int greenBits = 8; + int blueBits = 8; + int alphaBits = 8; + int depthBits = 24; + int stencilBits = 8; + bool doubleBuffer = true; + int msaaSamples = 0; + bool vsync = true; }; /** * @brief 渲染设备 - * - * 封装 OpenGL 4.5 核心功能,使用 DSA API */ class RenderDevice { public: - static RenderDevice& instance(); + static RenderDevice &instance(); - /** - * @brief 初始化渲染设备 - * @return 初始化成功返回 true - */ - bool init(); + /** + * @brief 初始化 OpenGL 上下文 + */ + bool init(SDL_Window *window, const RenderDeviceConfig &config = {}); - /** - * @brief 关闭渲染设备 - */ - void shutdown(); + /** + * @brief 关闭渲染设备 + */ + void shutdown(); - /** - * @brief 检查是否已初始化 - */ - bool isInitialized() const { return initialized_; } + /** + * @brief 检查是否已初始化 + */ + bool isInitialized() const { return initialized_; } - /** - * @brief 获取渲染能力信息 - */ - const RenderCaps& caps() const { return caps_; } + /** + * @brief 获取渲染能力信息 + */ + const RenderCaps &caps() const { return caps_; } - /** - * @brief 创建缓冲区 - */ - std::unique_ptr createBuffer(BufferType type, BufferUsage usage, - size_t size, const void* data = nullptr); + /** + * @brief 获取 SDL GL 上下文 + */ + SDL_GLContext glContext() const { return glContext_; } - /** - * @brief 创建顶点缓冲区 - */ - std::unique_ptr createVertexBuffer(BufferUsage usage, size_t size, - const void* data = nullptr); + /** + * @brief 交换缓冲区 + */ + void swapBuffers(); - /** - * @brief 创建索引缓冲区 - */ - std::unique_ptr createIndexBuffer(BufferUsage usage, size_t size, - const void* data = nullptr); + /** + * @brief 设置 VSync + */ + void setVSync(bool enabled); - /** - * @brief 创建 Uniform 缓冲区 - */ - std::unique_ptr createUniformBuffer(BufferUsage usage, size_t size, - const void* data = nullptr); + /** + * @brief 创建缓冲区 + */ + std::unique_ptr createBuffer(BufferType type, BufferUsage usage, + size_t size, const void *data = nullptr); - /** - * @brief 创建 VAO - */ - std::unique_ptr createVAO(); + /** + * @brief 创建顶点缓冲区 + */ + std::unique_ptr createVertexBuffer(BufferUsage usage, + size_t size, + const void *data = nullptr); - /** - * @brief 设置视口 - */ - void setViewport(int32 x, int32 y, int32 width, int32 height); + /** + * @brief 创建索引缓冲区 + */ + std::unique_ptr createIndexBuffer(BufferUsage usage, size_t size, + const void *data = nullptr); - /** - * @brief 设置裁剪矩形 - */ - void setScissor(int32 x, int32 y, int32 width, int32 height); + /** + * @brief 创建 Uniform 缓冲区 + */ + std::unique_ptr + createUniformBuffer(BufferUsage usage, size_t size, + const void *data = nullptr); - /** - * @brief 启用/禁用裁剪测试 - */ - void setScissorEnabled(bool enabled); + /** + * @brief 创建 VAO + */ + std::unique_ptr createVAO(); - /** - * @brief 清除缓冲区 - */ - void clear(bool color, bool depth, bool stencil, - float r = 0.0f, float g = 0.0f, float b = 0.0f, float a = 1.0f); + /** + * @brief 设置视口 + */ + void setViewport(int32 x, int32 y, int32 width, int32 height); - /** - * @brief 设置混合状态 - */ - void setBlendState(const BlendState& state); + /** + * @brief 设置裁剪矩形 + */ + void setScissor(int32 x, int32 y, int32 width, int32 height); - /** - * @brief 设置深度状态 - */ - void setDepthState(const DepthState& state); + /** + * @brief 启用/禁用裁剪测试 + */ + void setScissorEnabled(bool enabled); - /** - * @brief 设置光栅化状态 - */ - void setRasterState(const RasterState& state); + /** + * @brief 清除缓冲区 + */ + void clear(bool color, bool depth, bool stencil, float r = 0.0f, + float g = 0.0f, float b = 0.0f, float a = 1.0f); - /** - * @brief 绑定纹理到纹理单元 - */ - void bindTexture(uint32 unit, GLuint texture); + /** + * @brief 设置混合状态 + */ + void setBlendState(const BlendState &state); - /** - * @brief 绑定着色器程序 - */ - void bindProgram(GLuint program); + /** + * @brief 设置深度状态 + */ + void setDepthState(const DepthState &state); - /** - * @brief 绘制数组 - */ - void drawArrays(PrimitiveType mode, int32 first, int32 count); + /** + * @brief 设置光栅化状态 + */ + void setRasterState(const RasterState &state); - /** - * @brief 绘制索引 - */ - void drawElements(PrimitiveType mode, int32 count, IndexType type, - const void* indices = nullptr); + /** + * @brief 绑定纹理到纹理单元 + */ + void bindTexture(uint32 unit, GLuint texture); - /** - * @brief 绘制实例化数组 - */ - void drawArraysInstanced(PrimitiveType mode, int32 first, int32 count, - int32 instanceCount); + /** + * @brief 绑定着色器程序 + */ + void bindProgram(GLuint program); - /** - * @brief 绘制实例化索引 - */ - void drawElementsInstanced(PrimitiveType mode, int32 count, IndexType type, - const void* indices, int32 instanceCount); + /** + * @brief 绘制数组 + */ + void drawArrays(PrimitiveType mode, int32 first, int32 count); + + /** + * @brief 绘制索引 + */ + void drawElements(PrimitiveType mode, int32 count, IndexType type, + const void *indices = nullptr); + + /** + * @brief 绘制实例化数组 + */ + void drawArraysInstanced(PrimitiveType mode, int32 first, int32 count, + int32 instanceCount); + + /** + * @brief 绘制实例化索引 + */ + void drawElementsInstanced(PrimitiveType mode, int32 count, IndexType type, + const void *indices, int32 instanceCount); private: - RenderDevice() = default; - ~RenderDevice() = default; - RenderDevice(const RenderDevice&) = delete; - RenderDevice& operator=(const RenderDevice&) = delete; + RenderDevice() = default; + ~RenderDevice() = default; + RenderDevice(const RenderDevice &) = delete; + RenderDevice &operator=(const RenderDevice &) = delete; - void queryCaps(); - GLenum glPrimitiveType(PrimitiveType mode) const; - GLenum glIndexType(IndexType type) const; + bool initGL(const RenderDeviceConfig &config); + void queryCaps(); + GLenum glPrimitiveType(PrimitiveType mode) const; + GLenum glIndexType(IndexType type) const; - bool initialized_ = false; - RenderCaps caps_; + bool initialized_ = false; + SDL_Window *window_ = nullptr; + SDL_GLContext glContext_ = nullptr; + RenderCaps caps_; - BlendState currentBlend_; - DepthState currentDepth_; - RasterState currentRaster_; - GLuint currentProgram_ = 0; + BlendState currentBlend_; + DepthState currentDepth_; + RasterState currentRaster_; + GLuint currentProgram_ = 0; }; #define E2D_RENDER_DEVICE() ::extra2d::RenderDevice::instance() diff --git a/Extra2D/include/extra2d/render/render_types.h b/Extra2D/include/extra2d/render/render_types.h index eb0409f..f730633 100644 --- a/Extra2D/include/extra2d/render/render_types.h +++ b/Extra2D/include/extra2d/render/render_types.h @@ -31,360 +31,302 @@ using uint64 = std::uint64_t; // 混合模式 // --------------------------------------------------------------------------- enum class BlendMode : uint8 { - None, - Alpha, - Additive, - Multiply, - Screen, - Custom + None, + Alpha, + Additive, + Multiply, + Screen, + Custom }; // --------------------------------------------------------------------------- // 深度比较函数 // --------------------------------------------------------------------------- enum class CompareFunc : uint8 { - Never, - Less, - Equal, - LEqual, - Greater, - NotEqual, - GEqual, - Always + Never, + Less, + Equal, + LEqual, + Greater, + NotEqual, + GEqual, + Always }; // --------------------------------------------------------------------------- // 剔除模式 // --------------------------------------------------------------------------- -enum class CullMode : uint8 { - None, - Front, - Back -}; +enum class CullMode : uint8 { None, Front, Back }; // --------------------------------------------------------------------------- // 多边形模式 // --------------------------------------------------------------------------- -enum class PolygonMode : uint8 { - Fill, - Line, - Point -}; +enum class PolygonMode : uint8 { Fill, Line, Point }; // --------------------------------------------------------------------------- // 混合因子 // --------------------------------------------------------------------------- enum class BlendFactor : uint8 { - Zero, - One, - SrcColor, - OneMinusSrcColor, - DstColor, - OneMinusDstColor, - SrcAlpha, - OneMinusSrcAlpha, - DstAlpha, - OneMinusDstAlpha, - ConstantColor, - OneMinusConstantColor, - ConstantAlpha, - OneMinusConstantAlpha + Zero, + One, + SrcColor, + OneMinusSrcColor, + DstColor, + OneMinusDstColor, + SrcAlpha, + OneMinusSrcAlpha, + DstAlpha, + OneMinusDstAlpha, + ConstantColor, + OneMinusConstantColor, + ConstantAlpha, + OneMinusConstantAlpha }; // --------------------------------------------------------------------------- // 混合操作 // --------------------------------------------------------------------------- -enum class BlendOp : uint8 { - Add, - Subtract, - ReverseSubtract, - Min, - Max -}; +enum class BlendOp : uint8 { Add, Subtract, ReverseSubtract, Min, Max }; // --------------------------------------------------------------------------- // 缓冲区类型 // --------------------------------------------------------------------------- enum class BufferType : uint8 { - Vertex, - Index, - Uniform, - PixelPack, - PixelUnpack + Vertex, + Index, + Uniform, + PixelPack, + PixelUnpack }; // --------------------------------------------------------------------------- // 缓冲区使用方式 // --------------------------------------------------------------------------- -enum class BufferUsage : uint8 { - Static, - Dynamic, - Stream -}; +enum class BufferUsage : uint8 { Static, Dynamic, Stream }; // --------------------------------------------------------------------------- // 纹理过滤模式 // --------------------------------------------------------------------------- enum class FilterMode : uint8 { - Nearest, - Linear, - NearestMipmapNearest, - LinearMipmapNearest, - NearestMipmapLinear, - LinearMipmapLinear + Nearest, + Linear, + NearestMipmapNearest, + LinearMipmapNearest, + NearestMipmapLinear, + LinearMipmapLinear }; // --------------------------------------------------------------------------- // 纹理环绕模式 // --------------------------------------------------------------------------- -enum class WrapMode : uint8 { - Repeat, - Clamp, - Mirror, - MirrorClamp, - Border -}; +enum class WrapMode : uint8 { Repeat, Clamp, Mirror, MirrorClamp, Border }; // --------------------------------------------------------------------------- // 图元类型 // --------------------------------------------------------------------------- enum class PrimitiveType : uint8 { - Points, - Lines, - LineStrip, - LineLoop, - Triangles, - TriangleStrip, - TriangleFan + Points, + Lines, + LineStrip, + LineLoop, + Triangles, + TriangleStrip, + TriangleFan }; // --------------------------------------------------------------------------- // 索引类型 // --------------------------------------------------------------------------- -enum class IndexType : uint8 { - UInt8, - UInt16, - UInt32 -}; +enum class IndexType : uint8 { UInt8, UInt16, UInt32 }; // --------------------------------------------------------------------------- // 顶点属性语义 // --------------------------------------------------------------------------- enum class VertexSemantic : uint8 { - Position, - Normal, - Tangent, - Bitangent, - Color0, - Color1, - TexCoord0, - TexCoord1, - TexCoord2, - TexCoord3, - BoneIndices, - BoneWeights + Position, + Normal, + Tangent, + Bitangent, + Color0, + Color1, + TexCoord0, + TexCoord1, + TexCoord2, + TexCoord3, + BoneIndices, + BoneWeights }; // --------------------------------------------------------------------------- // 顶点属性类型 // --------------------------------------------------------------------------- enum class VertexAttribType : uint8 { - Float, - Float2, - Float3, - Float4, - Int, - Int2, - Int3, - Int4, - UInt, - UInt2, - UInt3, - UInt4, - Byte4, - Byte4Norm, - UByte4, - UByte4Norm, - Short2, - Short2Norm, - Short4, - Short4Norm + Float, + Float2, + Float3, + Float4, + Int, + Int2, + Int3, + Int4, + UInt, + UInt2, + UInt3, + UInt4, + Byte4, + Byte4Norm, + UByte4, + UByte4Norm, + Short2, + Short2Norm, + Short4, + Short4Norm }; // --------------------------------------------------------------------------- // 混合状态 // --------------------------------------------------------------------------- struct BlendState { - bool enabled = false; - BlendMode mode = BlendMode::Alpha; - BlendFactor srcRGB = BlendFactor::SrcAlpha; - BlendFactor dstRGB = BlendFactor::OneMinusSrcAlpha; - BlendFactor srcAlpha = BlendFactor::One; - BlendFactor dstAlpha = BlendFactor::OneMinusSrcAlpha; - BlendOp opRGB = BlendOp::Add; - BlendOp opAlpha = BlendOp::Add; - uint8 colorWriteMask = 0xF; + bool enabled = false; + BlendMode mode = BlendMode::Alpha; + BlendFactor srcRGB = BlendFactor::SrcAlpha; + BlendFactor dstRGB = BlendFactor::OneMinusSrcAlpha; + BlendFactor srcAlpha = BlendFactor::One; + BlendFactor dstAlpha = BlendFactor::OneMinusSrcAlpha; + BlendOp opRGB = BlendOp::Add; + BlendOp opAlpha = BlendOp::Add; + uint8 colorWriteMask = 0xF; - static BlendState opaque() { - return BlendState{false, BlendMode::None}; - } + static BlendState opaque() { return BlendState{false, BlendMode::None}; } - static BlendState alpha() { - return BlendState{true, BlendMode::Alpha}; - } + static BlendState alpha() { return BlendState{true, BlendMode::Alpha}; } - static BlendState additive() { - BlendState state; - state.enabled = true; - state.mode = BlendMode::Additive; - state.srcRGB = BlendFactor::SrcAlpha; - state.dstRGB = BlendFactor::One; - state.srcAlpha = BlendFactor::One; - state.dstAlpha = BlendFactor::One; - return state; - } + static BlendState additive() { + BlendState state; + state.enabled = true; + state.mode = BlendMode::Additive; + state.srcRGB = BlendFactor::SrcAlpha; + state.dstRGB = BlendFactor::One; + state.srcAlpha = BlendFactor::One; + state.dstAlpha = BlendFactor::One; + return state; + } - static BlendState multiply() { - BlendState state; - state.enabled = true; - state.mode = BlendMode::Multiply; - state.srcRGB = BlendFactor::DstColor; - state.dstRGB = BlendFactor::OneMinusSrcAlpha; - return state; - } + static BlendState multiply() { + BlendState state; + state.enabled = true; + state.mode = BlendMode::Multiply; + state.srcRGB = BlendFactor::DstColor; + state.dstRGB = BlendFactor::OneMinusSrcAlpha; + return state; + } }; // --------------------------------------------------------------------------- // 深度状态 // --------------------------------------------------------------------------- struct DepthState { - bool testEnabled = true; - bool writeEnabled = true; - CompareFunc compareFunc = CompareFunc::LEqual; + bool testEnabled = true; + bool writeEnabled = true; + CompareFunc compareFunc = CompareFunc::LEqual; - static DepthState readOnly() { - return DepthState{true, false, CompareFunc::LEqual}; - } + static DepthState readOnly() { + return DepthState{true, false, CompareFunc::LEqual}; + } - static DepthState disabled() { - return DepthState{false, false, CompareFunc::Always}; - } + static DepthState disabled() { + return DepthState{false, false, CompareFunc::Always}; + } }; // --------------------------------------------------------------------------- // 模板状态 // --------------------------------------------------------------------------- struct StencilState { - bool enabled = false; - uint8 readMask = 0xFF; - uint8 writeMask = 0xFF; - uint8 ref = 0; - CompareFunc compareFunc = CompareFunc::Always; - BlendOp stencilFailOp = BlendOp::Add; - BlendOp depthFailOp = BlendOp::Add; - BlendOp passOp = BlendOp::Add; + bool enabled = false; + uint8 readMask = 0xFF; + uint8 writeMask = 0xFF; + uint8 ref = 0; + CompareFunc compareFunc = CompareFunc::Always; + BlendOp stencilFailOp = BlendOp::Add; + BlendOp depthFailOp = BlendOp::Add; + BlendOp passOp = BlendOp::Add; }; // --------------------------------------------------------------------------- // 光栅化状态 // --------------------------------------------------------------------------- struct RasterState { - CullMode cullMode = CullMode::Back; - PolygonMode polygonMode = PolygonMode::Fill; - bool depthBiasEnabled = false; - float depthBias = 0.0f; - float depthBiasSlope = 0.0f; - bool scissorEnabled = false; - bool multisampleEnabled = true; - float lineWidth = 1.0f; - float pointSize = 1.0f; + CullMode cullMode = CullMode::Back; + PolygonMode polygonMode = PolygonMode::Fill; + bool depthBiasEnabled = false; + float depthBias = 0.0f; + float depthBiasSlope = 0.0f; + bool scissorEnabled = false; + bool multisampleEnabled = true; + float lineWidth = 1.0f; + float pointSize = 1.0f; }; // --------------------------------------------------------------------------- // 渲染统计 // --------------------------------------------------------------------------- struct RenderStats { - uint32 drawCalls = 0; - uint32 vertices = 0; - uint32 triangles = 0; - uint32 stateChanges = 0; - uint32 textureBinds = 0; - uint32 shaderBinds = 0; - uint32 bufferUpdates = 0; + uint32 drawCalls = 0; + uint32 vertices = 0; + uint32 triangles = 0; + uint32 stateChanges = 0; + uint32 textureBinds = 0; + uint32 shaderBinds = 0; + uint32 bufferUpdates = 0; - void reset() { - drawCalls = 0; - vertices = 0; - triangles = 0; - stateChanges = 0; - textureBinds = 0; - shaderBinds = 0; - bufferUpdates = 0; - } + void reset() { + drawCalls = 0; + vertices = 0; + triangles = 0; + stateChanges = 0; + textureBinds = 0; + shaderBinds = 0; + bufferUpdates = 0; + } }; // --------------------------------------------------------------------------- // 视口 // --------------------------------------------------------------------------- struct Viewport { - int32 x = 0; - int32 y = 0; - int32 width = 800; - int32 height = 600; - float minDepth = 0.0f; - float maxDepth = 1.0f; + int32 x = 0; + int32 y = 0; + int32 width = 800; + int32 height = 600; + float minDepth = 0.0f; + float maxDepth = 1.0f; }; // --------------------------------------------------------------------------- // 裁剪矩形 // --------------------------------------------------------------------------- struct ScissorRect { - int32 x = 0; - int32 y = 0; - int32 width = 0; - int32 height = 0; - bool enabled = false; + int32 x = 0; + int32 y = 0; + int32 width = 0; + int32 height = 0; + bool enabled = false; }; // --------------------------------------------------------------------------- // 清除标志 // --------------------------------------------------------------------------- struct ClearFlags { - bool color = true; - bool depth = true; - bool stencil = false; + bool color = true; + bool depth = true; + bool stencil = false; - static ClearFlags all() { - return ClearFlags{true, true, true}; - } + static ClearFlags all() { return ClearFlags{true, true, true}; } - static ClearFlags colorOnly() { - return ClearFlags{true, false, false}; - } + static ClearFlags colorOnly() { return ClearFlags{true, false, false}; } - static ClearFlags depthOnly() { - return ClearFlags{false, true, false}; - } -}; - -// --------------------------------------------------------------------------- -// 颜色 (RGBA) -// --------------------------------------------------------------------------- -struct Color { - float r = 0.0f; - float g = 0.0f; - float b = 0.0f; - float a = 1.0f; - - Color() = default; - Color(float r, float g, float b, float a = 1.0f) : r(r), g(g), b(b), a(a) {} - - static Color white() { return Color(1.0f, 1.0f, 1.0f, 1.0f); } - static Color black() { return Color(0.0f, 0.0f, 0.0f, 1.0f); } - static Color red() { return Color(1.0f, 0.0f, 0.0f, 1.0f); } - static Color green() { return Color(0.0f, 1.0f, 0.0f, 1.0f); } - static Color blue() { return Color(0.0f, 0.0f, 1.0f, 1.0f); } - static Color transparent() { return Color(0.0f, 0.0f, 0.0f, 0.0f); } + static ClearFlags depthOnly() { return ClearFlags{false, true, false}; } }; } // namespace extra2d diff --git a/Extra2D/include/extra2d/render/renderer.h b/Extra2D/include/extra2d/render/renderer.h new file mode 100644 index 0000000..8df6b43 --- /dev/null +++ b/Extra2D/include/extra2d/render/renderer.h @@ -0,0 +1,153 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace extra2d { + +/** + * @brief 高层渲染器 + * + * 封装 ShapeRenderer 和 SpriteRenderer,提供简单易用的 2D 渲染 API + */ +class Renderer { +public: + Renderer(); + ~Renderer(); + + /** + * @brief 初始化渲染器 + */ + bool init(); + + /** + * @brief 关闭渲染器 + */ + void shutdown(); + + /** + * @brief 开始帧渲染 + * @param clearColor 清屏颜色 + */ + void beginFrame(const Color& clearColor = Colors::Black); + + /** + * @brief 结束帧渲染 + */ + void endFrame(); + + /** + * @brief 设置视图投影矩阵 + */ + void setViewProjection(const glm::mat4& viewProjection); + + /** + * @brief 获取视图投影矩阵 + */ + const glm::mat4& viewProjection() const { return viewProjection_; } + + // ========================================================================= + // 图形绘制 API + // ========================================================================= + + /** + * @brief 绘制线条 + */ + void drawLine(const Vec2& start, const Vec2& end, const Color& color, float width = 1.0f); + + /** + * @brief 绘制矩形(描边) + */ + void drawRect(const Rect& rect, const Color& color, float width = 1.0f); + + /** + * @brief 绘制矩形(填充) + */ + void fillRect(const Rect& rect, const Color& color); + + /** + * @brief 绘制圆形(描边) + */ + void drawCircle(const Vec2& center, float radius, const Color& color, + int segments = 32, float width = 1.0f); + + /** + * @brief 绘制圆形(填充) + */ + void fillCircle(const Vec2& center, float radius, const Color& color, int segments = 32); + + /** + * @brief 绘制三角形(描边) + */ + void drawTriangle(const Vec2& p1, const Vec2& p2, const Vec2& p3, + const Color& color, float width = 1.0f); + + /** + * @brief 绘制三角形(填充) + */ + void fillTriangle(const Vec2& p1, const Vec2& p2, const Vec2& p3, const Color& color); + + /** + * @brief 绘制多边形(描边) + */ + void drawPolygon(const std::vector& points, const Color& color, float width = 1.0f); + + /** + * @brief 绘制多边形(填充) + */ + void fillPolygon(const std::vector& points, const Color& color); + + // ========================================================================= + // 精灵绘制 API + // ========================================================================= + + /** + * @brief 绘制精灵 + */ + void drawSprite(const Texture& texture, const Rect& destRect, const Rect& srcRect, + const Color& color = Colors::White, float rotation = 0.0f, + const Vec2& anchor = Vec2(0.5f, 0.5f)); + + /** + * @brief 绘制精灵(简化版) + */ + void drawSprite(const Texture& texture, const Vec2& position, + const Color& color = Colors::White); + + /** + * @brief 绘制精灵(带缩放) + */ + void drawSprite(const Texture& texture, const Vec2& position, const Vec2& scale, + const Color& color = Colors::White); + + // ========================================================================= + // 统计信息 + // ========================================================================= + + /** + * @brief 获取绘制调用次数 + */ + uint32 drawCalls() const; + + /** + * @brief 获取精灵数量 + */ + uint32 spriteCount() const; + +private: + glm::vec4 toVec4(const Color& color) const; + + std::unique_ptr shapeRenderer_; + std::unique_ptr spriteRenderer_; + glm::mat4 viewProjection_{1.0f}; + bool inFrame_ = false; +}; + +} // namespace extra2d diff --git a/Extra2D/include/extra2d/render/texture.h b/Extra2D/include/extra2d/render/texture.h new file mode 100644 index 0000000..a4ac689 --- /dev/null +++ b/Extra2D/include/extra2d/render/texture.h @@ -0,0 +1,108 @@ +#pragma once + +#include +#include +#include +#include + +namespace extra2d { + +/** + * @brief 纹理配置 + */ +struct TextureConfig { + int width = 0; + int height = 0; + int channels = 4; + FilterMode filter = FilterMode::Linear; + WrapMode wrap = WrapMode::Clamp; + bool generateMips = false; +}; + +/** + * @brief GPU 纹理类 + * + * 封装 OpenGL 纹理对象 + */ +class Texture { +public: + Texture() = default; + ~Texture(); + + /** + * @brief 从像素数据创建纹理 + */ + static std::unique_ptr create(const u8* data, const TextureConfig& config); + + /** + * @brief 创建空纹理 + */ + static std::unique_ptr createEmpty(int width, int height, int channels = 4); + + /** + * @brief 更新纹理数据 + */ + void update(const u8* data, int width, int height, int channels); + + /** + * @brief 更新纹理子区域 + */ + void updateSubRegion(const u8* data, int x, int y, int width, int height); + + /** + * @brief 绑定到纹理单元 + */ + void bind(uint32 unit = 0) const; + + /** + * @brief 解绑纹理 + */ + void unbind() const; + + /** + * @brief 获取 OpenGL 纹理 ID + */ + GLuint glHandle() const { return glHandle_; } + + /** + * @brief 获取宽度 + */ + int width() const { return width_; } + + /** + * @brief 获取高度 + */ + int height() const { return height_; } + + /** + * @brief 获取通道数 + */ + int channels() const { return channels_; } + + /** + * @brief 检查纹理是否有效 + */ + bool isValid() const { return glHandle_ != 0; } + + /** + * @brief 设置过滤模式 + */ + void setFilter(FilterMode filter); + + /** + * @brief 设置环绕模式 + */ + void setWrap(WrapMode wrap); + +private: + bool init(const u8* data, const TextureConfig& config); + GLenum glInternalFormat() const; + GLenum glFormat() const; + + GLuint glHandle_ = 0; + int width_ = 0; + int height_ = 0; + int channels_ = 4; +}; + +} // namespace extra2d diff --git a/Extra2D/include/extra2d/scene/node.h b/Extra2D/include/extra2d/scene/node.h index 03c1a38..b750716 100644 --- a/Extra2D/include/extra2d/scene/node.h +++ b/Extra2D/include/extra2d/scene/node.h @@ -1,21 +1,17 @@ #pragma once -#include #include #include #include #include -#include -#include +#include #include #include namespace extra2d { -// 前向声明 class Scene; class Renderer; -struct RenderCommand; // ============================================================================ // 节点基类 - 场景图的基础 @@ -25,30 +21,20 @@ public: Node(); virtual ~Node(); - // ------------------------------------------------------------------------ // 层级管理 - // ------------------------------------------------------------------------ - void addChild(Ptr child); - - /** - * @brief 批量添加子节点 - * @param children 子节点列表 - */ - void addChildren(std::vector> &&children); - - void removeChild(Ptr child); + void addChild(Ref child); + void addChildren(std::vector> &&children); + void removeChild(Ref child); void removeChildByName(const std::string &name); void removeFromParent(); void removeAllChildren(); - Ptr getParent() const { return parent_.lock(); } - const std::vector> &getChildren() const { return children_; } - Ptr getChildByName(const std::string &name) const; - Ptr getChildByTag(int tag) const; + Ref getParent() const { return parent_.lock(); } + const std::vector> &getChildren() const { return children_; } + Ref getChildByName(const std::string &name) const; + Ref getChildByTag(int tag) const; - // ------------------------------------------------------------------------ // 变换属性 - // ------------------------------------------------------------------------ void setPosition(const Vec2 &pos); void setPosition(float x, float y); Vec2 getPosition() const { return position_; } @@ -75,66 +61,39 @@ public: void setVisible(bool visible); bool isVisible() const { return visible_; } - /** - * @brief 设置颜色 - * @param color RGB颜色 - */ - void setColor(const Color3B& color); + void setColor(const Color3B &color); Color3B getColor() const { return color_; } - /** - * @brief 设置X轴翻转 - */ void setFlipX(bool flipX); bool isFlipX() const { return flipX_; } - /** - * @brief 设置Y轴翻转 - */ void setFlipY(bool flipY); bool isFlipY() const { return flipY_; } void setZOrder(int zOrder); int getZOrder() const { return zOrder_; } - // ------------------------------------------------------------------------ // 世界变换 - // ------------------------------------------------------------------------ Vec2 convertToWorldSpace(const Vec2 &localPos) const; Vec2 convertToNodeSpace(const Vec2 &worldPos) const; glm::mat4 getLocalTransform() const; glm::mat4 getWorldTransform() const; - /** - * @brief 标记变换矩阵为脏状态,并传播到所有子节点 - */ void markTransformDirty(); - - /** - * @brief 批量更新变换矩阵 - * 在渲染前统一计算所有脏节点的变换矩阵,避免逐节点计算时的重复递归 - */ void batchUpdateTransforms(); - /** - * @brief 获取变换脏标记状态 - */ bool isTransformDirty() const { return transformDirty_; } bool isWorldTransformDirty() const { return worldTransformDirty_; } - // ------------------------------------------------------------------------ // 名称和标签 - // ------------------------------------------------------------------------ void setName(const std::string &name) { name_ = name; } const std::string &getName() const { return name_; } void setTag(int tag) { tag_ = tag; } int getTag() const { return tag_; } - // ------------------------------------------------------------------------ // 生命周期回调 - // ------------------------------------------------------------------------ virtual void onEnter(); virtual void onExit(); virtual void onUpdate(float dt); @@ -142,26 +101,17 @@ public: virtual void onAttachToScene(Scene *scene); virtual void onDetachFromScene(); - // ------------------------------------------------------------------------ // 边界框(用于空间索引) - // ------------------------------------------------------------------------ virtual Rect getBoundingBox() const; - // 是否需要参与空间索引(默认 true) void setSpatialIndexed(bool indexed) { spatialIndexed_ = indexed; } bool isSpatialIndexed() const { return spatialIndexed_; } - - // 更新空间索引(手动调用,通常在边界框变化后) void updateSpatialIndex(); - // ------------------------------------------------------------------------ // 事件系统 - // ------------------------------------------------------------------------ EventDispatcher &getEventDispatcher() { return eventDispatcher_; } - // ------------------------------------------------------------------------ // 内部方法 - // ------------------------------------------------------------------------ void update(float dt); void render(Renderer &renderer); void sortChildren(); @@ -169,18 +119,10 @@ public: bool isRunning() const { return running_; } Scene *getScene() const { return scene_; } - // 多线程渲染命令收集 - virtual void collectRenderCommands(std::vector &commands, - int parentZOrder = 0); - protected: - // 子类重写 virtual void onDraw(Renderer &renderer) {} virtual void onUpdateNode(float dt) {} - virtual void generateRenderCommand(std::vector &commands, - int zOrder) {}; - // 供子类访问的内部状态 Vec2 &getPositionRef() { return position_; } Vec2 &getScaleRef() { return scale_; } Vec2 &getAnchorRef() { return anchor_; } @@ -188,65 +130,45 @@ protected: float getOpacityRef() { return opacity_; } private: - // ========================================================================== - // 成员变量按类型大小降序排列,减少内存对齐填充 - // 64位系统对齐:std::string(32) > glm::mat4(64) > std::vector(24) > - // double(8) > float(4) > int(4) > bool(1) - // ========================================================================== + mutable glm::mat4 localTransform_{1.0f}; + mutable glm::mat4 worldTransform_{1.0f}; - // 1. 大块内存(64字节) - mutable glm::mat4 localTransform_; // 64 bytes - mutable glm::mat4 worldTransform_; // 64 bytes + std::string name_; + std::vector> children_; - // 2. 字符串和容器(24-32字节) - std::string name_; // 32 bytes - std::vector> children_; // 24 bytes + std::unordered_map> nameIndex_; + std::unordered_map> tagIndex_; - // 3. 子节点索引(加速查找) - std::unordered_map> nameIndex_; // 56 bytes - std::unordered_map> tagIndex_; // 56 bytes + EventDispatcher eventDispatcher_; - // 4. 事件分发器 - EventDispatcher eventDispatcher_; // 大小取决于实现 + std::weak_ptr parent_; - // 5. 父节点引用 - WeakPtr parent_; // 16 bytes + Vec2 position_ = Vec2::Zero(); + Vec2 scale_ = Vec2(1.0f, 1.0f); + Vec2 anchor_ = Vec2(0.5f, 0.5f); + Vec2 skew_ = Vec2::Zero(); - // 7. 变换属性(按访问频率分组) - Vec2 position_ = Vec2::Zero(); // 8 bytes - Vec2 scale_ = Vec2(1.0f, 1.0f); // 8 bytes - Vec2 anchor_ = Vec2(0.5f, 0.5f); // 8 bytes - Vec2 skew_ = Vec2::Zero(); // 8 bytes + Rect lastSpatialBounds_; - // 8. 边界框(用于空间索引) - Rect lastSpatialBounds_; // 16 bytes + float rotation_ = 0.0f; + float opacity_ = 1.0f; - // 9. 浮点属性 - float rotation_ = 0.0f; // 4 bytes - float opacity_ = 1.0f; // 4 bytes + Color3B color_ = Color3B(255, 255, 255); - // 10. 颜色属性 - Color3B color_ = Color3B(255, 255, 255); // 3 bytes + int zOrder_ = 0; + int tag_ = -1; - // 11. 整数属性 - int zOrder_ = 0; // 4 bytes - int tag_ = -1; // 4 bytes + bool flipX_ = false; + bool flipY_ = false; - // 12. 布尔属性 - bool flipX_ = false; // 1 byte - bool flipY_ = false; // 1 byte + Scene *scene_ = nullptr; - // 11. 场景指针 - Scene *scene_ = nullptr; // 8 bytes - - // 12. 布尔标志(打包在一起) - mutable bool transformDirty_ = true; // 1 byte - mutable bool worldTransformDirty_ = true; // 1 byte - bool childrenOrderDirty_ = false; // 1 byte - bool visible_ = true; // 1 byte - bool running_ = false; // 1 byte - bool spatialIndexed_ = true; // 1 byte - // 填充 2 bytes 到 8 字节对齐 + mutable bool transformDirty_ = true; + mutable bool worldTransformDirty_ = true; + bool childrenOrderDirty_ = false; + bool visible_ = true; + bool running_ = false; + bool spatialIndexed_ = true; }; } // namespace extra2d diff --git a/Extra2D/include/extra2d/scene/scene.h b/Extra2D/include/extra2d/scene/scene.h index 6f09a3a..ff0cb1b 100644 --- a/Extra2D/include/extra2d/scene/scene.h +++ b/Extra2D/include/extra2d/scene/scene.h @@ -1,15 +1,13 @@ #pragma once #include -#include +#include #include #include #include namespace extra2d { -// 前向声明 -struct RenderCommand; class Renderer; // ============================================================================ @@ -17,96 +15,75 @@ class Renderer; // ============================================================================ class Scene : public Node { public: - Scene(); - ~Scene() override = default; + Scene(); + ~Scene() override = default; - // ------------------------------------------------------------------------ - // 场景属性 - // ------------------------------------------------------------------------ - void setBackgroundColor(const Color &color) { backgroundColor_ = color; } - Color getBackgroundColor() const { return backgroundColor_; } + // 场景属性 + void setBackgroundColor(const Color& color) { backgroundColor_ = color; } + Color getBackgroundColor() const { return backgroundColor_; } - // ------------------------------------------------------------------------ - // 摄像机 - // ------------------------------------------------------------------------ - void setCamera(Ptr camera); - Ptr getCamera() const { return camera_; } + // 摄像机 + void setCamera(Ref camera); + Ref getCamera() const { return camera_; } - Camera *getActiveCamera() const { - return camera_ ? camera_.get() : defaultCamera_.get(); - } + Camera* getActiveCamera() const { + return camera_ ? camera_.get() : defaultCamera_.get(); + } - // ------------------------------------------------------------------------ - // 视口和尺寸 - // ------------------------------------------------------------------------ - void setViewportSize(float width, float height); - void setViewportSize(const Size &size); - Size getViewportSize() const { return viewportSize_; } + // 视口和尺寸 + void setViewportSize(float width, float height); + void setViewportSize(const Size& size); + Size getViewportSize() const { return viewportSize_; } - float getWidth() const { return viewportSize_.width; } - float getHeight() const { return viewportSize_.height; } + float getWidth() const { return viewportSize_.width; } + float getHeight() const { return viewportSize_.height; } - // ------------------------------------------------------------------------ - // 场景状态 - // ------------------------------------------------------------------------ - bool isPaused() const { return paused_; } - void pause() { paused_ = true; } - void resume() { paused_ = false; } + // 场景状态 + bool isPaused() const { return paused_; } + void pause() { paused_ = true; } + void resume() { paused_ = false; } - // ------------------------------------------------------------------------ - // 渲染和更新 - // ------------------------------------------------------------------------ - void renderScene(Renderer &renderer); - virtual void renderContent(Renderer &renderer); - void updateScene(float dt); - void collectRenderCommands(std::vector &commands, - int parentZOrder = 0) override; + // 渲染和更新 + void renderScene(Renderer& renderer); + virtual void renderContent(Renderer& renderer); + void updateScene(float dt); - // ------------------------------------------------------------------------ - // 空间索引系统 - // ------------------------------------------------------------------------ - SpatialManager &getSpatialManager() { return spatialManager_; } - const SpatialManager &getSpatialManager() const { return spatialManager_; } + // 空间索引系统 + SpatialManager& getSpatialManager() { return spatialManager_; } + const SpatialManager& getSpatialManager() const { return spatialManager_; } - // 启用/禁用空间索引 - void setSpatialIndexingEnabled(bool enabled) { - spatialIndexingEnabled_ = enabled; - } - bool isSpatialIndexingEnabled() const { return spatialIndexingEnabled_; } + void setSpatialIndexingEnabled(bool enabled) { + spatialIndexingEnabled_ = enabled; + } + bool isSpatialIndexingEnabled() const { return spatialIndexingEnabled_; } - // 节点空间索引管理(内部使用) - void updateNodeInSpatialIndex(Node *node, const Rect &oldBounds, - const Rect &newBounds); - void removeNodeFromSpatialIndex(Node *node); + void updateNodeInSpatialIndex(Node* node, const Rect& oldBounds, const Rect& newBounds); + void removeNodeFromSpatialIndex(Node* node); - // 碰撞检测查询 - std::vector queryNodesInArea(const Rect &area) const; - std::vector queryNodesAtPoint(const Vec2 &point) const; - std::vector> queryCollisions() const; + std::vector queryNodesInArea(const Rect& area) const; + std::vector queryNodesAtPoint(const Vec2& point) const; + std::vector> queryCollisions() const; - // ------------------------------------------------------------------------ - // 静态创建方法 - // ------------------------------------------------------------------------ - static Ptr create(); + // 静态创建方法 + static Ref create(); protected: - void onEnter() override; - void onExit() override; + void onEnter() override; + void onExit() override; - friend class SceneManager; + friend class SceneManager; private: - Color backgroundColor_ = Colors::Black; - Size viewportSize_ = Size::Zero(); + Color backgroundColor_ = Colors::Black; + Size viewportSize_ = Size::Zero(); - Ptr camera_; - Ptr defaultCamera_; + Ref camera_; + Ref defaultCamera_; - bool paused_ = false; + bool paused_ = false; - // 空间索引系统 - SpatialManager spatialManager_; - bool spatialIndexingEnabled_ = true; + SpatialManager spatialManager_; + bool spatialIndexingEnabled_ = true; }; } // namespace extra2d diff --git a/Extra2D/include/extra2d/scene/scene_manager.h b/Extra2D/include/extra2d/scene/scene_manager.h index 167c78c..59459dc 100644 --- a/Extra2D/include/extra2d/scene/scene_manager.h +++ b/Extra2D/include/extra2d/scene/scene_manager.h @@ -1,98 +1,62 @@ #pragma once #include +#include #include -#include #include #include #include -#include namespace extra2d { -// 前向声明 -struct RenderCommand; -class Renderer; - // ============================================================================ // 场景管理器 - 管理场景的生命周期和切换 // ============================================================================ class SceneManager { public: - // ------------------------------------------------------------------------ - // 单例访问 - // ------------------------------------------------------------------------ static SceneManager &getInstance(); - // ------------------------------------------------------------------------ // 场景栈操作 - // ------------------------------------------------------------------------ - - // 运行第一个场景 - void runWithScene(Ptr scene); - - // 替换当前场景 - void replaceScene(Ptr scene); - - // 压入新场景(当前场景暂停) - void pushScene(Ptr scene); - - // 弹出当前场景(恢复上一个场景) + void runWithScene(Ref scene); + void replaceScene(Ref scene); + void pushScene(Ref scene); void popScene(); - - // 弹出到根场景 void popToRootScene(); - - // 弹出到指定场景 void popToScene(const std::string &name); - // ------------------------------------------------------------------------ // 获取场景 - // ------------------------------------------------------------------------ - Ptr getCurrentScene() const; - Ptr getPreviousScene() const; - Ptr getRootScene() const; + Ref getCurrentScene() const; + Ref getPreviousScene() const; + Ref getRootScene() const; + Ref getSceneByName(const std::string &name) const; - // 通过名称获取场景 - Ptr getSceneByName(const std::string &name) const; - - // ------------------------------------------------------------------------ // 查询 - // ------------------------------------------------------------------------ size_t getSceneCount() const { return sceneStack_.size(); } bool isEmpty() const { return sceneStack_.empty(); } bool hasScene(const std::string &name) const; - // ------------------------------------------------------------------------ // 更新和渲染 - // ------------------------------------------------------------------------ void update(float dt); void render(Renderer &renderer); - void collectRenderCommands(std::vector &commands); - // ------------------------------------------------------------------------ // 过渡控制 - // ------------------------------------------------------------------------ bool isTransitioning() const { return false; } - // ------------------------------------------------------------------------ // 清理 - // ------------------------------------------------------------------------ void end(); void purgeCachedScenes(); -public: + // 场景切换(供 Application 使用) + void enterScene(Ref scene); + +private: SceneManager() = default; ~SceneManager() = default; SceneManager(const SceneManager &) = delete; SceneManager &operator=(const SceneManager &) = delete; - // 场景切换(供 Application 使用) - void enterScene(Ptr scene); - -private: - std::stack> sceneStack_; - std::unordered_map> namedScenes_; + std::stack> sceneStack_; + std::unordered_map> namedScenes_; }; } // namespace extra2d diff --git a/Extra2D/include/extra2d/scene/shape_node.h b/Extra2D/include/extra2d/scene/shape_node.h index 084d595..a9b9087 100644 --- a/Extra2D/include/extra2d/scene/shape_node.h +++ b/Extra2D/include/extra2d/scene/shape_node.h @@ -17,88 +17,66 @@ enum class ShapeType { Point, Line, Rect, Circle, Triangle, Polygon }; // ============================================================================ class ShapeNode : public Node { public: - ShapeNode(); - ~ShapeNode() override = default; + ShapeNode(); + ~ShapeNode() override = default; - // ------------------------------------------------------------------------ - // 静态创建方法 - // ------------------------------------------------------------------------ - static Ptr create(); + // 静态创建方法 + static Ref create(); - // 点 - static Ptr createPoint(const Vec2 &pos, const Color &color); - - // 线 - static Ptr createLine(const Vec2 &start, const Vec2 &end, - const Color &color, float width = 1.0f); - - // 矩形 - static Ptr createRect(const Rect &rect, const Color &color, - float width = 1.0f); - static Ptr createFilledRect(const Rect &rect, const Color &color); - - // 圆形 - static Ptr createCircle(const Vec2 ¢er, float radius, - const Color &color, int segments = 32, + static Ref createPoint(const Vec2& pos, const Color& color); + static Ref createLine(const Vec2& start, const Vec2& end, + const Color& color, float width = 1.0f); + static Ref createRect(const Rect& rect, const Color& color, float width = 1.0f); - static Ptr createFilledCircle(const Vec2 ¢er, float radius, - const Color &color, - int segments = 32); - - // 三角形 - static Ptr createTriangle(const Vec2 &p1, const Vec2 &p2, - const Vec2 &p3, const Color &color, + static Ref createFilledRect(const Rect& rect, const Color& color); + static Ref createCircle(const Vec2& center, float radius, + const Color& color, int segments = 32, float width = 1.0f); - static Ptr createFilledTriangle(const Vec2 &p1, const Vec2 &p2, - const Vec2 &p3, - const Color &color); + static Ref createFilledCircle(const Vec2& center, float radius, + const Color& color, int segments = 32); + static Ref createTriangle(const Vec2& p1, const Vec2& p2, + const Vec2& p3, const Color& color, + float width = 1.0f); + static Ref createFilledTriangle(const Vec2& p1, const Vec2& p2, + const Vec2& p3, const Color& color); + static Ref createPolygon(const std::vector& points, + const Color& color, float width = 1.0f); + static Ref createFilledPolygon(const std::vector& points, + const Color& color); - // 多边形 - static Ptr createPolygon(const std::vector &points, - const Color &color, float width = 1.0f); - static Ptr createFilledPolygon(const std::vector &points, - const Color &color); + // 属性设置 + void setShapeType(ShapeType type) { shapeType_ = type; } + ShapeType getShapeType() const { return shapeType_; } - // ------------------------------------------------------------------------ - // 属性设置 - // ------------------------------------------------------------------------ - void setShapeType(ShapeType type) { shapeType_ = type; } - ShapeType getShapeType() const { return shapeType_; } + void setColor(const Color& color) { color_ = color; } + Color getColor() const { return color_; } - void setColor(const Color &color) { color_ = color; } - Color getColor() const { return color_; } + void setFilled(bool filled) { filled_ = filled; } + bool isFilled() const { return filled_; } - void setFilled(bool filled) { filled_ = filled; } - bool isFilled() const { return filled_; } + void setLineWidth(float width) { lineWidth_ = width; } + float getLineWidth() const { return lineWidth_; } - void setLineWidth(float width) { lineWidth_ = width; } - float getLineWidth() const { return lineWidth_; } + void setSegments(int segments) { segments_ = segments; } + int getSegments() const { return segments_; } - void setSegments(int segments) { segments_ = segments; } - int getSegments() const { return segments_; } + void setPoints(const std::vector& points); + const std::vector& getPoints() const { return points_; } + void addPoint(const Vec2& point); + void clearPoints(); - // ------------------------------------------------------------------------ - // 点设置 - // ------------------------------------------------------------------------ - void setPoints(const std::vector &points); - const std::vector &getPoints() const { return points_; } - void addPoint(const Vec2 &point); - void clearPoints(); - - Rect getBoundingBox() const override; + Rect getBoundingBox() const override; protected: - void onDraw(Renderer &renderer) override; - void generateRenderCommand(std::vector &commands, - int zOrder) override; + void onDraw(Renderer& renderer) override; private: - ShapeType shapeType_ = ShapeType::Rect; - Color color_ = Colors::White; - bool filled_ = false; - float lineWidth_ = 1.0f; - int segments_ = 32; - std::vector points_; + ShapeType shapeType_ = ShapeType::Rect; + Color color_ = Colors::White; + bool filled_ = false; + float lineWidth_ = 1.0f; + int segments_ = 32; + std::vector points_; }; } // namespace extra2d diff --git a/Extra2D/include/extra2d/scene/sprite.h b/Extra2D/include/extra2d/scene/sprite.h index e8f56cb..915de99 100644 --- a/Extra2D/include/extra2d/scene/sprite.h +++ b/Extra2D/include/extra2d/scene/sprite.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include namespace extra2d { @@ -10,46 +10,44 @@ namespace extra2d { // ============================================================================ class Sprite : public Node { public: - Sprite(); - explicit Sprite(Ptr texture); - ~Sprite() override = default; + Sprite(); + explicit Sprite(Ref texture); + ~Sprite() override = default; - // 纹理 - void setTexture(Ptr texture); - Ptr getTexture() const { return texture_; } + // 纹理 + void setTexture(Ref texture); + Ref getTexture() const { return texture_; } - // 纹理矩形 (用于图集) - void setTextureRect(const Rect &rect); - Rect getTextureRect() const { return textureRect_; } + // 纹理矩形 (用于图集) + void setTextureRect(const Rect& rect); + Rect getTextureRect() const { return textureRect_; } - // 颜色混合 - void setColor(const Color &color); - Color getColor() const { return color_; } + // 颜色混合 + void setColor(const Color& color); + Color getColor() const { return color_; } - // 翻转 - void setFlipX(bool flip); - void setFlipY(bool flip); - bool isFlipX() const { return flipX_; } - bool isFlipY() const { return flipY_; } + // 翻转 + void setFlipX(bool flip); + void setFlipY(bool flip); + bool isFlipX() const { return flipX_; } + bool isFlipY() const { return flipY_; } - // 静态创建方法 - static Ptr create(); - static Ptr create(Ptr texture); - static Ptr create(Ptr texture, const Rect &rect); + // 静态创建方法 + static Ref create(); + static Ref create(Ref texture); + static Ref create(Ref texture, const Rect& rect); - Rect getBoundingBox() const override; + Rect getBoundingBox() const override; protected: - void onDraw(Renderer &renderer) override; - void generateRenderCommand(std::vector &commands, - int zOrder) override; + void onDraw(Renderer& renderer) override; private: - Ptr texture_; - Rect textureRect_; - Color color_ = Colors::White; - bool flipX_ = false; - bool flipY_ = false; + Ref texture_; + Rect textureRect_; + Color color_ = Colors::White; + bool flipX_ = false; + bool flipY_ = false; }; } // namespace extra2d diff --git a/Extra2D/include/extra2d/services/logger_service.h b/Extra2D/include/extra2d/services/logger_service.h index a3333ad..3c17582 100644 --- a/Extra2D/include/extra2d/services/logger_service.h +++ b/Extra2D/include/extra2d/services/logger_service.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include @@ -10,7 +9,7 @@ namespace extra2d { /** - * @brief 日志颜色结构 + * @brief 日志颜色 */ struct LogColor { u8 r, g, b; @@ -18,36 +17,22 @@ struct LogColor { constexpr LogColor() : r(255), g(255), b(255) {} constexpr LogColor(u8 r, u8 g, u8 b) : r(r), g(g), b(b) {} - static constexpr LogColor White() { return LogColor(255, 255, 255); } - static constexpr LogColor Gray() { return LogColor(128, 128, 128); } - static constexpr LogColor Red() { return LogColor(255, 85, 85); } - static constexpr LogColor Green() { return LogColor(85, 255, 85); } - static constexpr LogColor Yellow() { return LogColor(255, 255, 85); } - static constexpr LogColor Blue() { return LogColor(85, 85, 255); } - static constexpr LogColor Magenta() { return LogColor(255, 85, 255); } - static constexpr LogColor Cyan() { return LogColor(85, 255, 255); } - static constexpr LogColor Orange() { return LogColor(255, 165, 0); } - - static constexpr LogColor Slate() { return LogColor(100, 116, 139); } - static constexpr LogColor SlateLight() { return LogColor(148, 163, 184); } - static constexpr LogColor Sky() { return LogColor(14, 165, 233); } - static constexpr LogColor SkyLight() { return LogColor(125, 211, 252); } - static constexpr LogColor Emerald() { return LogColor(16, 185, 129); } - static constexpr LogColor EmeraldLight() { return LogColor(110, 231, 183); } - static constexpr LogColor Amber() { return LogColor(245, 158, 11); } - static constexpr LogColor AmberLight() { return LogColor(252, 211, 77); } - static constexpr LogColor Rose() { return LogColor(244, 63, 94); } - static constexpr LogColor RoseLight() { return LogColor(253, 164, 175); } - static constexpr LogColor Violet() { return LogColor(139, 92, 246); } - static constexpr LogColor VioletLight() { return LogColor(196, 181, 253); } - static constexpr LogColor Indigo() { return LogColor(99, 102, 241); } - static constexpr LogColor IndigoLight() { return LogColor(165, 180, 252); } + static constexpr LogColor White() { return {255, 255, 255}; } + static constexpr LogColor Gray() { return {128, 128, 128}; } + static constexpr LogColor Red() { return {255, 85, 85}; } + static constexpr LogColor Green() { return {85, 255, 85}; } + static constexpr LogColor Yellow() { return {255, 255, 85}; } + static constexpr LogColor Blue() { return {85, 85, 255}; } + static constexpr LogColor Magenta() { return {255, 85, 255}; } + static constexpr LogColor Cyan() { return {85, 255, 255}; } + static constexpr LogColor SkyLight() { return {125, 211, 252}; } + static constexpr LogColor IndigoLight() { return {165, 180, 252}; } }; /** - * @brief 日志级别枚举 + * @brief 日志级别 */ -enum class LogLevel { +enum class LogLevel : u8 { Trace = 0, Debug = 1, Info = 2, @@ -65,102 +50,36 @@ class ILogger : public IService { public: virtual ~ILogger() = default; - /** - * @brief 设置日志级别 - */ virtual void level(LogLevel lvl) = 0; - - /** - * @brief 获取日志级别 - */ virtual LogLevel level() const = 0; - - /** - * @brief 检查日志级别是否启用 - */ virtual bool enabled(LogLevel lvl) const = 0; - /** - * @brief 记录日志(格式化) - */ virtual void log(LogLevel lvl, const char *fmt, ...) = 0; - - /** - * @brief 记录日志(字符串) - */ virtual void log(LogLevel lvl, const std::string &msg) = 0; - /** - * @brief Trace级别日志 - */ virtual void trace(const char *fmt, ...) = 0; - - /** - * @brief Debug级别日志 - */ virtual void debug(const char *fmt, ...) = 0; - - /** - * @brief Info级别日志 - */ virtual void info(const char *fmt, ...) = 0; - - /** - * @brief Registry级别日志(用于模块/服务注册显示) - */ virtual void registry(const char *fmt, ...) = 0; - - /** - * @brief Warn级别日志 - */ virtual void warn(const char *fmt, ...) = 0; - - /** - * @brief Error级别日志 - */ virtual void error(const char *fmt, ...) = 0; - - /** - * @brief Fatal级别日志 - */ virtual void fatal(const char *fmt, ...) = 0; - /** - * @brief 设置日志级别颜色 - * @param lvl 日志级别 - * @param c 颜色 - */ virtual void levelColor(LogLevel lvl, const LogColor &c) = 0; - - /** - * @brief 获取日志级别颜色 - * @param lvl 日志级别 - * @return 颜色 - */ virtual LogColor levelColor(LogLevel lvl) const = 0; - - /** - * @brief 启用/禁用颜色输出 - * @param on 是否启用 - */ virtual void colors(bool on) = 0; - - /** - * @brief 是否启用颜色输出 - */ virtual bool colors() const = 0; ServiceInfo info() const override { ServiceInfo i; i.name = "Logger"; i.priority = ServicePriority::Core; - i.enabled = true; return i; } }; /** - * @brief 控制台日志服务实现 + * @brief 控制台日志服务 */ class ConsoleLogger : public ILogger { public: @@ -195,38 +114,32 @@ private: const char *levelString(LogLevel lvl); std::string ansiColor(LogLevel lvl); - LogLevel level_; - bool colors_; + LogLevel level_ = LogLevel::Info; + bool colors_ = true; LogColor levelColors_[7]; class Impl; Unique impl_; - // 服务注册元数据 E2D_AUTO_REGISTER_SERVICE(ILogger, ConsoleLogger); }; } // namespace extra2d -// 格式化辅助函数 - 将参数转换为字符串 +// 格式化辅助 namespace extra2d { namespace detail { template std::string to_string(T &&value) { - using Decayed = std::decay_t; - if constexpr (std::is_same_v) { + using D = std::decay_t; + if constexpr (std::is_same_v) return value; - } else if constexpr (std::is_same_v) { + else if constexpr (std::is_same_v) return value ? value : "(null)"; - } else if constexpr (std::is_arithmetic_v) { - if constexpr (std::is_same_v) { - return value ? "true" : "false"; - } else if constexpr (std::is_floating_point_v) { - return std::to_string(value); - } else { - return std::to_string(value); - } - } else { + else if constexpr (std::is_same_v) + return value ? "true" : "false"; + else if constexpr (std::is_arithmetic_v) + return std::to_string(value); + else return ""; - } } inline void format_impl(std::string &result, const char *fmt) { result += fmt; } @@ -234,42 +147,33 @@ inline void format_impl(std::string &result, const char *fmt) { result += fmt; } template void format_impl(std::string &result, const char *fmt, T &&value, Args &&...args) { - const char *p = fmt; - while (*p) { - if (*p == '{' && *(p + 1) == '}') { + while (*fmt) { + if (*fmt == '{' && *(fmt + 1) == '}') { result += to_string(std::forward(value)); - format_impl(result, p + 2, std::forward(args)...); - return; + return format_impl(result, fmt + 2, std::forward(args)...); } - result += *p++; + result += *fmt++; } - result += " "; - result += to_string(std::forward(value)); - format_impl(result, p, std::forward(args)...); + result += " " + to_string(std::forward(value)); + format_impl(result, fmt, std::forward(args)...); } } // namespace detail template std::string format_str(const char *fmt, Args &&...args) { - if constexpr (sizeof...(args) == 0) { - return std::string(fmt); - } else { - std::string result; - detail::format_impl(result, fmt, std::forward(args)...); - return result; - } + std::string result; + detail::format_impl(result, fmt, std::forward(args)...); + return result; } } // namespace extra2d -// 便捷宏 - 自动获取日志服务 -#define E2D_LOG(lvl, ...) \ +// 日志宏 +#define E2D_LOG(lvl, ...) \ do { \ - if (auto logService = ::extra2d::ServiceLocator::instance() \ - .tryGet<::extra2d::ILogger>()) { \ - if (logService->enabled(lvl)) { \ - logService->log(lvl, ::extra2d::format_str(__VA_ARGS__)); \ - } \ - } \ + if (auto log = ::extra2d::ServiceLocator::instance() \ + .tryGet<::extra2d::ILogger>()) \ + if (log->enabled(lvl)) \ + log->log(lvl, ::extra2d::format_str(__VA_ARGS__)); \ } while (0) #define E2D_TRACE(...) E2D_LOG(::extra2d::LogLevel::Trace, __VA_ARGS__) @@ -279,32 +183,3 @@ std::string format_str(const char *fmt, Args &&...args) { #define E2D_WARN(...) E2D_LOG(::extra2d::LogLevel::Warn, __VA_ARGS__) #define E2D_ERROR(...) E2D_LOG(::extra2d::LogLevel::Error, __VA_ARGS__) #define E2D_FATAL(...) E2D_LOG(::extra2d::LogLevel::Fatal, __VA_ARGS__) - -// 带颜色参数的日志宏 -#define E2D_LOG_COLOR(lvl, c, ...) \ - do { \ - if (auto logService = ::extra2d::ServiceLocator::instance() \ - .tryGet<::extra2d::ILogger>()) { \ - if (logService->enabled(lvl)) { \ - auto prevColor = logService->levelColor(lvl); \ - logService->levelColor(lvl, c); \ - logService->log(lvl, ::extra2d::format_str(__VA_ARGS__)); \ - logService->levelColor(lvl, prevColor); \ - } \ - } \ - } while (0) - -#define E2D_TRACE_COLOR(c, ...) \ - E2D_LOG_COLOR(::extra2d::LogLevel::Trace, c, __VA_ARGS__) -#define E2D_DEBUG_COLOR(c, ...) \ - E2D_LOG_COLOR(::extra2d::LogLevel::Debug, c, __VA_ARGS__) -#define E2D_INFO_COLOR(c, ...) \ - E2D_LOG_COLOR(::extra2d::LogLevel::Info, c, __VA_ARGS__) -#define E2D_REGISTRY_COLOR(c, ...) \ - E2D_LOG_COLOR(::extra2d::LogLevel::Registry, c, __VA_ARGS__) -#define E2D_WARN_COLOR(c, ...) \ - E2D_LOG_COLOR(::extra2d::LogLevel::Warn, c, __VA_ARGS__) -#define E2D_ERROR_COLOR(c, ...) \ - E2D_LOG_COLOR(::extra2d::LogLevel::Error, c, __VA_ARGS__) -#define E2D_FATAL_COLOR(c, ...) \ - E2D_LOG_COLOR(::extra2d::LogLevel::Fatal, c, __VA_ARGS__) diff --git a/Extra2D/include/extra2d/utils/logger.h b/Extra2D/include/extra2d/utils/logger.h deleted file mode 100644 index 837ca26..0000000 --- a/Extra2D/include/extra2d/utils/logger.h +++ /dev/null @@ -1,270 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -// SDL2 日志头文件 -#include - -namespace extra2d { - -// ============================================================================ -// 日志级别枚举 - 映射到 SDL_LogPriority -// ============================================================================ -enum class LogLevel { - Trace = SDL_LOG_PRIORITY_VERBOSE, // SDL 详细日志 - Debug = SDL_LOG_PRIORITY_DEBUG, // SDL 调试日志 - Info = SDL_LOG_PRIORITY_INFO, // SDL 信息日志 - Warn = SDL_LOG_PRIORITY_WARN, // SDL 警告日志 - Error = SDL_LOG_PRIORITY_ERROR, // SDL 错误日志 - Fatal = SDL_LOG_PRIORITY_CRITICAL, // SDL 严重日志 - Off = SDL_LOG_PRIORITY_CRITICAL + 1 // 关闭日志 (使用 Critical+1 作为关闭标记) -}; - -// ============================================================================ -// 简单的 fmt-style {} 格式化器 -// ============================================================================ -namespace detail { - -// 将单个参数转为字符串 -template inline std::string to_string_arg(const T &value) { - if constexpr (std::is_same_v) { - return value; - } else if constexpr (std::is_same_v || - std::is_same_v) { - return value ? std::string(value) : std::string("(null)"); - } else if constexpr (std::is_same_v) { - return value ? "true" : "false"; - } else if constexpr (std::is_arithmetic_v) { - // 对浮点数使用特殊格式 - if constexpr (std::is_floating_point_v) { - char buf[64]; - snprintf(buf, sizeof(buf), "%.2f", static_cast(value)); - return buf; - } else { - return std::to_string(value); - } - } else { - std::ostringstream oss; - oss << value; - return oss.str(); - } -} - -// 格式化基础情况:没有更多参数 -inline std::string format_impl(const char *fmt) { - std::string result; - while (*fmt) { - if (*fmt == '{' && *(fmt + 1) == '}') { - result += "{}"; // 无参数可替换,保留原样 - fmt += 2; - } else { - result += *fmt; - ++fmt; - } - } - return result; -} - -// 格式化递归:替换第一个 {} 并递归处理剩余 -template -inline std::string format_impl(const char *fmt, const T &first, - const Args &...rest) { - std::string result; - while (*fmt) { - if (*fmt == '{') { - // 检查 {:#x} 等格式说明符 - if (*(fmt + 1) == '}') { - result += to_string_arg(first); - fmt += 2; - result += format_impl(fmt, rest...); - return result; - } else if (*(fmt + 1) == ':') { - // 跳过格式说明符直到 } - const char *end = fmt + 2; - while (*end && *end != '}') - ++end; - if (*end == '}') { - // 检查是否是十六进制格式 - std::string spec(fmt + 2, end); - if (spec.find('x') != std::string::npos || - spec.find('X') != std::string::npos) { - if constexpr (std::is_integral_v) { - char buf[32]; - snprintf(buf, sizeof(buf), "0x%x", - static_cast(first)); - result += buf; - } else { - result += to_string_arg(first); - } - } else if (spec.find('f') != std::string::npos || - spec.find('.') != std::string::npos) { - if constexpr (std::is_arithmetic_v) { - // 解析精度 - int precision = 2; - auto dot = spec.find('.'); - if (dot != std::string::npos) { - precision = 0; - for (size_t i = dot + 1; - i < spec.size() && spec[i] >= '0' && spec[i] <= '9'; ++i) { - precision = precision * 10 + (spec[i] - '0'); - } - } - char fmtbuf[16]; - snprintf(fmtbuf, sizeof(fmtbuf), "%%.%df", precision); - char buf[64]; - snprintf(buf, sizeof(buf), fmtbuf, static_cast(first)); - result += buf; - } else { - result += to_string_arg(first); - } - } else { - result += to_string_arg(first); - } - fmt = end + 1; - result += format_impl(fmt, rest...); - return result; - } - } - } - result += *fmt; - ++fmt; - } - return result; -} - -} // namespace detail - -// 顶层格式化函数 -template -inline std::string e2d_format(const char *fmt, const Args &...args) { - return detail::format_impl(fmt, args...); -} - -// 无参数版本 -inline std::string e2d_format(const char *fmt) { return std::string(fmt); } - -// ============================================================================ -// Logger 类 - 使用 SDL2 日志系统 -// ============================================================================ -class Logger { -public: - /** - * @brief 初始化日志系统 - */ - static void init(); - - /** - * @brief 关闭日志系统 - */ - static void shutdown(); - - /** - * @brief 设置日志级别 - * @param level 日志级别 - */ - static void setLevel(LogLevel level); - - /** - * @brief 设置是否输出到控制台 - * @param enable 是否启用 - */ - static void setConsoleOutput(bool enable); - - /** - * @brief 设置日志输出到文件 - * @param filename 日志文件名 - */ - static void setFileOutput(const std::string &filename); - - /** - * @brief 获取当前日志级别 - * @return 当前日志级别 - */ - static LogLevel getLevel() { return level_; } - - /** - * @brief 日志记录模板函数 - * @param level 日志级别 - * @param fmt 格式化字符串 - * @param args 可变参数 - */ - template - static void log(LogLevel level, const char *fmt, const Args &...args) { - if (static_cast(level) < static_cast(level_)) - return; - std::string msg = e2d_format(fmt, args...); - SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, - static_cast(level), "[%s] %s", - getLevelString(level), msg.c_str()); - } - - /** - * @brief 日志记录无参数版本 - * @param level 日志级别 - * @param msg 日志消息 - */ - static void log(LogLevel level, const char *msg) { - if (static_cast(level) < static_cast(level_)) - return; - SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, - static_cast(level), "[%s] %s", - getLevelString(level), msg); - } - -private: - static LogLevel level_; // 当前日志级别 - static bool initialized_; // 是否已初始化 - static bool consoleOutput_; // 是否输出到控制台 - static bool fileOutput_; // 是否输出到文件 - static std::string logFile_; // 日志文件路径 - - /** - * @brief 获取日志级别字符串 - * @param level 日志级别 - * @return 级别字符串 - */ - static const char *getLevelString(LogLevel level); -}; - -// ============================================================================ -// 日志宏 -// ============================================================================ - -#ifdef E2D_DEBUG -#define E2D_LOG_TRACE(...) \ - ::extra2d::Logger::log(::extra2d::LogLevel::Trace, __VA_ARGS__) -#define E2D_LOG_DEBUG(...) \ - ::extra2d::Logger::log(::extra2d::LogLevel::Debug, __VA_ARGS__) -#else -#define E2D_LOG_TRACE(...) -#define E2D_LOG_DEBUG(...) -#endif - -#define E2D_LOG_INFO(...) \ - ::extra2d::Logger::log(::extra2d::LogLevel::Info, __VA_ARGS__) -#define E2D_LOG_WARN(...) \ - ::extra2d::Logger::log(::extra2d::LogLevel::Warn, __VA_ARGS__) -#define E2D_LOG_ERROR(...) \ - ::extra2d::Logger::log(::extra2d::LogLevel::Error, __VA_ARGS__) -#define E2D_LOG_FATAL(...) \ - ::extra2d::Logger::log(::extra2d::LogLevel::Fatal, __VA_ARGS__) - -// 简化的日志宏 -#define E2D_INFO(...) E2D_LOG_INFO(__VA_ARGS__) -#define E2D_WARN(...) E2D_LOG_WARN(__VA_ARGS__) -#define E2D_ERROR(...) E2D_LOG_ERROR(__VA_ARGS__) -#define E2D_FATAL(...) E2D_LOG_FATAL(__VA_ARGS__) -#ifdef E2D_DEBUG -#define E2D_DEBUG_LOG(...) E2D_LOG_DEBUG(__VA_ARGS__) -#define E2D_TRACE(...) E2D_LOG_TRACE(__VA_ARGS__) -#else -#define E2D_DEBUG_LOG(...) -#define E2D_TRACE(...) -#endif - -} // namespace extra2d diff --git a/Extra2D/include/extra2d/window/window.h b/Extra2D/include/extra2d/window/window.h index e261f2c..d6bae4f 100644 --- a/Extra2D/include/extra2d/window/window.h +++ b/Extra2D/include/extra2d/window/window.h @@ -1,75 +1,49 @@ #pragma once -<<<<<<< HEAD -#include -#include #include - -======= -#include -#include #include -#include ->>>>>>> 9bf328b1dca01df84a07724394abc9a238739869 #include namespace extra2d { -class Input; - struct WindowConfig { - std::string title = "Extra2D Application"; - int width = 1280; - int height = 720; - bool fullscreen = true; - bool resizable = false; - bool vsync = true; - int msaaSamples = 0; - bool centerWindow = true; + std::string title = "Extra2D Application"; + int width = 1280; + int height = 720; + bool fullscreen = true; + bool resizable = false; + bool centerWindow = true; }; class Window { public: - Window(); - ~Window(); + Window(); + ~Window(); - bool create(const WindowConfig &config); - void destroy(); + bool create(const WindowConfig& config); + void destroy(); - void pollEvents(); - void swapBuffers(); - bool shouldClose() const; - void setShouldClose(bool close); + void pollEvents(); + bool shouldClose() const; + void setShouldClose(bool close); - void setTitle(const std::string &title); - void setSize(int width, int height); - void setFullscreen(bool fullscreen); - void setVSync(bool enabled); + void setTitle(const std::string& title); + void setSize(int width, int height); + void setFullscreen(bool fullscreen); - int getWidth() const { return width_; } - int getHeight() const { return height_; } - bool isFullscreen() const { return fullscreen_; } - bool isVSync() const { return vsync_; } + int getWidth() const { return width_; } + int getHeight() const { return height_; } + bool isFullscreen() const { return fullscreen_; } - SDL_Window *getSDLWindow() const { return sdlWindow_; } - SDL_GLContext getGLContext() const { return glContext_; } - - Input *getInput() const { return input_.get(); } + SDL_Window* sdlWindow() const { return sdlWindow_; } private: - SDL_Window *sdlWindow_; - SDL_GLContext glContext_; - - int width_; - int height_; - bool vsync_; - bool shouldClose_; - bool fullscreen_; - UniquePtr input_; - - bool initSDL(const WindowConfig &config); - void deinitSDL(); + SDL_Window* sdlWindow_ = nullptr; + int width_ = 1280; + int height_ = 720; + bool fullscreen_ = true; + bool shouldClose_ = false; }; } // namespace extra2d diff --git a/Extra2D/src/app/application.cpp b/Extra2D/src/app/application.cpp index 60264da..3dca6ff 100644 --- a/Extra2D/src/app/application.cpp +++ b/Extra2D/src/app/application.cpp @@ -1,68 +1,49 @@ #include -<<<<<<< HEAD -#include -#include -#include -#include -#include +#include +#include #include -#include -#include -======= -#include -#include -#include -#include -#include -#include ->>>>>>> 9bf328b1dca01df84a07724394abc9a238739869 +#include namespace extra2d { -static f64 getTimeSeconds() { -#ifdef __SWITCH__ - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return static_cast(ts.tv_sec) + - static_cast(ts.tv_nsec) / 1000000000.0; -#else - using namespace std::chrono; - auto now = steady_clock::now(); - auto duration = now.time_since_epoch(); - return duration_cast>(duration).count(); -#endif +Application &Application::instance() { + static Application app; + return app; } -Application &Application::get() { - static Application instance; - return instance; -} - -Application::Application() { Registry::instance().setApp(this); } - -Application::~Application() { - if (initialized_) { - shutdown(); - } -} +Application::~Application() { shutdown(); } bool Application::init() { - if (initialized_) { + if (initialized_) return true; - } - // 初始化所有模块(拓扑排序) - // 服务通过 E2D_AUTO_REGISTER_SERVICE 宏自动注册 - if (!Registry::instance().init()) { + E2D_INFO("Application initializing: {}", name); + + ServiceLocator::instance().init(); + + window_ = new Window(); + if (!window_->create({.title = name, .width = 1280, .height = 720})) { + E2D_ERROR("Failed to create window"); + delete window_; + window_ = nullptr; return false; } - // 初始化所有服务 - ServiceLocator::instance().init(); + auto &device = RenderDevice::instance(); + if (!device.init(window_->sdlWindow())) { + E2D_ERROR("Failed to initialize render device"); + window_->destroy(); + delete window_; + window_ = nullptr; + return false; + } initialized_ = true; running_ = true; + lastFrameTime_ = SDL_GetPerformanceCounter(); + + E2D_INFO("Application initialized successfully"); return true; } @@ -70,10 +51,17 @@ void Application::shutdown() { if (!initialized_) return; + E2D_INFO("Application shutting down"); + + RenderDevice::instance().shutdown(); + + if (window_) { + window_->destroy(); + delete window_; + window_ = nullptr; + } + ServiceLocator::instance().shutdown(); - ServiceLocator::instance().clear(); - Registry::instance().shutdown(); - Registry::instance().clear(); initialized_ = false; running_ = false; @@ -83,95 +71,33 @@ void Application::run() { if (!initialized_) return; - auto *winMod = get(); - if (!winMod || !winMod->win()) - return; - - lastFrameTime_ = getTimeSeconds(); - - while (running_ && !winMod->win()->shouldClose()) { + while (running_ && !window_->shouldClose()) { mainLoop(); } } -<<<<<<< HEAD void Application::quit() { running_ = false; } -======= -void Application::quit() { - shouldQuit_ = true; - running_ = false; -} ->>>>>>> 9bf328b1dca01df84a07724394abc9a238739869 - -void Application::pause() { - if (!paused_) { - paused_ = true; - ServiceLocator::instance().pause(); - } -} - -void Application::resume() { - if (paused_) { - paused_ = false; - ServiceLocator::instance().resume(); - lastFrameTime_ = getTimeSeconds(); - } -} void Application::mainLoop() { - f64 currentTime = getTimeSeconds(); - dt_ = static_cast(currentTime - lastFrameTime_); + u64 currentTime = SDL_GetPerformanceCounter(); + u64 frequency = SDL_GetPerformanceFrequency(); + dt_ = static_cast(currentTime - lastFrameTime_) / + static_cast(frequency); lastFrameTime_ = currentTime; totalTime_ += dt_; - frameCount_++; fpsTimer_ += dt_; + if (fpsTimer_ >= 1.0f) { fps_ = frameCount_; frameCount_ = 0; fpsTimer_ -= 1.0f; } - auto *winMod = get(); - if (winMod && winMod->win()) { - winMod->win()->poll(); - } - - auto eventService = ServiceLocator::instance().get(); - if (eventService) { - eventService->process(); - } - - if (!paused_) { - update(); - } - - render(); -} - -void Application::update() { ServiceLocator::instance().update(dt_); } - -void Application::render() { - auto *winMod = get(); - if (!winMod || !winMod->win()) - return; - -<<<<<<< HEAD - renderer_->beginFrame(Colors::Black); - - // 渲染内容可以在这里添加 - - renderer_->endFrame(); - window_->swapBuffers(); -======= - winMod->win()->swap(); ->>>>>>> 9bf328b1dca01df84a07724394abc9a238739869 -} - -GLFWWindow *Application::window() { - auto *winMod = get(); - return winMod ? winMod->win() : nullptr; + window_->pollEvents(); + ServiceLocator::instance().update(dt_); + RenderDevice::instance().swapBuffers(); } } // namespace extra2d diff --git a/Extra2D/src/audio/audio_engine.cpp b/Extra2D/src/audio/audio_engine.cpp index cc7f6f1..5822be4 100644 --- a/Extra2D/src/audio/audio_engine.cpp +++ b/Extra2D/src/audio/audio_engine.cpp @@ -1,6 +1,6 @@ #include "extra2d/audio/audio_engine.h" #include "extra2d/audio/sound.h" -#include "extra2d/utils/logger.h" +#include #include #include diff --git a/Extra2D/src/audio/sound.cpp b/Extra2D/src/audio/sound.cpp index b5dad3a..c698fea 100644 --- a/Extra2D/src/audio/sound.cpp +++ b/Extra2D/src/audio/sound.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include namespace extra2d { diff --git a/Extra2D/src/graphics/opengl/gl_font_atlas.cpp b/Extra2D/src/graphics/opengl/gl_font_atlas.cpp deleted file mode 100644 index 24e5d29..0000000 --- a/Extra2D/src/graphics/opengl/gl_font_atlas.cpp +++ /dev/null @@ -1,285 +0,0 @@ -#include -#include -#include -#include -#define STB_TRUETYPE_IMPLEMENTATION -#include -#define STB_RECT_PACK_IMPLEMENTATION -#include -#include - -namespace extra2d { - -// ============================================================================ -// 构造函数 - 初始化字体图集 -// ============================================================================ -GLFontAtlas::GLFontAtlas(const std::string &filepath, int fontSize, bool useSDF) - : fontSize_(fontSize), useSDF_(useSDF), currentY_(0), scale_(0.0f), - ascent_(0.0f), descent_(0.0f), lineGap_(0.0f) { - - // 加载字体文件 - std::ifstream file(filepath, std::ios::binary | std::ios::ate); - if (!file.is_open()) { - E2D_LOG_ERROR("Failed to load font: {}", filepath); - return; - } - - std::streamsize size = file.tellg(); - file.seekg(0, std::ios::beg); - fontData_.resize(size); - if (!file.read(reinterpret_cast(fontData_.data()), size)) { - E2D_LOG_ERROR("Failed to read font file: {}", filepath); - return; - } - - // 初始化 stb_truetype - if (!stbtt_InitFont(&fontInfo_, fontData_.data(), - stbtt_GetFontOffsetForIndex(fontData_.data(), 0))) { - E2D_LOG_ERROR("Failed to init font: {}", filepath); - return; - } - - scale_ = stbtt_ScaleForPixelHeight(&fontInfo_, static_cast(fontSize_)); - - int ascent, descent, lineGap; - stbtt_GetFontVMetrics(&fontInfo_, &ascent, &descent, &lineGap); - ascent_ = static_cast(ascent) * scale_; - descent_ = static_cast(descent) * scale_; - lineGap_ = static_cast(lineGap) * scale_; - - createAtlas(); -} - -// ============================================================================ -// 析构函数 -// ============================================================================ -GLFontAtlas::~GLFontAtlas() = default; - -// ============================================================================ -// 获取字形 - 如果字形不存在则缓存它 -// ============================================================================ -const Glyph *GLFontAtlas::getGlyph(char32_t codepoint) const { - auto it = glyphs_.find(codepoint); - if (it == glyphs_.end()) { - cacheGlyph(codepoint); - it = glyphs_.find(codepoint); - } - return (it != glyphs_.end()) ? &it->second : nullptr; -} - -// ============================================================================ -// 测量文本尺寸 -// ============================================================================ -Vec2 GLFontAtlas::measureText(const std::string &text) { - float width = 0.0f; - float height = getAscent() - getDescent(); - float currentWidth = 0.0f; - - std::u32string utf32_text; - utf32_text.resize(simdutf::utf32_length_from_utf8(text.data(), text.size())); - simdutf::convert_utf8_to_utf32(text.data(), text.size(), utf32_text.data()); - for (char32_t codepoint : utf32_text) { - if (codepoint == '\n') { - width = std::max(width, currentWidth); - currentWidth = 0.0f; - height += getLineHeight(); - continue; - } - - const Glyph *glyph = getGlyph(codepoint); - if (glyph) { - currentWidth += glyph->advance; - } - } - - width = std::max(width, currentWidth); - return Vec2(width, height); -} - -// ============================================================================ -// 创建图集纹理 - 初始化空白纹理和矩形打包上下文 -// ============================================================================ -void GLFontAtlas::createAtlas() { - // 统一使用 4 通道格式 - int channels = 4; - std::vector emptyData(ATLAS_WIDTH * ATLAS_HEIGHT * channels, 0); - texture_ = std::make_unique(ATLAS_WIDTH, ATLAS_HEIGHT, - emptyData.data(), channels); - texture_->setFilter(true); - - // 初始化矩形打包上下文 - packNodes_.resize(ATLAS_WIDTH); - stbrp_init_target(&packContext_, ATLAS_WIDTH, ATLAS_HEIGHT, packNodes_.data(), - ATLAS_WIDTH); - - // 预分配字形缓冲区 - // 假设最大字形尺寸为 fontSize * fontSize * 4 (RGBA) - size_t maxGlyphSize = static_cast(fontSize_ * fontSize_ * 4 * 4); - glyphBitmapCache_.reserve(maxGlyphSize); - glyphRgbaCache_.reserve(maxGlyphSize); -} - -// ============================================================================ -// 缓存字形 - 渲染字形到图集并存储信息 -// 使用 stb_rect_pack 进行矩形打包 -// ============================================================================ -void GLFontAtlas::cacheGlyph(char32_t codepoint) const { - int advance = 0; - stbtt_GetCodepointHMetrics(&fontInfo_, static_cast(codepoint), &advance, - nullptr); - float advancePx = advance * scale_; - - if (useSDF_) { - constexpr int SDF_PADDING = 8; - constexpr unsigned char ONEDGE_VALUE = 128; - constexpr float PIXEL_DIST_SCALE = 64.0f; - - int w = 0, h = 0, xoff = 0, yoff = 0; - unsigned char *sdf = stbtt_GetCodepointSDF( - &fontInfo_, scale_, static_cast(codepoint), SDF_PADDING, - ONEDGE_VALUE, PIXEL_DIST_SCALE, &w, &h, &xoff, &yoff); - if (!sdf || w <= 0 || h <= 0) { - if (sdf) - stbtt_FreeSDF(sdf, nullptr); - Glyph glyph{}; - glyph.advance = advancePx; - glyphs_[codepoint] = glyph; - return; - } - - stbrp_rect rect; - rect.id = static_cast(codepoint); - rect.w = w + PADDING * 2; - rect.h = h + PADDING * 2; - - stbrp_pack_rects(&packContext_, &rect, 1); - if (!rect.was_packed) { - E2D_LOG_WARN("Font atlas is full, cannot cache codepoint: {}", - static_cast(codepoint)); - stbtt_FreeSDF(sdf, nullptr); - return; - } - - int atlasX = rect.x + PADDING; - int atlasY = rect.y + PADDING; - - Glyph glyph; - glyph.width = static_cast(w); - glyph.height = static_cast(h); - glyph.bearingX = static_cast(xoff); - glyph.bearingY = static_cast(yoff); - glyph.advance = advancePx; - - // stb_rect_pack 使用左上角为原点,OpenGL纹理使用左下角为原点 - // 需要翻转V坐标 - float v0 = static_cast(atlasY) / ATLAS_HEIGHT; - float v1 = static_cast(atlasY + h) / ATLAS_HEIGHT; - glyph.u0 = static_cast(atlasX) / ATLAS_WIDTH; - glyph.v0 = 1.0f - v1; // 翻转V坐标 - glyph.u1 = static_cast(atlasX + w) / ATLAS_WIDTH; - glyph.v1 = 1.0f - v0; // 翻转V坐标 - - glyphs_[codepoint] = glyph; - - // 将 SDF 单通道数据转换为 RGBA 格式(统一格式) - size_t pixelCount = static_cast(w) * static_cast(h); - glyphRgbaCache_.resize(pixelCount * 4); - for (size_t i = 0; i < pixelCount; ++i) { - uint8_t alpha = sdf[i]; - glyphRgbaCache_[i * 4 + 0] = 255; // R - glyphRgbaCache_[i * 4 + 1] = 255; // G - glyphRgbaCache_[i * 4 + 2] = 255; // B - glyphRgbaCache_[i * 4 + 3] = alpha; // A - SDF 值存储在 Alpha 通道 - } - - // 直接设置像素对齐为 4,无需查询当前状态 - glBindTexture(GL_TEXTURE_2D, texture_->getTextureID()); - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - // OpenGL纹理坐标原点在左下角,需要将Y坐标翻转 - glTexSubImage2D(GL_TEXTURE_2D, 0, atlasX, ATLAS_HEIGHT - atlasY - h, w, h, - GL_RGBA, GL_UNSIGNED_BYTE, glyphRgbaCache_.data()); - - stbtt_FreeSDF(sdf, nullptr); - return; - } - - int x0 = 0, y0 = 0, x1 = 0, y1 = 0; - stbtt_GetCodepointBitmapBox(&fontInfo_, static_cast(codepoint), scale_, - scale_, &x0, &y0, &x1, &y1); - int w = x1 - x0; - int h = y1 - y0; - int xoff = x0; - int yoff = y0; - - if (w <= 0 || h <= 0) { - Glyph glyph{}; - glyph.advance = advancePx; - glyphs_[codepoint] = glyph; - return; - } - - // 使用预分配缓冲区 - size_t pixelCount = static_cast(w) * static_cast(h); - glyphBitmapCache_.resize(pixelCount); - stbtt_MakeCodepointBitmap(&fontInfo_, glyphBitmapCache_.data(), w, h, w, scale_, scale_, - static_cast(codepoint)); - - // 使用 stb_rect_pack 打包矩形 - stbrp_rect rect; - rect.id = static_cast(codepoint); - rect.w = w + PADDING * 2; - rect.h = h + PADDING * 2; - - stbrp_pack_rects(&packContext_, &rect, 1); - - if (!rect.was_packed) { - // 图集已满,无法缓存更多字形 - E2D_LOG_WARN("Font atlas is full, cannot cache codepoint: {}", - static_cast(codepoint)); - return; - } - - int atlasX = rect.x + PADDING; - int atlasY = rect.y + PADDING; - - // 创建字形信息 - Glyph glyph; - glyph.width = static_cast(w); - glyph.height = static_cast(h); - glyph.bearingX = static_cast(xoff); - glyph.bearingY = static_cast(yoff); - glyph.advance = advancePx; - - // 计算纹理坐标(相对于图集) - // stb_rect_pack 使用左上角为原点,OpenGL纹理使用左下角为原点 - // 需要翻转V坐标 - float v0 = static_cast(atlasY) / ATLAS_HEIGHT; - float v1 = static_cast(atlasY + h) / ATLAS_HEIGHT; - glyph.u0 = static_cast(atlasX) / ATLAS_WIDTH; - glyph.v0 = 1.0f - v1; // 翻转V坐标 - glyph.u1 = static_cast(atlasX + w) / ATLAS_WIDTH; - glyph.v1 = 1.0f - v0; // 翻转V坐标 - - // 存储字形 - glyphs_[codepoint] = glyph; - - // 将单通道字形数据转换为 RGBA 格式(白色字形,Alpha 通道存储灰度) - glyphRgbaCache_.resize(pixelCount * 4); - for (size_t i = 0; i < pixelCount; ++i) { - uint8_t alpha = glyphBitmapCache_[i]; - glyphRgbaCache_[i * 4 + 0] = 255; // R - glyphRgbaCache_[i * 4 + 1] = 255; // G - glyphRgbaCache_[i * 4 + 2] = 255; // B - glyphRgbaCache_[i * 4 + 3] = alpha; // A - } - - // 更新纹理 - 将字形数据上传到图集的指定位置 - // 直接设置像素对齐为 4,无需查询当前状态 - glBindTexture(GL_TEXTURE_2D, texture_->getTextureID()); - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - // OpenGL纹理坐标原点在左下角,需要将Y坐标翻转 - glTexSubImage2D(GL_TEXTURE_2D, 0, atlasX, ATLAS_HEIGHT - atlasY - h, w, h, - GL_RGBA, GL_UNSIGNED_BYTE, glyphRgbaCache_.data()); -} - -} // namespace extra2d diff --git a/Extra2D/src/graphics/opengl/gl_renderer.cpp b/Extra2D/src/graphics/opengl/gl_renderer.cpp deleted file mode 100644 index 7ca31f3..0000000 --- a/Extra2D/src/graphics/opengl/gl_renderer.cpp +++ /dev/null @@ -1,629 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace extra2d { - -// 形状渲染着色器 - 支持顶点颜色批处理 (GLES 3.2) -static const char *SHAPE_VERTEX_SHADER = R"( -#version 300 es -precision highp float; -layout(location = 0) in vec2 aPosition; -layout(location = 1) in vec4 aColor; -uniform mat4 uViewProjection; -out vec4 vColor; -void main() { - gl_Position = uViewProjection * vec4(aPosition, 0.0, 1.0); - vColor = aColor; -} -)"; - -static const char *SHAPE_FRAGMENT_SHADER = R"( -#version 300 es -precision highp float; -in vec4 vColor; -out vec4 fragColor; -void main() { - fragColor = vColor; -} -)"; - -// VBO 初始大小(用于 VRAM 跟踪) -static constexpr size_t SHAPE_VBO_SIZE = 1024 * sizeof(float); - -// ============================================================================ -// BlendMode 查找表 - 编译期构建,运行时 O(1) 查找 -// ============================================================================ -struct BlendState { - bool enable; - GLenum srcFactor; - GLenum dstFactor; -}; - -static constexpr BlendState BLEND_STATES[] = { - {false, 0, 0}, // BlendMode::None - {true, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, // BlendMode::Alpha - {true, GL_SRC_ALPHA, GL_ONE}, // BlendMode::Additive - {true, GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA} // BlendMode::Multiply -}; - -static constexpr size_t BLEND_STATE_COUNT = - sizeof(BLEND_STATES) / sizeof(BLEND_STATES[0]); - -GLRenderer::GLRenderer() - : window_(nullptr), shapeVao_(0), shapeVbo_(0), lineVao_(0), lineVbo_(0), - vsync_(true), shapeVertexCount_(0), currentShapeMode_(GL_TRIANGLES), - lineVertexCount_(0), currentLineWidth_(1.0f) { - resetStats(); - for (auto &v : shapeVertexCache_) { - v = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; - } - for (auto &v : lineVertexCache_) { - v = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; - } -} - -GLRenderer::~GLRenderer() { shutdown(); } - -bool GLRenderer::init(Window *window) { - window_ = window; - - // Switch: GL 上下文已通过 SDL2 + EGL 初始化,无需 glewInit() - - // 初始化精灵批渲染器 - if (!spriteBatch_.init()) { - E2D_LOG_ERROR("Failed to initialize sprite batch"); - return false; - } - - // 初始化形状渲染 - initShapeRendering(); - - // 设置 OpenGL 状态 - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - // 标记 GPU 上下文为有效 - GPUContext::getInstance().markValid(); - - E2D_LOG_INFO("OpenGL Renderer initialized"); - E2D_LOG_INFO("OpenGL Version: {}", - reinterpret_cast(glGetString(GL_VERSION))); - - return true; -} - -void GLRenderer::shutdown() { - // 标记 GPU 上下文为无效 - // 这会在销毁 OpenGL 上下文之前通知所有 GPU 资源 - GPUContext::getInstance().markInvalid(); - - spriteBatch_.shutdown(); - - if (lineVbo_ != 0) { - glDeleteBuffers(1, &lineVbo_); - VRAMManager::getInstance().freeBuffer(MAX_LINE_VERTICES * - sizeof(ShapeVertex)); - lineVbo_ = 0; - } - if (lineVao_ != 0) { - glDeleteVertexArrays(1, &lineVao_); - lineVao_ = 0; - } - if (shapeVbo_ != 0) { - glDeleteBuffers(1, &shapeVbo_); - VRAMManager::getInstance().freeBuffer(MAX_SHAPE_VERTICES * - sizeof(ShapeVertex)); - shapeVbo_ = 0; - } - if (shapeVao_ != 0) { - glDeleteVertexArrays(1, &shapeVao_); - shapeVao_ = 0; - } -} - -void GLRenderer::beginFrame(const Color &clearColor) { - glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); - glClear(GL_COLOR_BUFFER_BIT); - resetStats(); -} - -void GLRenderer::endFrame() { - // 刷新所有待处理的形状批次 - flushShapeBatch(); - // 刷新所有待处理的线条批次 - flushLineBatch(); -} - -void GLRenderer::setViewport(int x, int y, int width, int height) { - glViewport(x, y, width, height); -} - -void GLRenderer::setVSync(bool enabled) { - vsync_ = enabled; - // 使用 SDL2 设置交换间隔 - SDL_GL_SetSwapInterval(enabled ? 1 : 0); -} - -void GLRenderer::setBlendMode(BlendMode mode) { - // 状态缓存检查,避免冗余 GL 调用 - if (cachedBlendMode_ == mode) { - return; - } - cachedBlendMode_ = mode; - - // 使用查找表替代 switch - size_t index = static_cast(mode); - if (index >= BLEND_STATE_COUNT) { - index = 0; - } - - const BlendState &state = BLEND_STATES[index]; - if (state.enable) { - if (!blendEnabled_) { - glEnable(GL_BLEND); - blendEnabled_ = true; - } - glBlendFunc(state.srcFactor, state.dstFactor); - } else { - if (blendEnabled_) { - glDisable(GL_BLEND); - blendEnabled_ = false; - } - } -} - -void GLRenderer::setViewProjection(const glm::mat4 &matrix) { - viewProjection_ = matrix; -} - -void GLRenderer::pushTransform(const glm::mat4 &transform) { - if (transformStack_.empty()) { - transformStack_.push_back(transform); - } else { - transformStack_.push_back(transformStack_.back() * transform); - } -} - -void GLRenderer::popTransform() { - if (!transformStack_.empty()) { - transformStack_.pop_back(); - } -} - -glm::mat4 GLRenderer::getCurrentTransform() const { - if (transformStack_.empty()) { - return glm::mat4(1.0f); - } - return transformStack_.back(); -} - -Ptr GLRenderer::createTexture(int width, int height, - const uint8_t *pixels, int channels) { - return makePtr(width, height, pixels, channels); -} - -Ptr GLRenderer::loadTexture(const std::string &filepath) { - return makePtr(filepath); -} - -void GLRenderer::beginSpriteBatch() { spriteBatch_.begin(viewProjection_); } - -void GLRenderer::drawSprite(const Texture &texture, const Rect &destRect, - const Rect &srcRect, const Color &tint, - float rotation, const Vec2 &anchor) { - GLSpriteBatch::SpriteData data; - data.position = glm::vec2(destRect.origin.x, destRect.origin.y); - data.size = glm::vec2(destRect.size.width, destRect.size.height); - - Texture *tex = const_cast(&texture); - float texW = static_cast(tex->getWidth()); - float texH = static_cast(tex->getHeight()); - - // 纹理坐标计算 - float u1 = srcRect.origin.x / texW; - float u2 = (srcRect.origin.x + srcRect.size.width) / texW; - float v1 = srcRect.origin.y / texH; - float v2 = (srcRect.origin.y + srcRect.size.height) / texH; - - data.texCoordMin = glm::vec2(glm::min(u1, u2), glm::min(v1, v2)); - data.texCoordMax = glm::vec2(glm::max(u1, u2), glm::max(v1, v2)); - - data.color = glm::vec4(tint.r, tint.g, tint.b, tint.a); - data.rotation = rotation * 3.14159f / 180.0f; - data.anchor = glm::vec2(anchor.x, anchor.y); - data.isSDF = false; - - spriteBatch_.draw(texture, data); -} - -void GLRenderer::drawSprite(const Texture &texture, const Vec2 &position, - const Color &tint) { - Rect destRect(position.x, position.y, static_cast(texture.getWidth()), - static_cast(texture.getHeight())); - Rect srcRect(0, 0, static_cast(texture.getWidth()), - static_cast(texture.getHeight())); - drawSprite(texture, destRect, srcRect, tint, 0.0f, Vec2(0, 0)); -} - -void GLRenderer::endSpriteBatch() { - spriteBatch_.end(); - stats_.drawCalls += spriteBatch_.getDrawCallCount(); -} - -void GLRenderer::drawLine(const Vec2 &start, const Vec2 &end, - const Color &color, float width) { - // 如果线宽改变,需要先刷新线条批次 - if (width != currentLineWidth_) { - flushLineBatch(); - currentLineWidth_ = width; - } - - // 添加两个顶点到线条缓冲区 - addLineVertex(start.x, start.y, color); - addLineVertex(end.x, end.y, color); -} - -void GLRenderer::drawRect(const Rect &rect, const Color &color, float width) { - // 如果线宽改变,需要先刷新线条批次 - if (width != currentLineWidth_) { - flushLineBatch(); - currentLineWidth_ = width; - } - - float x1 = rect.origin.x; - float y1 = rect.origin.y; - float x2 = rect.origin.x + rect.size.width; - float y2 = rect.origin.y + rect.size.height; - - // 4条线段 = 8个顶点 - // 上边 - addLineVertex(x1, y1, color); - addLineVertex(x2, y1, color); - // 右边 - addLineVertex(x2, y1, color); - addLineVertex(x2, y2, color); - // 下边 - addLineVertex(x2, y2, color); - addLineVertex(x1, y2, color); - // 左边 - addLineVertex(x1, y2, color); - addLineVertex(x1, y1, color); -} - -void GLRenderer::fillRect(const Rect &rect, const Color &color) { - // 提交当前批次(如果模式不同) - submitShapeBatch(GL_TRIANGLES); - - // 添加两个三角形组成矩形(6个顶点) - float x1 = rect.origin.x; - float y1 = rect.origin.y; - float x2 = rect.origin.x + rect.size.width; - float y2 = rect.origin.y + rect.size.height; - - // 三角形1: (x1,y1), (x2,y1), (x2,y2) - addShapeVertex(x1, y1, color); - addShapeVertex(x2, y1, color); - addShapeVertex(x2, y2, color); - - // 三角形2: (x1,y1), (x2,y2), (x1,y2) - addShapeVertex(x1, y1, color); - addShapeVertex(x2, y2, color); - addShapeVertex(x1, y2, color); -} - -void GLRenderer::drawCircle(const Vec2 ¢er, float radius, - const Color &color, int segments, float width) { - // 限制段数不超过缓存大小 - if (segments > static_cast(MAX_CIRCLE_SEGMENTS)) { - segments = static_cast(MAX_CIRCLE_SEGMENTS); - } - - // 如果线宽改变,需要先刷新线条批次 - if (width != currentLineWidth_) { - flushLineBatch(); - currentLineWidth_ = width; - } - - // 使用线条批处理绘制圆形 - for (int i = 0; i < segments; ++i) { - float angle1 = - 2.0f * 3.14159f * static_cast(i) / static_cast(segments); - float angle2 = 2.0f * 3.14159f * static_cast(i + 1) / - static_cast(segments); - - addLineVertex(center.x + radius * cosf(angle1), - center.y + radius * sinf(angle1), color); - addLineVertex(center.x + radius * cosf(angle2), - center.y + radius * sinf(angle2), color); - } -} - -void GLRenderer::fillCircle(const Vec2 ¢er, float radius, - const Color &color, int segments) { - // 限制段数不超过缓存大小 - if (segments > static_cast(MAX_CIRCLE_SEGMENTS)) { - segments = static_cast(MAX_CIRCLE_SEGMENTS); - } - - // 提交当前批次(如果模式不同) - submitShapeBatch(GL_TRIANGLES); - - // 使用三角形扇形填充圆 - // 中心点 + 边缘点 - for (int i = 0; i < segments; ++i) { - float angle1 = - 2.0f * 3.14159f * static_cast(i) / static_cast(segments); - float angle2 = 2.0f * 3.14159f * static_cast(i + 1) / - static_cast(segments); - - // 每个三角形:中心 -> 边缘点1 -> 边缘点2 - addShapeVertex(center.x, center.y, color); - addShapeVertex(center.x + radius * cosf(angle1), - center.y + radius * sinf(angle1), color); - addShapeVertex(center.x + radius * cosf(angle2), - center.y + radius * sinf(angle2), color); - } -} - -void GLRenderer::drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3, - const Color &color, float width) { - drawLine(p1, p2, color, width); - drawLine(p2, p3, color, width); - drawLine(p3, p1, color, width); -} - -void GLRenderer::fillTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3, - const Color &color) { - submitShapeBatch(GL_TRIANGLES); - - addShapeVertex(p1.x, p1.y, color); - addShapeVertex(p2.x, p2.y, color); - addShapeVertex(p3.x, p3.y, color); -} - -void GLRenderer::drawPolygon(const std::vector &points, - const Color &color, float width) { - if (points.size() < 2) - return; - - // 如果线宽改变,需要先刷新线条批次 - if (width != currentLineWidth_) { - flushLineBatch(); - currentLineWidth_ = width; - } - - // 绘制所有边 - for (size_t i = 0; i < points.size(); ++i) { - const Vec2 &p1 = points[i]; - const Vec2 &p2 = points[(i + 1) % points.size()]; - addLineVertex(p1.x, p1.y, color); - addLineVertex(p2.x, p2.y, color); - } -} - -void GLRenderer::fillPolygon(const std::vector &points, - const Color &color) { - if (points.size() < 3) - return; - - submitShapeBatch(GL_TRIANGLES); - - // 使用三角形扇形填充 - // 从第一个点开始,每两个相邻点组成一个三角形 - for (size_t i = 1; i < points.size() - 1; ++i) { - addShapeVertex(points[0].x, points[0].y, color); - addShapeVertex(points[i].x, points[i].y, color); - addShapeVertex(points[i + 1].x, points[i + 1].y, color); - } -} - -Ptr GLRenderer::createFontAtlas(const std::string &filepath, - int fontSize, bool useSDF) { - return makePtr(filepath, fontSize, useSDF); -} - -void GLRenderer::drawText(const FontAtlas &font, const std::string &text, - const Vec2 &position, const Color &color) { - drawText(font, text, position.x, position.y, color); -} - -void GLRenderer::drawText(const FontAtlas &font, const std::string &text, - float x, float y, const Color &color) { - float cursorX = x; - float cursorY = y; - float baselineY = cursorY + font.getAscent(); - - // 收集所有字符数据用于批处理 - std::vector sprites; - sprites.reserve(text.size()); // 预分配空间 - - std::u32string utf32_text; - utf32_text.resize(simdutf::utf32_length_from_utf8(text.data(), text.size())); - simdutf::convert_utf8_to_utf32(text.data(), text.size(), utf32_text.data()); - for (char32_t codepoint : utf32_text) { - if (codepoint == '\n') { - cursorX = x; - cursorY += font.getLineHeight(); - baselineY = cursorY + font.getAscent(); - continue; - } - - const Glyph *glyph = font.getGlyph(codepoint); - if (glyph) { - float penX = cursorX; - cursorX += glyph->advance; - - if (glyph->width <= 0.0f || glyph->height <= 0.0f) { - continue; - } - - float xPos = penX + glyph->bearingX; - float yPos = baselineY + glyph->bearingY; - - GLSpriteBatch::SpriteData data; - data.position = glm::vec2(xPos, yPos); - data.size = glm::vec2(glyph->width, glyph->height); - data.texCoordMin = glm::vec2(glyph->u0, glyph->v0); - data.texCoordMax = glm::vec2(glyph->u1, glyph->v1); - data.color = glm::vec4(color.r, color.g, color.b, color.a); - data.rotation = 0.0f; - data.anchor = glm::vec2(0.0f, 0.0f); - data.isSDF = font.isSDF(); - - sprites.push_back(data); - } - } - - // 使用批处理绘制所有字符 - if (!sprites.empty()) { - spriteBatch_.drawBatch(*font.getTexture(), sprites); - } -} - -void GLRenderer::resetStats() { stats_ = Stats{}; } - -void GLRenderer::initShapeRendering() { - // 编译形状着色器 - shapeShader_.compileFromSource(SHAPE_VERTEX_SHADER, SHAPE_FRAGMENT_SHADER); - - // 创建形状 VAO 和 VBO - glGenVertexArrays(1, &shapeVao_); - glGenBuffers(1, &shapeVbo_); - - glBindVertexArray(shapeVao_); - glBindBuffer(GL_ARRAY_BUFFER, shapeVbo_); - glBufferData(GL_ARRAY_BUFFER, MAX_SHAPE_VERTICES * sizeof(ShapeVertex), - nullptr, GL_DYNAMIC_DRAW); - - // 位置属性 (location = 0) - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(ShapeVertex), - reinterpret_cast(offsetof(ShapeVertex, x))); - - // 颜色属性 (location = 1) - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(ShapeVertex), - reinterpret_cast(offsetof(ShapeVertex, r))); - - glBindVertexArray(0); - - // 创建线条专用 VAO 和 VBO - glGenVertexArrays(1, &lineVao_); - glGenBuffers(1, &lineVbo_); - - glBindVertexArray(lineVao_); - glBindBuffer(GL_ARRAY_BUFFER, lineVbo_); - glBufferData(GL_ARRAY_BUFFER, MAX_LINE_VERTICES * sizeof(ShapeVertex), - nullptr, GL_DYNAMIC_DRAW); - - // 位置属性 (location = 0) - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(ShapeVertex), - reinterpret_cast(offsetof(ShapeVertex, x))); - - // 颜色属性 (location = 1) - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(ShapeVertex), - reinterpret_cast(offsetof(ShapeVertex, r))); - - glBindVertexArray(0); - - // VRAM 跟踪 - VRAMManager::getInstance().allocBuffer(MAX_SHAPE_VERTICES * - sizeof(ShapeVertex)); - VRAMManager::getInstance().allocBuffer(MAX_LINE_VERTICES * - sizeof(ShapeVertex)); -} - -void GLRenderer::addShapeVertex(float x, float y, const Color &color) { - if (shapeVertexCount_ >= MAX_SHAPE_VERTICES) { - flushShapeBatch(); - } - ShapeVertex &v = shapeVertexCache_[shapeVertexCount_++]; - v.x = x; - v.y = y; - v.r = color.r; - v.g = color.g; - v.b = color.b; - v.a = color.a; -} - -void GLRenderer::addLineVertex(float x, float y, const Color &color) { - if (lineVertexCount_ >= MAX_LINE_VERTICES) { - flushLineBatch(); - } - ShapeVertex &v = lineVertexCache_[lineVertexCount_++]; - v.x = x; - v.y = y; - v.r = color.r; - v.g = color.g; - v.b = color.b; - v.a = color.a; -} - -void GLRenderer::submitShapeBatch(GLenum mode) { - if (shapeVertexCount_ == 0) - return; - - // 如果模式改变,先刷新 - if (currentShapeMode_ != mode && shapeVertexCount_ > 0) { - flushShapeBatch(); - } - currentShapeMode_ = mode; -} - -void GLRenderer::flushShapeBatch() { - if (shapeVertexCount_ == 0) - return; - - shapeShader_.bind(); - shapeShader_.setMat4("uViewProjection", viewProjection_); - - glBindBuffer(GL_ARRAY_BUFFER, shapeVbo_); - glBufferSubData(GL_ARRAY_BUFFER, 0, shapeVertexCount_ * sizeof(ShapeVertex), - shapeVertexCache_.data()); - - glBindVertexArray(shapeVao_); - glDrawArrays(currentShapeMode_, 0, static_cast(shapeVertexCount_)); - - stats_.drawCalls++; - stats_.triangleCount += static_cast(shapeVertexCount_ / 3); - - shapeVertexCount_ = 0; -} - -void GLRenderer::flushLineBatch() { - if (lineVertexCount_ == 0) - return; - - // 先刷新形状批次 - flushShapeBatch(); - - glLineWidth(currentLineWidth_); - shapeShader_.bind(); - shapeShader_.setMat4("uViewProjection", viewProjection_); - - glBindBuffer(GL_ARRAY_BUFFER, lineVbo_); - glBufferSubData(GL_ARRAY_BUFFER, 0, lineVertexCount_ * sizeof(ShapeVertex), - lineVertexCache_.data()); - - glBindVertexArray(lineVao_); - glDrawArrays(GL_LINES, 0, static_cast(lineVertexCount_)); - - stats_.drawCalls++; - - lineVertexCount_ = 0; -} - -} // namespace extra2d diff --git a/Extra2D/src/render/render_context.cpp b/Extra2D/src/render/render_context.cpp index e9cee7a..df9f1ed 100644 --- a/Extra2D/src/render/render_context.cpp +++ b/Extra2D/src/render/render_context.cpp @@ -1,208 +1,200 @@ +#include #include #include namespace extra2d { -RenderContext& RenderContext::instance() { - static RenderContext instance; - return instance; +RenderContext &RenderContext::instance() { + static RenderContext instance; + return instance; } -bool RenderContext::init() { - if (initialized_) { - return true; - } - - if (!device_.init()) { - return false; - } - - queue_.reserve(RenderQueue::INITIAL_CAPACITY); - - viewport_ = {0, 0, 800, 600}; - scissor_ = {0, 0, 0, 0, false}; - clearColor_ = Color::black(); - - currentBlend_ = BlendState::opaque(); - currentDepth_ = DepthState{}; - currentRaster_ = RasterState{}; - - initialized_ = true; +bool RenderContext::init(SDL_Window *window, const RenderDeviceConfig &config) { + if (initialized_) { return true; + } + + if (!device_.init(window, config)) { + return false; + } + + queue_.reserve(RenderQueue::INITIAL_CAPACITY); + + viewport_ = {0, 0, 800, 600}; + scissor_ = {0, 0, 0, 0, false}; + clearColor_ = Colors::Black; + + currentBlend_ = BlendState::opaque(); + currentDepth_ = DepthState{}; + currentRaster_ = RasterState{}; + + initialized_ = true; + return true; } void RenderContext::shutdown() { - if (!initialized_) { - return; - } + if (!initialized_) { + return; + } - queue_.clear(); - while (!viewportStack_.empty()) viewportStack_.pop(); - while (!scissorStack_.empty()) scissorStack_.pop(); + queue_.clear(); + while (!viewportStack_.empty()) + viewportStack_.pop(); + while (!scissorStack_.empty()) + scissorStack_.pop(); - device_.shutdown(); - initialized_ = false; + device_.shutdown(); + initialized_ = false; } void RenderContext::beginFrame() { - queue_.clear(); - resetStats(); - E2D_RENDER_STATS().reset(); + queue_.clear(); + resetStats(); + E2D_RENDER_STATS().reset(); } -void RenderContext::endFrame() { - flush(); -} +void RenderContext::endFrame() { flush(); } -void RenderContext::submit(const RenderCommand& cmd) { - queue_.addCommand(cmd); -} +void RenderContext::submit(const RenderCommand &cmd) { queue_.addCommand(cmd); } -void RenderContext::submit(RenderCommand&& cmd) { - queue_.addCommand(std::move(cmd)); +void RenderContext::submit(RenderCommand &&cmd) { + queue_.addCommand(std::move(cmd)); } void RenderContext::flush() { - queue_.sort(); + queue_.sort(); - for (const auto& cmd : queue_.commands()) { - executeCommand(cmd); - } + for (const auto &cmd : queue_.commands()) { + executeCommand(cmd); + } - queue_.clear(); + queue_.clear(); } -void RenderContext::executeCommand(const RenderCommand& cmd) { - if (cmd.type == RenderCommandType::None) { - return; +void RenderContext::executeCommand(const RenderCommand &cmd) { + if (cmd.type == RenderCommandType::None) { + return; + } + + if (cmd.type == RenderCommandType::Custom && cmd.customCallback) { + cmd.customCallback(); + return; + } + + if (cmd.blend.enabled != currentBlend_.enabled || + cmd.blend.mode != currentBlend_.mode) { + device_.setBlendState(cmd.blend); + currentBlend_ = cmd.blend; + } + + if (cmd.depth.testEnabled != currentDepth_.testEnabled || + cmd.depth.writeEnabled != currentDepth_.writeEnabled) { + device_.setDepthState(cmd.depth); + currentDepth_ = cmd.depth; + } + + if (cmd.program != currentProgram_) { + device_.bindProgram(cmd.program); + currentProgram_ = cmd.program; + } + + if (cmd.texture != currentTexture_) { + device_.bindTexture(0, cmd.texture); + currentTexture_ = cmd.texture; + } + + if (cmd.vao != currentVAO_) { + if (cmd.vao) { + cmd.vao->bind(); } + currentVAO_ = cmd.vao; + } - if (cmd.type == RenderCommandType::Custom && cmd.customCallback) { - cmd.customCallback(); - return; - } + switch (cmd.type) { + case RenderCommandType::DrawArrays: + device_.drawArrays(cmd.primitive, cmd.firstVertex, cmd.vertexCount); + break; - if (cmd.blend.enabled != currentBlend_.enabled || - cmd.blend.mode != currentBlend_.mode) { - device_.setBlendState(cmd.blend); - currentBlend_ = cmd.blend; - } + case RenderCommandType::DrawElements: + device_.drawElements(cmd.primitive, cmd.indexCount, cmd.indexType, + cmd.indices); + break; - if (cmd.depth.testEnabled != currentDepth_.testEnabled || - cmd.depth.writeEnabled != currentDepth_.writeEnabled) { - device_.setDepthState(cmd.depth); - currentDepth_ = cmd.depth; - } + case RenderCommandType::DrawArraysInstanced: + device_.drawArraysInstanced(cmd.primitive, cmd.firstVertex, cmd.vertexCount, + cmd.instanceCount); + break; - if (cmd.program != currentProgram_) { - device_.bindProgram(cmd.program); - currentProgram_ = cmd.program; - } + case RenderCommandType::DrawElementsInstanced: + device_.drawElementsInstanced(cmd.primitive, cmd.indexCount, cmd.indexType, + cmd.indices, cmd.instanceCount); + break; - if (cmd.texture != currentTexture_) { - device_.bindTexture(0, cmd.texture); - currentTexture_ = cmd.texture; - } - - if (cmd.vao != currentVAO_) { - if (cmd.vao) { - cmd.vao->bind(); - } - currentVAO_ = cmd.vao; - } - - switch (cmd.type) { - case RenderCommandType::DrawArrays: - device_.drawArrays(cmd.primitive, cmd.firstVertex, cmd.vertexCount); - break; - - case RenderCommandType::DrawElements: - device_.drawElements(cmd.primitive, cmd.indexCount, cmd.indexType, cmd.indices); - break; - - case RenderCommandType::DrawArraysInstanced: - device_.drawArraysInstanced(cmd.primitive, cmd.firstVertex, - cmd.vertexCount, cmd.instanceCount); - break; - - case RenderCommandType::DrawElementsInstanced: - device_.drawElementsInstanced(cmd.primitive, cmd.indexCount, - cmd.indexType, cmd.indices, cmd.instanceCount); - break; - - default: - break; - } + default: + break; + } } void RenderContext::setViewport(int32 x, int32 y, int32 width, int32 height) { - viewport_.x = x; - viewport_.y = y; - viewport_.width = width; - viewport_.height = height; - device_.setViewport(x, y, width, height); + viewport_.x = x; + viewport_.y = y; + viewport_.width = width; + viewport_.height = height; + device_.setViewport(x, y, width, height); } -void RenderContext::setViewport(const Viewport& vp) { - viewport_ = vp; - device_.setViewport(vp.x, vp.y, vp.width, vp.height); +void RenderContext::setViewport(const Viewport &vp) { + viewport_ = vp; + device_.setViewport(vp.x, vp.y, vp.width, vp.height); } -void RenderContext::setScissor(const ScissorRect& rect) { - scissor_ = rect; - device_.setScissorEnabled(rect.enabled); - if (rect.enabled) { - device_.setScissor(rect.x, rect.y, rect.width, rect.height); - } +void RenderContext::setScissor(const ScissorRect &rect) { + scissor_ = rect; + device_.setScissorEnabled(rect.enabled); + if (rect.enabled) { + device_.setScissor(rect.x, rect.y, rect.width, rect.height); + } } void RenderContext::setScissor(int32 x, int32 y, int32 width, int32 height) { - scissor_.x = x; - scissor_.y = y; - scissor_.width = width; - scissor_.height = height; - scissor_.enabled = true; - device_.setScissorEnabled(true); - device_.setScissor(x, y, width, height); + scissor_.x = x; + scissor_.y = y; + scissor_.width = width; + scissor_.height = height; + scissor_.enabled = true; + device_.setScissorEnabled(true); + device_.setScissor(x, y, width, height); } -void RenderContext::pushViewport() { - viewportStack_.push(viewport_); -} +void RenderContext::pushViewport() { viewportStack_.push(viewport_); } void RenderContext::popViewport() { - if (!viewportStack_.empty()) { - setViewport(viewportStack_.top()); - viewportStack_.pop(); - } + if (!viewportStack_.empty()) { + setViewport(viewportStack_.top()); + viewportStack_.pop(); + } } -void RenderContext::pushScissor() { - scissorStack_.push(scissor_); -} +void RenderContext::pushScissor() { scissorStack_.push(scissor_); } void RenderContext::popScissor() { - if (!scissorStack_.empty()) { - setScissor(scissorStack_.top()); - scissorStack_.pop(); - } + if (!scissorStack_.empty()) { + setScissor(scissorStack_.top()); + scissorStack_.pop(); + } } -void RenderContext::setClearColor(const Color& color) { - clearColor_ = color; -} +void RenderContext::setClearColor(const Color &color) { clearColor_ = color; } void RenderContext::clear(bool color, bool depth, bool stencil) { - device_.clear(color, depth, stencil, - clearColor_.r, clearColor_.g, clearColor_.b, clearColor_.a); + device_.clear(color, depth, stencil, clearColor_.r, clearColor_.g, + clearColor_.b, clearColor_.a); } -const RenderStats& RenderContext::stats() const { - return E2D_RENDER_STATS().stats(); +const RenderStats &RenderContext::stats() const { + return E2D_RENDER_STATS().stats(); } -void RenderContext::resetStats() { - E2D_RENDER_STATS().reset(); -} +void RenderContext::resetStats() { E2D_RENDER_STATS().reset(); } } // namespace extra2d diff --git a/Extra2D/src/render/render_device.cpp b/Extra2D/src/render/render_device.cpp index d98e663..a25152f 100644 --- a/Extra2D/src/render/render_device.cpp +++ b/Extra2D/src/render/render_device.cpp @@ -1,322 +1,388 @@ +#include #include #include -#include +#include namespace extra2d { -RenderDevice& RenderDevice::instance() { - static RenderDevice instance; - return instance; +RenderDevice &RenderDevice::instance() { + static RenderDevice instance; + return instance; } -bool RenderDevice::init() { - if (initialized_) { - return true; - } - - GLint majorVersion = 0; - GLint minorVersion = 0; - glGetIntegerv(GL_MAJOR_VERSION, &majorVersion); - glGetIntegerv(GL_MINOR_VERSION, &minorVersion); - - if (majorVersion < 4 || (majorVersion == 4 && minorVersion < 5)) { - printf("OpenGL 4.5 is required, got %d.%d\n", majorVersion, minorVersion); - return false; - } - - queryCaps(); - - if (!caps_.dsaSupported) { - printf("OpenGL 4.5 DSA is not supported\n"); - return false; - } - - glEnable(GL_TEXTURE_2D); - - currentBlend_ = BlendState::opaque(); - currentDepth_ = DepthState{}; - currentRaster_ = RasterState{}; - - initialized_ = true; +bool RenderDevice::init(SDL_Window *window, const RenderDeviceConfig &config) { + if (initialized_) return true; + + window_ = window; + + if (!initGL(config)) { + return false; + } + + queryCaps(); + + currentBlend_ = BlendState::opaque(); + currentDepth_ = DepthState{}; + currentRaster_ = RasterState{}; + + initialized_ = true; + + E2D_INFO("RenderDevice initialized"); + E2D_INFO("OpenGL Version: {}", caps_.version); + E2D_INFO("OpenGL Renderer: {}", caps_.renderer); + E2D_INFO("GLSL Version: {}", caps_.glslVersion); + + return true; +} + +bool RenderDevice::initGL(const RenderDeviceConfig &config) { + if (config.useES) { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + } else { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, + SDL_GL_CONTEXT_PROFILE_CORE); + } + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, config.glMajor); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, config.glMinor); + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, config.redBits); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, config.greenBits); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, config.blueBits); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, config.alphaBits); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, config.depthBits); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, config.stencilBits); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, config.doubleBuffer ? 1 : 0); + + if (config.msaaSamples > 0) { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, config.msaaSamples); + } + + glContext_ = SDL_GL_CreateContext(window_); + if (!glContext_) { + E2D_ERROR("SDL_GL_CreateContext failed: {}", SDL_GetError()); + return false; + } + + if (SDL_GL_MakeCurrent(window_, glContext_) != 0) { + E2D_ERROR("SDL_GL_MakeCurrent failed: {}", SDL_GetError()); + SDL_GL_DeleteContext(glContext_); + glContext_ = nullptr; + return false; + } + + if (gladLoadGLLoader(reinterpret_cast(SDL_GL_GetProcAddress)) == + 0) { + E2D_ERROR("gladLoadGLLoader failed"); + SDL_GL_DeleteContext(glContext_); + glContext_ = nullptr; + return false; + } + + SDL_GL_SetSwapInterval(config.vsync ? 1 : 0); + + return true; } void RenderDevice::shutdown() { - if (!initialized_) { - return; - } + if (!initialized_) + return; - currentProgram_ = 0; - initialized_ = false; + if (glContext_) { + SDL_GL_DeleteContext(glContext_); + glContext_ = nullptr; + } + + window_ = nullptr; + currentProgram_ = 0; + initialized_ = false; + + E2D_INFO("RenderDevice shutdown"); +} + +void RenderDevice::swapBuffers() { + if (window_) { + SDL_GL_SwapWindow(window_); + } +} + +void RenderDevice::setVSync(bool enabled) { + SDL_GL_SetSwapInterval(enabled ? 1 : 0); } void RenderDevice::queryCaps() { - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &caps_.maxTextureSize); - glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &caps_.maxTextureUnits); - glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &caps_.maxVertexAttribs); - glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &caps_.maxUniformBlockBindings); - glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &caps_.maxUniformBlockSize); - glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &caps_.maxVertexUniformComponents); - glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &caps_.maxFragmentUniformComponents); - glGetIntegerv(GL_MAX_DRAW_BUFFERS, &caps_.maxDrawBuffers); - glGetIntegerv(GL_MAX_SAMPLES, &caps_.maxSamples); + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &caps_.maxTextureSize); + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &caps_.maxTextureUnits); + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &caps_.maxVertexAttribs); + glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &caps_.maxUniformBlockBindings); + glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &caps_.maxUniformBlockSize); + glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, + &caps_.maxVertexUniformComponents); + glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, + &caps_.maxFragmentUniformComponents); + glGetIntegerv(GL_MAX_DRAW_BUFFERS, &caps_.maxDrawBuffers); + glGetIntegerv(GL_MAX_SAMPLES, &caps_.maxSamples); - GLint majorVersion = 0; - GLint minorVersion = 0; - glGetIntegerv(GL_MAJOR_VERSION, &majorVersion); - glGetIntegerv(GL_MINOR_VERSION, &minorVersion); - caps_.dsaSupported = (majorVersion > 4 || (majorVersion == 4 && minorVersion >= 5)); + GLint majorVersion = 0; + GLint minorVersion = 0; + glGetIntegerv(GL_MAJOR_VERSION, &majorVersion); + glGetIntegerv(GL_MINOR_VERSION, &minorVersion); + caps_.dsaSupported = + (majorVersion > 4 || (majorVersion == 4 && minorVersion >= 5)); - GLint extensions = 0; - glGetIntegerv(GL_NUM_EXTENSIONS, &extensions); - for (GLint i = 0; i < extensions; ++i) { - String ext = reinterpret_cast(glGetStringi(GL_EXTENSIONS, i)); - if (ext.find("compute_shader") != String::npos) { - caps_.computeSupported = true; - } - if (ext.find("tessellation_shader") != String::npos) { - caps_.tessellationSupported = true; - } - if (ext.find("geometry_shader") != String::npos) { - caps_.geometryShaderSupported = true; - } - } - - caps_.renderer = reinterpret_cast(glGetString(GL_RENDERER)); - caps_.vendor = reinterpret_cast(glGetString(GL_VENDOR)); - caps_.version = reinterpret_cast(glGetString(GL_VERSION)); - caps_.glslVersion = reinterpret_cast(glGetString(GL_SHADING_LANGUAGE_VERSION)); + caps_.renderer = reinterpret_cast(glGetString(GL_RENDERER)); + caps_.vendor = reinterpret_cast(glGetString(GL_VENDOR)); + caps_.version = reinterpret_cast(glGetString(GL_VERSION)); + caps_.glslVersion = + reinterpret_cast(glGetString(GL_SHADING_LANGUAGE_VERSION)); } -std::unique_ptr RenderDevice::createBuffer(BufferType type, BufferUsage usage, - size_t size, const void* data) { - auto buffer = std::make_unique(); - if (!buffer->create(type, usage, size, data)) { - return nullptr; - } - return buffer; +std::unique_ptr RenderDevice::createBuffer(BufferType type, + BufferUsage usage, + size_t size, + const void *data) { + auto buffer = std::make_unique(); + if (!buffer->create(type, usage, size, data)) { + return nullptr; + } + return buffer; } -std::unique_ptr RenderDevice::createVertexBuffer(BufferUsage usage, size_t size, - const void* data) { - auto buffer = std::make_unique(); - if (!buffer->create(usage, size, data)) { - return nullptr; - } - return buffer; +std::unique_ptr +RenderDevice::createVertexBuffer(BufferUsage usage, size_t size, + const void *data) { + auto buffer = std::make_unique(); + if (!buffer->create(usage, size, data)) { + return nullptr; + } + return buffer; } -std::unique_ptr RenderDevice::createIndexBuffer(BufferUsage usage, size_t size, - const void* data) { - auto buffer = std::make_unique(); - if (!buffer->create(usage, size, data)) { - return nullptr; - } - return buffer; +std::unique_ptr RenderDevice::createIndexBuffer(BufferUsage usage, + size_t size, + const void *data) { + auto buffer = std::make_unique(); + if (!buffer->create(usage, size, data)) { + return nullptr; + } + return buffer; } -std::unique_ptr RenderDevice::createUniformBuffer(BufferUsage usage, size_t size, - const void* data) { - auto buffer = std::make_unique(); - if (!buffer->create(usage, size, data)) { - return nullptr; - } - return buffer; +std::unique_ptr +RenderDevice::createUniformBuffer(BufferUsage usage, size_t size, + const void *data) { + auto buffer = std::make_unique(); + if (!buffer->create(usage, size, data)) { + return nullptr; + } + return buffer; } std::unique_ptr RenderDevice::createVAO() { - auto vao = std::make_unique(); - if (!vao->create()) { - return nullptr; - } - return vao; + auto vao = std::make_unique(); + if (!vao->create()) { + return nullptr; + } + return vao; } void RenderDevice::setViewport(int32 x, int32 y, int32 width, int32 height) { - glViewport(x, y, width, height); + glViewport(x, y, width, height); } void RenderDevice::setScissor(int32 x, int32 y, int32 width, int32 height) { - glScissor(x, y, width, height); + glScissor(x, y, width, height); } void RenderDevice::setScissorEnabled(bool enabled) { - if (enabled) { - glEnable(GL_SCISSOR_TEST); - } else { - glDisable(GL_SCISSOR_TEST); - } + if (enabled) { + glEnable(GL_SCISSOR_TEST); + } else { + glDisable(GL_SCISSOR_TEST); + } } -void RenderDevice::clear(bool color, bool depth, bool stencil, - float r, float g, float b, float a) { - GLbitfield mask = 0; - if (color) { - glClearColor(r, g, b, a); - mask |= GL_COLOR_BUFFER_BIT; - } - if (depth) { - glClearDepth(1.0); - mask |= GL_DEPTH_BUFFER_BIT; - } - if (stencil) { - glClearStencil(0); - mask |= GL_STENCIL_BUFFER_BIT; - } - glClear(mask); +void RenderDevice::clear(bool color, bool depth, bool stencil, float r, float g, + float b, float a) { + GLbitfield mask = 0; + if (color) { + glClearColor(r, g, b, a); + mask |= GL_COLOR_BUFFER_BIT; + } + if (depth) { + glClearDepth(1.0); + mask |= GL_DEPTH_BUFFER_BIT; + } + if (stencil) { + glClearStencil(0); + mask |= GL_STENCIL_BUFFER_BIT; + } + glClear(mask); } -void RenderDevice::setBlendState(const BlendState& state) { - if (state.enabled != currentBlend_.enabled) { - if (state.enabled) { - glEnable(GL_BLEND); - } else { - glDisable(GL_BLEND); - } - E2D_RENDER_STATS().addStateChange(); - } - +void RenderDevice::setBlendState(const BlendState &state) { + if (state.enabled != currentBlend_.enabled) { if (state.enabled) { - if (state.srcRGB != currentBlend_.srcRGB || - state.dstRGB != currentBlend_.dstRGB || - state.srcAlpha != currentBlend_.srcAlpha || - state.dstAlpha != currentBlend_.dstAlpha) { - glBlendFuncSeparate( - static_cast(state.srcRGB) + GL_ZERO, - static_cast(state.dstRGB) + GL_ZERO, - static_cast(state.srcAlpha) + GL_ZERO, - static_cast(state.dstAlpha) + GL_ZERO - ); - E2D_RENDER_STATS().addStateChange(); - } + glEnable(GL_BLEND); + } else { + glDisable(GL_BLEND); + } + E2D_RENDER_STATS().addStateChange(); + } - if (state.opRGB != currentBlend_.opRGB || state.opAlpha != currentBlend_.opAlpha) { - glBlendEquationSeparate( - static_cast(state.opRGB) + GL_FUNC_ADD, - static_cast(state.opAlpha) + GL_FUNC_ADD - ); - E2D_RENDER_STATS().addStateChange(); - } - - if (state.colorWriteMask != currentBlend_.colorWriteMask) { - glColorMask( - (state.colorWriteMask & 0x1) != 0, - (state.colorWriteMask & 0x2) != 0, - (state.colorWriteMask & 0x4) != 0, - (state.colorWriteMask & 0x8) != 0 - ); - E2D_RENDER_STATS().addStateChange(); - } + if (state.enabled) { + if (state.srcRGB != currentBlend_.srcRGB || + state.dstRGB != currentBlend_.dstRGB || + state.srcAlpha != currentBlend_.srcAlpha || + state.dstAlpha != currentBlend_.dstAlpha) { + glBlendFuncSeparate(static_cast(state.srcRGB) + GL_ZERO, + static_cast(state.dstRGB) + GL_ZERO, + static_cast(state.srcAlpha) + GL_ZERO, + static_cast(state.dstAlpha) + GL_ZERO); + E2D_RENDER_STATS().addStateChange(); } - currentBlend_ = state; + if (state.opRGB != currentBlend_.opRGB || + state.opAlpha != currentBlend_.opAlpha) { + glBlendEquationSeparate(static_cast(state.opRGB) + GL_FUNC_ADD, + static_cast(state.opAlpha) + GL_FUNC_ADD); + E2D_RENDER_STATS().addStateChange(); + } + + if (state.colorWriteMask != currentBlend_.colorWriteMask) { + glColorMask( + (state.colorWriteMask & 0x1) != 0, (state.colorWriteMask & 0x2) != 0, + (state.colorWriteMask & 0x4) != 0, (state.colorWriteMask & 0x8) != 0); + E2D_RENDER_STATS().addStateChange(); + } + } + + currentBlend_ = state; } -void RenderDevice::setDepthState(const DepthState& state) { - if (state.testEnabled != currentDepth_.testEnabled) { - if (state.testEnabled) { - glEnable(GL_DEPTH_TEST); - } else { - glDisable(GL_DEPTH_TEST); - } - E2D_RENDER_STATS().addStateChange(); +void RenderDevice::setDepthState(const DepthState &state) { + if (state.testEnabled != currentDepth_.testEnabled) { + if (state.testEnabled) { + glEnable(GL_DEPTH_TEST); + } else { + glDisable(GL_DEPTH_TEST); } + E2D_RENDER_STATS().addStateChange(); + } - if (state.testEnabled && state.compareFunc != currentDepth_.compareFunc) { - glDepthFunc(static_cast(state.compareFunc) + GL_NEVER); - E2D_RENDER_STATS().addStateChange(); - } + if (state.testEnabled && state.compareFunc != currentDepth_.compareFunc) { + glDepthFunc(static_cast(state.compareFunc) + GL_NEVER); + E2D_RENDER_STATS().addStateChange(); + } - if (state.writeEnabled != currentDepth_.writeEnabled) { - glDepthMask(state.writeEnabled ? GL_TRUE : GL_FALSE); - E2D_RENDER_STATS().addStateChange(); - } + if (state.writeEnabled != currentDepth_.writeEnabled) { + glDepthMask(state.writeEnabled ? GL_TRUE : GL_FALSE); + E2D_RENDER_STATS().addStateChange(); + } - currentDepth_ = state; + currentDepth_ = state; } -void RenderDevice::setRasterState(const RasterState& state) { - if (state.cullMode != currentRaster_.cullMode) { - if (state.cullMode == CullMode::None) { - glDisable(GL_CULL_FACE); - } else { - glEnable(GL_CULL_FACE); - glCullFace(state.cullMode == CullMode::Front ? GL_FRONT : GL_BACK); - } - E2D_RENDER_STATS().addStateChange(); +void RenderDevice::setRasterState(const RasterState &state) { + if (state.cullMode != currentRaster_.cullMode) { + if (state.cullMode == CullMode::None) { + glDisable(GL_CULL_FACE); + } else { + glEnable(GL_CULL_FACE); + glCullFace(state.cullMode == CullMode::Front ? GL_FRONT : GL_BACK); } + E2D_RENDER_STATS().addStateChange(); + } - if (state.polygonMode != currentRaster_.polygonMode) { - glPolygonMode(GL_FRONT_AND_BACK, - state.polygonMode == PolygonMode::Line ? GL_LINE : - (state.polygonMode == PolygonMode::Point ? GL_POINT : GL_FILL)); - E2D_RENDER_STATS().addStateChange(); - } + if (state.polygonMode != currentRaster_.polygonMode) { + glPolygonMode( + GL_FRONT_AND_BACK, + state.polygonMode == PolygonMode::Line + ? GL_LINE + : (state.polygonMode == PolygonMode::Point ? GL_POINT : GL_FILL)); + E2D_RENDER_STATS().addStateChange(); + } - if (state.lineWidth != currentRaster_.lineWidth) { - glLineWidth(state.lineWidth); - } + if (state.lineWidth != currentRaster_.lineWidth) { + glLineWidth(state.lineWidth); + } - currentRaster_ = state; + currentRaster_ = state; } void RenderDevice::bindTexture(uint32 unit, GLuint texture) { - glBindTextureUnit(unit, texture); - E2D_RENDER_STATS().addTextureBind(); + glBindTextureUnit(unit, texture); + E2D_RENDER_STATS().addTextureBind(); } void RenderDevice::bindProgram(GLuint program) { - if (program != currentProgram_) { - glUseProgram(program); - currentProgram_ = program; - E2D_RENDER_STATS().addShaderBind(); - } + if (program != currentProgram_) { + glUseProgram(program); + currentProgram_ = program; + E2D_RENDER_STATS().addShaderBind(); + } } void RenderDevice::drawArrays(PrimitiveType mode, int32 first, int32 count) { - glDrawArrays(glPrimitiveType(mode), first, count); - E2D_RENDER_STATS().addDrawCall(count, count / 3); + glDrawArrays(glPrimitiveType(mode), first, count); + E2D_RENDER_STATS().addDrawCall(count, count / 3); } -void RenderDevice::drawElements(PrimitiveType mode, int32 count, IndexType type, - const void* indices) { - glDrawElements(glPrimitiveType(mode), count, glIndexType(type), indices); - E2D_RENDER_STATS().addDrawCall(count, count / 3); +void RenderDevice::drawElements(PrimitiveType mode, int32 count, IndexType type, + const void *indices) { + glDrawElements(glPrimitiveType(mode), count, glIndexType(type), indices); + E2D_RENDER_STATS().addDrawCall(count, count / 3); } -void RenderDevice::drawArraysInstanced(PrimitiveType mode, int32 first, - int32 count, int32 instanceCount) { - glDrawArraysInstanced(glPrimitiveType(mode), first, count, instanceCount); - E2D_RENDER_STATS().addDrawCall(count * instanceCount, (count / 3) * instanceCount); +void RenderDevice::drawArraysInstanced(PrimitiveType mode, int32 first, + int32 count, int32 instanceCount) { + glDrawArraysInstanced(glPrimitiveType(mode), first, count, instanceCount); + E2D_RENDER_STATS().addDrawCall(count * instanceCount, + (count / 3) * instanceCount); } -void RenderDevice::drawElementsInstanced(PrimitiveType mode, int32 count, IndexType type, - const void* indices, int32 instanceCount) { - glDrawElementsInstanced(glPrimitiveType(mode), count, glIndexType(type), - indices, instanceCount); - E2D_RENDER_STATS().addDrawCall(count * instanceCount, (count / 3) * instanceCount); +void RenderDevice::drawElementsInstanced(PrimitiveType mode, int32 count, + IndexType type, const void *indices, + int32 instanceCount) { + glDrawElementsInstanced(glPrimitiveType(mode), count, glIndexType(type), + indices, instanceCount); + E2D_RENDER_STATS().addDrawCall(count * instanceCount, + (count / 3) * instanceCount); } GLenum RenderDevice::glPrimitiveType(PrimitiveType mode) const { - switch (mode) { - case PrimitiveType::Points: return GL_POINTS; - case PrimitiveType::Lines: return GL_LINES; - case PrimitiveType::LineStrip: return GL_LINE_STRIP; - case PrimitiveType::LineLoop: return GL_LINE_LOOP; - case PrimitiveType::Triangles: return GL_TRIANGLES; - case PrimitiveType::TriangleStrip: return GL_TRIANGLE_STRIP; - case PrimitiveType::TriangleFan: return GL_TRIANGLE_FAN; - default: return GL_TRIANGLES; - } + switch (mode) { + case PrimitiveType::Points: + return GL_POINTS; + case PrimitiveType::Lines: + return GL_LINES; + case PrimitiveType::LineStrip: + return GL_LINE_STRIP; + case PrimitiveType::LineLoop: + return GL_LINE_LOOP; + case PrimitiveType::Triangles: + return GL_TRIANGLES; + case PrimitiveType::TriangleStrip: + return GL_TRIANGLE_STRIP; + case PrimitiveType::TriangleFan: + return GL_TRIANGLE_FAN; + default: + return GL_TRIANGLES; + } } GLenum RenderDevice::glIndexType(IndexType type) const { - switch (type) { - case IndexType::UInt8: return GL_UNSIGNED_BYTE; - case IndexType::UInt16: return GL_UNSIGNED_SHORT; - case IndexType::UInt32: return GL_UNSIGNED_INT; - default: return GL_UNSIGNED_INT; - } + switch (type) { + case IndexType::UInt8: + return GL_UNSIGNED_BYTE; + case IndexType::UInt16: + return GL_UNSIGNED_SHORT; + case IndexType::UInt32: + return GL_UNSIGNED_INT; + default: + return GL_UNSIGNED_INT; + } } } // namespace extra2d diff --git a/Extra2D/src/render/renderer.cpp b/Extra2D/src/render/renderer.cpp new file mode 100644 index 0000000..a91ecd2 --- /dev/null +++ b/Extra2D/src/render/renderer.cpp @@ -0,0 +1,219 @@ +#include +#include + +namespace extra2d { + +Renderer::Renderer() = default; +Renderer::~Renderer() = default; + +bool Renderer::init() { + shapeRenderer_ = std::make_unique(); + if (!shapeRenderer_->init()) { + return false; + } + + spriteRenderer_ = std::make_unique(); + if (!spriteRenderer_->init()) { + shapeRenderer_->shutdown(); + return false; + } + + return true; +} + +void Renderer::shutdown() { + if (spriteRenderer_) { + spriteRenderer_->shutdown(); + spriteRenderer_.reset(); + } + if (shapeRenderer_) { + shapeRenderer_->shutdown(); + shapeRenderer_.reset(); + } +} + +void Renderer::beginFrame(const Color& clearColor) { + auto& ctx = RenderContext::instance(); + ctx.beginFrame(); + ctx.setClearColor(clearColor); + ctx.clear(true, true, false); + inFrame_ = true; +} + +void Renderer::endFrame() { + if (!inFrame_) { + return; + } + + if (spriteRenderer_) { + spriteRenderer_->end(); + } + if (shapeRenderer_) { + shapeRenderer_->end(); + } + + auto& ctx = RenderContext::instance(); + ctx.endFrame(); + inFrame_ = false; +} + +void Renderer::setViewProjection(const glm::mat4& viewProjection) { + viewProjection_ = viewProjection; + + if (shapeRenderer_) { + shapeRenderer_->end(); + shapeRenderer_->begin(viewProjection_); + } + if (spriteRenderer_) { + spriteRenderer_->end(); + spriteRenderer_->begin(viewProjection_); + } +} + +void Renderer::drawLine(const Vec2& start, const Vec2& end, + const Color& color, float width) { + if (shapeRenderer_) { + shapeRenderer_->drawLine(start.x, start.y, end.x, end.y, + toVec4(color), width); + } +} + +void Renderer::drawRect(const Rect& rect, const Color& color, float width) { + if (shapeRenderer_) { + shapeRenderer_->drawRect(rect.origin.x, rect.origin.y, + rect.size.width, rect.size.height, + toVec4(color), width); + } +} + +void Renderer::fillRect(const Rect& rect, const Color& color) { + if (shapeRenderer_) { + shapeRenderer_->fillRect(rect.origin.x, rect.origin.y, + rect.size.width, rect.size.height, + toVec4(color)); + } +} + +void Renderer::drawCircle(const Vec2& center, float radius, const Color& color, + int segments, float width) { + if (shapeRenderer_) { + shapeRenderer_->drawCircle(center.x, center.y, radius, + toVec4(color), width, segments); + } +} + +void Renderer::fillCircle(const Vec2& center, float radius, + const Color& color, int segments) { + if (shapeRenderer_) { + shapeRenderer_->fillCircle(center.x, center.y, radius, + toVec4(color), segments); + } +} + +void Renderer::drawTriangle(const Vec2& p1, const Vec2& p2, const Vec2& p3, + const Color& color, float width) { + if (shapeRenderer_) { + shapeRenderer_->drawLine(p1.x, p1.y, p2.x, p2.y, toVec4(color), width); + shapeRenderer_->drawLine(p2.x, p2.y, p3.x, p3.y, toVec4(color), width); + shapeRenderer_->drawLine(p3.x, p3.y, p1.x, p1.y, toVec4(color), width); + } +} + +void Renderer::fillTriangle(const Vec2& p1, const Vec2& p2, const Vec2& p3, + const Color& color) { + if (shapeRenderer_) { + shapeRenderer_->fillTriangle(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, + toVec4(color)); + } +} + +void Renderer::drawPolygon(const std::vector& points, const Color& color, + float width) { + if (shapeRenderer_ && points.size() >= 2) { + std::vector glmPoints; + glmPoints.reserve(points.size()); + for (const auto& p : points) { + glmPoints.emplace_back(p.x, p.y); + } + shapeRenderer_->drawPolygon(glmPoints.data(), glmPoints.size(), + toVec4(color), width); + } +} + +void Renderer::fillPolygon(const std::vector& points, const Color& color) { + if (shapeRenderer_ && points.size() >= 3) { + std::vector glmPoints; + glmPoints.reserve(points.size()); + for (const auto& p : points) { + glmPoints.emplace_back(p.x, p.y); + } + shapeRenderer_->fillPolygon(glmPoints.data(), glmPoints.size(), + toVec4(color)); + } +} + +void Renderer::drawSprite(const Texture& texture, const Rect& destRect, + const Rect& srcRect, const Color& color, + float rotation, const Vec2& anchor) { + if (spriteRenderer_ && texture.isValid()) { + SpriteData data; + data.position = glm::vec2(destRect.origin.x, destRect.origin.y); + data.size = glm::vec2(destRect.size.width, destRect.size.height); + data.anchor = glm::vec2(anchor.x, anchor.y); + data.color = toVec4(color); + data.texRect = glm::vec4( + srcRect.origin.x / static_cast(texture.width()), + srcRect.origin.y / static_cast(texture.height()), + srcRect.size.width / static_cast(texture.width()), + srcRect.size.height / static_cast(texture.height()) + ); + data.rotation = rotation; + + spriteRenderer_->draw(texture.glHandle(), data); + } +} + +void Renderer::drawSprite(const Texture& texture, const Vec2& position, + const Color& color) { + if (texture.isValid()) { + Rect destRect(position.x, position.y, + static_cast(texture.width()), + static_cast(texture.height())); + Rect srcRect(0, 0, static_cast(texture.width()), + static_cast(texture.height())); + drawSprite(texture, destRect, srcRect, color); + } +} + +void Renderer::drawSprite(const Texture& texture, const Vec2& position, + const Vec2& scale, const Color& color) { + if (texture.isValid()) { + Rect destRect(position.x, position.y, + static_cast(texture.width()) * scale.x, + static_cast(texture.height()) * scale.y); + Rect srcRect(0, 0, static_cast(texture.width()), + static_cast(texture.height())); + drawSprite(texture, destRect, srcRect, color); + } +} + +uint32 Renderer::drawCalls() const { + uint32 calls = 0; + if (shapeRenderer_) { + calls += shapeRenderer_->drawCalls(); + } + if (spriteRenderer_) { + calls += spriteRenderer_->drawCalls(); + } + return calls; +} + +uint32 Renderer::spriteCount() const { + return spriteRenderer_ ? spriteRenderer_->spriteCount() : 0; +} + +glm::vec4 Renderer::toVec4(const Color& color) const { + return glm::vec4(color.r, color.g, color.b, color.a); +} + +} // namespace extra2d diff --git a/Extra2D/src/render/texture.cpp b/Extra2D/src/render/texture.cpp new file mode 100644 index 0000000..1e4b0ff --- /dev/null +++ b/Extra2D/src/render/texture.cpp @@ -0,0 +1,189 @@ +#include +#include + +namespace extra2d { + +Texture::~Texture() { + if (glHandle_ != 0) { + glDeleteTextures(1, &glHandle_); + glHandle_ = 0; + } +} + +std::unique_ptr Texture::create(const u8 *data, + const TextureConfig &config) { + auto texture = std::make_unique(); + if (!texture->init(data, config)) { + return nullptr; + } + return texture; +} + +std::unique_ptr Texture::createEmpty(int width, int height, + int channels) { + TextureConfig config; + config.width = width; + config.height = height; + config.channels = channels; + return create(nullptr, config); +} + +bool Texture::init(const u8 *data, const TextureConfig &config) { + width_ = config.width; + height_ = config.height; + channels_ = config.channels; + + glCreateTextures(GL_TEXTURE_2D, 1, &glHandle_); + if (glHandle_ == 0) { + return false; + } + + glTextureStorage2D(glHandle_, 1, glInternalFormat(), width_, height_); + + if (data != nullptr) { + glTextureSubImage2D(glHandle_, 0, 0, 0, width_, height_, glFormat(), + GL_UNSIGNED_BYTE, data); + } + + setFilter(config.filter); + setWrap(config.wrap); + + if (config.generateMips) { + glGenerateTextureMipmap(glHandle_); + } + + return true; +} + +void Texture::update(const u8 *data, int width, int height, int channels) { + if (glHandle_ == 0) { + return; + } + + if (width != width_ || height != height_ || channels != channels_) { + glDeleteTextures(1, &glHandle_); + width_ = width; + height_ = height; + channels_ = channels; + glCreateTextures(GL_TEXTURE_2D, 1, &glHandle_); + glTextureStorage2D(glHandle_, 1, glInternalFormat(), width_, height_); + } + + glTextureSubImage2D(glHandle_, 0, 0, 0, width_, height_, glFormat(), + GL_UNSIGNED_BYTE, data); +} + +void Texture::updateSubRegion(const u8 *data, int x, int y, int width, + int height) { + if (glHandle_ == 0) { + return; + } + + glTextureSubImage2D(glHandle_, 0, x, y, width, height, glFormat(), + GL_UNSIGNED_BYTE, data); +} + +void Texture::bind(uint32 unit) const { + if (glHandle_ != 0) { + glBindTextureUnit(unit, glHandle_); + } +} + +void Texture::unbind() const { glBindTextureUnit(0, 0); } + +void Texture::setFilter(FilterMode filter) { + if (glHandle_ == 0) { + return; + } + + GLenum minFilter, magFilter; + switch (filter) { + case FilterMode::Nearest: + minFilter = GL_NEAREST; + magFilter = GL_NEAREST; + break; + case FilterMode::NearestMipmapNearest: + minFilter = GL_NEAREST_MIPMAP_NEAREST; + magFilter = GL_NEAREST; + break; + case FilterMode::LinearMipmapNearest: + minFilter = GL_LINEAR_MIPMAP_NEAREST; + magFilter = GL_LINEAR; + break; + case FilterMode::NearestMipmapLinear: + minFilter = GL_NEAREST_MIPMAP_LINEAR; + magFilter = GL_NEAREST; + break; + case FilterMode::LinearMipmapLinear: + minFilter = GL_LINEAR_MIPMAP_LINEAR; + magFilter = GL_LINEAR; + break; + case FilterMode::Linear: + default: + minFilter = GL_LINEAR; + magFilter = GL_LINEAR; + break; + } + + glTextureParameteri(glHandle_, GL_TEXTURE_MIN_FILTER, minFilter); + glTextureParameteri(glHandle_, GL_TEXTURE_MAG_FILTER, magFilter); +} + +void Texture::setWrap(WrapMode wrap) { + if (glHandle_ == 0) { + return; + } + + GLenum glWrap; + switch (wrap) { + case WrapMode::Repeat: + glWrap = GL_REPEAT; + break; + case WrapMode::Mirror: + glWrap = GL_MIRRORED_REPEAT; + break; + case WrapMode::MirrorClamp: + glWrap = GL_MIRROR_CLAMP_TO_EDGE; + break; + case WrapMode::Border: + glWrap = GL_CLAMP_TO_BORDER; + break; + case WrapMode::Clamp: + default: + glWrap = GL_CLAMP_TO_EDGE; + break; + } + + glTextureParameteri(glHandle_, GL_TEXTURE_WRAP_S, glWrap); + glTextureParameteri(glHandle_, GL_TEXTURE_WRAP_T, glWrap); +} + +GLenum Texture::glInternalFormat() const { + switch (channels_) { + case 1: + return GL_R8; + case 2: + return GL_RG8; + case 3: + return GL_RGB8; + case 4: + default: + return GL_RGBA8; + } +} + +GLenum Texture::glFormat() const { + switch (channels_) { + case 1: + return GL_RED; + case 2: + return GL_RG; + case 3: + return GL_RGB; + case 4: + default: + return GL_RGBA; + } +} + +} // namespace extra2d diff --git a/Extra2D/src/scene/node.cpp b/Extra2D/src/scene/node.cpp index dbe10f5..8ea13ca 100644 --- a/Extra2D/src/scene/node.cpp +++ b/Extra2D/src/scene/node.cpp @@ -1,461 +1,430 @@ #include #include -#include #include #include -#include +#include namespace extra2d { Node::Node() = default; -Node::~Node() { removeAllChildren(); } - -void Node::addChild(Ptr child) { - if (!child || child.get() == this) { - return; - } - - child->removeFromParent(); - child->parent_ = weak_from_this(); - children_.push_back(child); - childrenOrderDirty_ = true; - - // 更新索引 - if (!child->getName().empty()) { - nameIndex_[child->getName()] = child; - } - if (child->getTag() != -1) { - tagIndex_[child->getTag()] = child; - } - - if (running_) { - child->onEnter(); - if (scene_) { - child->onAttachToScene(scene_); - } - } +Node::~Node() { + removeAllChildren(); } -void Node::addChildren(std::vector> &&children) { - // 预留空间,避免多次扩容 - size_t newSize = children_.size() + children.size(); - if (newSize > children_.capacity()) { - children_.reserve(newSize); - } - - for (auto &child : children) { +void Node::addChild(Ref child) { if (!child || child.get() == this) { - continue; + return; } child->removeFromParent(); child->parent_ = weak_from_this(); children_.push_back(child); + childrenOrderDirty_ = true; - // 更新索引 if (!child->getName().empty()) { - nameIndex_[child->getName()] = child; + nameIndex_[child->getName()] = child; } if (child->getTag() != -1) { - tagIndex_[child->getTag()] = child; + tagIndex_[child->getTag()] = child; } if (running_) { - child->onEnter(); - if (scene_) { - child->onAttachToScene(scene_); - } + child->onEnter(); + if (scene_) { + child->onAttachToScene(scene_); + } } - } - - if (!children.empty()) { - childrenOrderDirty_ = true; - } } -void Node::removeChild(Ptr child) { - if (!child) - return; +void Node::addChildren(std::vector>&& children) { + size_t newSize = children_.size() + children.size(); + if (newSize > children_.capacity()) { + children_.reserve(newSize); + } - auto it = std::find(children_.begin(), children_.end(), child); - if (it != children_.end()) { - // 始终从空间索引中移除(无论 running_ 状态) - // 这确保节点被正确清理 - (*it)->onDetachFromScene(); + for (auto& child : children) { + if (!child || child.get() == this) { + continue; + } - if (running_) { - (*it)->onExit(); + child->removeFromParent(); + child->parent_ = weak_from_this(); + children_.push_back(child); + + if (!child->getName().empty()) { + nameIndex_[child->getName()] = child; + } + if (child->getTag() != -1) { + tagIndex_[child->getTag()] = child; + } + + if (running_) { + child->onEnter(); + if (scene_) { + child->onAttachToScene(scene_); + } + } } - // 从索引中移除 - if (!(*it)->getName().empty()) { - nameIndex_.erase((*it)->getName()); + + if (!children.empty()) { + childrenOrderDirty_ = true; } - if ((*it)->getTag() != -1) { - tagIndex_.erase((*it)->getTag()); - } - (*it)->parent_.reset(); - children_.erase(it); - } } -void Node::removeChildByName(const std::string &name) { - auto child = getChildByName(name); - if (child) { - removeChild(child); - } +void Node::removeChild(Ref child) { + if (!child) { + return; + } + + auto it = std::find(children_.begin(), children_.end(), child); + if (it != children_.end()) { + (*it)->onDetachFromScene(); + + if (running_) { + (*it)->onExit(); + } + + if (!(*it)->getName().empty()) { + nameIndex_.erase((*it)->getName()); + } + if ((*it)->getTag() != -1) { + tagIndex_.erase((*it)->getTag()); + } + (*it)->parent_.reset(); + children_.erase(it); + } +} + +void Node::removeChildByName(const std::string& name) { + auto child = getChildByName(name); + if (child) { + removeChild(child); + } } void Node::removeFromParent() { - auto p = parent_.lock(); - if (p) { - // 安全获取 shared_ptr,避免在对象未由 shared_ptr 管理时崩溃 - Ptr self; - try { - self = shared_from_this(); - } catch (const std::bad_weak_ptr &) { - // 对象不是由 shared_ptr 管理的,直接重置父节点引用 - parent_.reset(); - return; + auto p = parent_.lock(); + if (p) { + Ref self; + try { + self = shared_from_this(); + } catch (const std::bad_weak_ptr&) { + parent_.reset(); + return; + } + p->removeChild(self); } - p->removeChild(self); - } } void Node::removeAllChildren() { - for (auto &child : children_) { - if (running_) { - child->onDetachFromScene(); - child->onExit(); + for (auto& child : children_) { + if (running_) { + child->onDetachFromScene(); + child->onExit(); + } + child->parent_.reset(); } - child->parent_.reset(); - } - children_.clear(); - nameIndex_.clear(); - tagIndex_.clear(); + children_.clear(); + nameIndex_.clear(); + tagIndex_.clear(); } -Ptr Node::getChildByName(const std::string &name) const { - // 使用哈希索引,O(1) 查找 - auto it = nameIndex_.find(name); - if (it != nameIndex_.end()) { - return it->second.lock(); - } - return nullptr; +Ref Node::getChildByName(const std::string& name) const { + auto it = nameIndex_.find(name); + if (it != nameIndex_.end()) { + return it->second.lock(); + } + return nullptr; } -Ptr Node::getChildByTag(int tag) const { - // 使用哈希索引,O(1) 查找 - auto it = tagIndex_.find(tag); - if (it != tagIndex_.end()) { - return it->second.lock(); - } - return nullptr; +Ref Node::getChildByTag(int tag) const { + auto it = tagIndex_.find(tag); + if (it != tagIndex_.end()) { + return it->second.lock(); + } + return nullptr; } -void Node::setPosition(const Vec2 &pos) { - position_ = pos; - markTransformDirty(); - updateSpatialIndex(); +void Node::setPosition(const Vec2& pos) { + position_ = pos; + markTransformDirty(); + updateSpatialIndex(); } -void Node::setPosition(float x, float y) { setPosition(Vec2(x, y)); } +void Node::setPosition(float x, float y) { + setPosition(Vec2(x, y)); +} void Node::setRotation(float degrees) { - rotation_ = degrees; - markTransformDirty(); - updateSpatialIndex(); + rotation_ = degrees; + markTransformDirty(); + updateSpatialIndex(); } -void Node::setScale(const Vec2 &scale) { - scale_ = scale; - markTransformDirty(); - updateSpatialIndex(); +void Node::setScale(const Vec2& scale) { + scale_ = scale; + markTransformDirty(); + updateSpatialIndex(); } -void Node::setScale(float scale) { setScale(Vec2(scale, scale)); } - -void Node::setScale(float x, float y) { setScale(Vec2(x, y)); } - -void Node::setAnchor(const Vec2 &anchor) { - anchor_ = anchor; - markTransformDirty(); +void Node::setScale(float scale) { + setScale(Vec2(scale, scale)); } -void Node::setAnchor(float x, float y) { setAnchor(Vec2(x, y)); } - -void Node::setSkew(const Vec2 &skew) { - skew_ = skew; - markTransformDirty(); +void Node::setScale(float x, float y) { + setScale(Vec2(x, y)); } -void Node::setSkew(float x, float y) { setSkew(Vec2(x, y)); } +void Node::setAnchor(const Vec2& anchor) { + anchor_ = anchor; + markTransformDirty(); +} + +void Node::setAnchor(float x, float y) { + setAnchor(Vec2(x, y)); +} + +void Node::setSkew(const Vec2& skew) { + skew_ = skew; + markTransformDirty(); +} + +void Node::setSkew(float x, float y) { + setSkew(Vec2(x, y)); +} void Node::setOpacity(float opacity) { - opacity_ = std::clamp(opacity, 0.0f, 1.0f); + opacity_ = std::clamp(opacity, 0.0f, 1.0f); } -void Node::setVisible(bool visible) { visible_ = visible; } +void Node::setVisible(bool visible) { + visible_ = visible; +} -void Node::setColor(const Color3B &color) { color_ = color; } +void Node::setColor(const Color3B& color) { + color_ = color; +} -void Node::setFlipX(bool flipX) { flipX_ = flipX; } +void Node::setFlipX(bool flipX) { + flipX_ = flipX; +} -void Node::setFlipY(bool flipY) { flipY_ = flipY; } +void Node::setFlipY(bool flipY) { + flipY_ = flipY; +} void Node::setZOrder(int zOrder) { - if (zOrder_ != zOrder) { - zOrder_ = zOrder; - childrenOrderDirty_ = true; - } + if (zOrder_ != zOrder) { + zOrder_ = zOrder; + childrenOrderDirty_ = true; + } } -Vec2 Node::convertToWorldSpace(const Vec2 &localPos) const { - glm::vec4 worldPos = - getWorldTransform() * glm::vec4(localPos.x, localPos.y, 0.0f, 1.0f); - return Vec2(worldPos.x, worldPos.y); +Vec2 Node::convertToWorldSpace(const Vec2& localPos) const { + glm::vec4 worldPos = getWorldTransform() * glm::vec4(localPos.x, localPos.y, 0.0f, 1.0f); + return Vec2(worldPos.x, worldPos.y); } -Vec2 Node::convertToNodeSpace(const Vec2 &worldPos) const { - glm::mat4 invWorld = glm::inverse(getWorldTransform()); - glm::vec4 localPos = invWorld * glm::vec4(worldPos.x, worldPos.y, 0.0f, 1.0f); - return Vec2(localPos.x, localPos.y); +Vec2 Node::convertToNodeSpace(const Vec2& worldPos) const { + glm::mat4 invWorld = glm::inverse(getWorldTransform()); + glm::vec4 localPos = invWorld * glm::vec4(worldPos.x, worldPos.y, 0.0f, 1.0f); + return Vec2(localPos.x, localPos.y); } glm::mat4 Node::getLocalTransform() const { - if (transformDirty_) { - localTransform_ = glm::mat4(1.0f); + if (transformDirty_) { + localTransform_ = glm::mat4(1.0f); - // T - R - S order - localTransform_ = glm::translate(localTransform_, - glm::vec3(position_.x, position_.y, 0.0f)); + localTransform_ = glm::translate(localTransform_, + glm::vec3(position_.x, position_.y, 0.0f)); - if (rotation_ != 0.0f) { - localTransform_ = glm::rotate(localTransform_, rotation_ * DEG_TO_RAD, - glm::vec3(0.0f, 0.0f, 1.0f)); + if (rotation_ != 0.0f) { + localTransform_ = glm::rotate(localTransform_, rotation_ * DEG_TO_RAD, + glm::vec3(0.0f, 0.0f, 1.0f)); + } + + if (skew_.x != 0.0f || skew_.y != 0.0f) { + glm::mat4 skewMatrix(1.0f); + skewMatrix[1][0] = std::tan(skew_.x * DEG_TO_RAD); + skewMatrix[0][1] = std::tan(skew_.y * DEG_TO_RAD); + localTransform_ *= skewMatrix; + } + + localTransform_ = glm::scale(localTransform_, glm::vec3(scale_.x, scale_.y, 1.0f)); + + transformDirty_ = false; } - - if (skew_.x != 0.0f || skew_.y != 0.0f) { - glm::mat4 skewMatrix(1.0f); - skewMatrix[1][0] = std::tan(skew_.x * DEG_TO_RAD); - skewMatrix[0][1] = std::tan(skew_.y * DEG_TO_RAD); - localTransform_ *= skewMatrix; - } - - localTransform_ = - glm::scale(localTransform_, glm::vec3(scale_.x, scale_.y, 1.0f)); - - // 注意:锚点偏移在渲染时处理,不在本地变换中处理 - // 这样可以避免锚点偏移被父节点的缩放影响 - - transformDirty_ = false; - } - return localTransform_; + return localTransform_; } glm::mat4 Node::getWorldTransform() const { - if (worldTransformDirty_) { - // 使用线程局部存储的固定数组,避免每帧内存分配 - // 限制最大深度为 256 层,足以覆盖绝大多数场景 - thread_local std::array nodeChainCache; - thread_local size_t chainCount = 0; + if (worldTransformDirty_) { + thread_local std::array nodeChainCache; + thread_local size_t chainCount = 0; - chainCount = 0; - const Node *current = this; - while (current && chainCount < nodeChainCache.size()) { - nodeChainCache[chainCount++] = current; - auto p = current->parent_.lock(); - current = p.get(); - } + chainCount = 0; + const Node* current = this; + while (current && chainCount < nodeChainCache.size()) { + nodeChainCache[chainCount++] = current; + auto p = current->parent_.lock(); + current = p.get(); + } - // 从根节点开始计算 - glm::mat4 transform = glm::mat4(1.0f); - for (size_t i = chainCount; i > 0; --i) { - transform = transform * nodeChainCache[i - 1]->getLocalTransform(); + glm::mat4 transform = glm::mat4(1.0f); + for (size_t i = chainCount; i > 0; --i) { + transform = transform * nodeChainCache[i - 1]->getLocalTransform(); + } + worldTransform_ = transform; + worldTransformDirty_ = false; } - worldTransform_ = transform; - worldTransformDirty_ = false; - } - return worldTransform_; + return worldTransform_; } void Node::markTransformDirty() { - // 避免重复标记,提高性能 - if (!transformDirty_ || !worldTransformDirty_) { - transformDirty_ = true; - worldTransformDirty_ = true; + if (!transformDirty_ || !worldTransformDirty_) { + transformDirty_ = true; + worldTransformDirty_ = true; - // 递归标记所有子节点 - for (auto &child : children_) { - child->markTransformDirty(); + for (auto& child : children_) { + child->markTransformDirty(); + } } - } } void Node::batchUpdateTransforms() { - // 如果本地变换脏了,先计算本地变换 - if (transformDirty_) { - (void)getLocalTransform(); // 这会计算并缓存本地变换 - } - - // 如果世界变换脏了,需要重新计算 - if (worldTransformDirty_) { - auto parent = parent_.lock(); - if (parent) { - // 使用父节点的世界变换(确保父节点已经更新) - worldTransform_ = parent->getWorldTransform() * localTransform_; - } else { - // 根节点 - worldTransform_ = localTransform_; + if (transformDirty_) { + (void)getLocalTransform(); } - worldTransformDirty_ = false; - } - // 递归更新子节点 - for (auto &child : children_) { - child->batchUpdateTransforms(); - } + if (worldTransformDirty_) { + auto parent = parent_.lock(); + if (parent) { + worldTransform_ = parent->getWorldTransform() * localTransform_; + } else { + worldTransform_ = localTransform_; + } + worldTransformDirty_ = false; + } + + for (auto& child : children_) { + child->batchUpdateTransforms(); + } } void Node::onEnter() { - running_ = true; - for (auto &child : children_) { - child->onEnter(); - } + running_ = true; + for (auto& child : children_) { + child->onEnter(); + } } void Node::onExit() { - running_ = false; - for (auto &child : children_) { - child->onExit(); - } + running_ = false; + for (auto& child : children_) { + child->onExit(); + } } void Node::onUpdate(float dt) { - onUpdateNode(dt); + onUpdateNode(dt); - // Update children - for (auto &child : children_) { - child->onUpdate(dt); - } + for (auto& child : children_) { + child->onUpdate(dt); + } } -void Node::onRender(Renderer &renderer) { - if (!visible_) - return; +void Node::onRender(Renderer& renderer) { + if (!visible_) { + return; + } - onDraw(renderer); + onDraw(renderer); - for (auto &child : children_) { - child->onRender(renderer); - } + for (auto& child : children_) { + child->onRender(renderer); + } } -void Node::onAttachToScene(Scene *scene) { - scene_ = scene; +void Node::onAttachToScene(Scene* scene) { + scene_ = scene; - // 添加到场景的空间索引 - if (spatialIndexed_ && scene_) { - lastSpatialBounds_ = Rect(); - updateSpatialIndex(); - } + if (spatialIndexed_ && scene_) { + lastSpatialBounds_ = Rect(); + updateSpatialIndex(); + } - for (auto &child : children_) { - child->onAttachToScene(scene); - } + for (auto& child : children_) { + child->onAttachToScene(scene); + } } void Node::onDetachFromScene() { - // 从场景的空间索引移除 - // 注意:即使 lastSpatialBounds_ 为空也要尝试移除, - // 因为节点可能通过其他方式被插入到空间索引中 - if (spatialIndexed_ && scene_) { - scene_->removeNodeFromSpatialIndex(this); - lastSpatialBounds_ = Rect(); - } + if (spatialIndexed_ && scene_) { + scene_->removeNodeFromSpatialIndex(this); + lastSpatialBounds_ = Rect(); + } - scene_ = nullptr; - for (auto &child : children_) { - child->onDetachFromScene(); - } + scene_ = nullptr; + for (auto& child : children_) { + child->onDetachFromScene(); + } } Rect Node::getBoundingBox() const { - // 默认返回一个以位置为中心的点矩形 - return Rect(position_.x, position_.y, 0, 0); + return Rect(position_.x, position_.y, 0, 0); } void Node::updateSpatialIndex() { - if (!spatialIndexed_ || !scene_) { - return; - } + if (!spatialIndexed_ || !scene_) { + return; + } - Rect newBounds = getBoundingBox(); - if (newBounds != lastSpatialBounds_) { - scene_->updateNodeInSpatialIndex(this, lastSpatialBounds_, newBounds); - lastSpatialBounds_ = newBounds; - } + Rect newBounds = getBoundingBox(); + if (newBounds != lastSpatialBounds_) { + scene_->updateNodeInSpatialIndex(this, lastSpatialBounds_, newBounds); + lastSpatialBounds_ = newBounds; + } } -void Node::update(float dt) { onUpdate(dt); } +void Node::update(float dt) { + onUpdate(dt); +} -void Node::render(Renderer &renderer) { - if (childrenOrderDirty_) { - sortChildren(); - } - onRender(renderer); +void Node::render(Renderer& renderer) { + if (childrenOrderDirty_) { + sortChildren(); + } + onRender(renderer); } void Node::sortChildren() { - // 使用插入排序优化小范围更新场景 - // 插入排序在大部分已有序的情况下性能接近O(n) - size_t n = children_.size(); - if (n <= 1) { - childrenOrderDirty_ = false; - return; - } - - // 小数组使用插入排序,大数组使用std::sort - if (n < 32) { - // 插入排序 - for (size_t i = 1; i < n; ++i) { - auto key = children_[i]; - int keyZOrder = key->getZOrder(); - int j = static_cast(i) - 1; - - while (j >= 0 && children_[j]->getZOrder() > keyZOrder) { - children_[j + 1] = children_[j]; - --j; - } - children_[j + 1] = key; + size_t n = children_.size(); + if (n <= 1) { + childrenOrderDirty_ = false; + return; } - } else { - // 大数组使用标准排序 - std::sort(children_.begin(), children_.end(), - [](const Ptr &a, const Ptr &b) { - return a->getZOrder() < b->getZOrder(); - }); - } - childrenOrderDirty_ = false; -} + if (n < 32) { + for (size_t i = 1; i < n; ++i) { + auto key = children_[i]; + int keyZOrder = key->getZOrder(); + int j = static_cast(i) - 1; -void Node::collectRenderCommands(std::vector &commands, - int parentZOrder) { - if (!visible_) - return; + while (j >= 0 && children_[j]->getZOrder() > keyZOrder) { + children_[j + 1] = children_[j]; + --j; + } + children_[j + 1] = key; + } + } else { + std::sort(children_.begin(), children_.end(), + [](const Ref& a, const Ref& b) { + return a->getZOrder() < b->getZOrder(); + }); + } - // 计算累积 Z 序 - int accumulatedZOrder = parentZOrder + zOrder_; - - // 生成当前节点的渲染命令 - generateRenderCommand(commands, accumulatedZOrder); - - // 递归收集子节点的渲染命令 - // 注意:这里假设子节点已经按 Z 序排序 - for (auto &child : children_) { - child->collectRenderCommands(commands, accumulatedZOrder); - } + childrenOrderDirty_ = false; } } // namespace extra2d diff --git a/Extra2D/src/scene/scene.cpp b/Extra2D/src/scene/scene.cpp index 5fe293d..c9a69a0 100644 --- a/Extra2D/src/scene/scene.cpp +++ b/Extra2D/src/scene/scene.cpp @@ -1,129 +1,120 @@ -#include -#include +#include #include -#include +#include namespace extra2d { -Scene::Scene() { defaultCamera_ = makePtr(); } +Scene::Scene() { + defaultCamera_ = ptr::make(); +} -void Scene::setCamera(Ptr camera) { camera_ = camera; } +void Scene::setCamera(Ref camera) { + camera_ = camera; +} void Scene::setViewportSize(float width, float height) { - viewportSize_ = Size(width, height); - if (defaultCamera_) { - defaultCamera_->setViewport(0, width, height, 0); - } else if (camera_) { - camera_->setViewport(0, width, height, 0); - } + viewportSize_ = Size(width, height); + if (defaultCamera_) { + defaultCamera_->setViewport(0, static_cast(width), static_cast(height), 0); + } else if (camera_) { + camera_->setViewport(0, static_cast(width), static_cast(height), 0); + } } -void Scene::setViewportSize(const Size &size) { - setViewportSize(size.width, size.height); +void Scene::setViewportSize(const Size& size) { + setViewportSize(size.width, size.height); } -void Scene::renderScene(Renderer &renderer) { - if (!isVisible()) - return; +void Scene::renderScene(Renderer& renderer) { + if (!isVisible()) { + return; + } - // Begin frame with background color - renderer.beginFrame(backgroundColor_); - renderContent(renderer); - renderer.endFrame(); + renderer.beginFrame(backgroundColor_); + renderContent(renderer); + renderer.endFrame(); } -void Scene::renderContent(Renderer &renderer) { - if (!isVisible()) - return; +void Scene::renderContent(Renderer& renderer) { + if (!isVisible()) { + return; + } - // 在渲染前批量更新所有节点的世界变换 - batchUpdateTransforms(); + batchUpdateTransforms(); - Camera *activeCam = getActiveCamera(); - if (activeCam) { - renderer.setViewProjection(activeCam->getViewProjectionMatrix()); - } + Camera* activeCam = getActiveCamera(); + if (activeCam) { + renderer.setViewProjection(activeCam->getViewProjectionMatrix()); + } - render(renderer); + render(renderer); } void Scene::updateScene(float dt) { - if (!paused_) { - update(dt); - } + if (!paused_) { + update(dt); + } } void Scene::onEnter() { - Node::onEnter(); + Node::onEnter(); - // 初始化空间索引世界边界 - if (spatialIndexingEnabled_) { - spatialManager_.setWorldBounds( - Rect(0, 0, viewportSize_.width, viewportSize_.height)); - } + if (spatialIndexingEnabled_) { + spatialManager_.setWorldBounds( + Rect(0, 0, viewportSize_.width, viewportSize_.height)); + } } void Scene::onExit() { - // 清理空间索引 - spatialManager_.clear(); - Node::onExit(); + spatialManager_.clear(); + Node::onExit(); } -void Scene::updateNodeInSpatialIndex(Node *node, const Rect &oldBounds, - const Rect &newBounds) { - if (!spatialIndexingEnabled_ || !node || !node->isSpatialIndexed()) { - return; - } +void Scene::updateNodeInSpatialIndex(Node* node, const Rect& oldBounds, const Rect& newBounds) { + if (!spatialIndexingEnabled_ || !node || !node->isSpatialIndexed()) { + return; + } + + if (!oldBounds.empty()) { + spatialManager_.remove(node); + } + + if (!newBounds.empty()) { + spatialManager_.insert(node, newBounds); + } +} + +void Scene::removeNodeFromSpatialIndex(Node* node) { + if (!spatialIndexingEnabled_ || !node) { + return; + } - // 如果旧边界有效,先移除 - if (!oldBounds.empty()) { spatialManager_.remove(node); - } - - // 如果新边界有效,插入 - if (!newBounds.empty()) { - spatialManager_.insert(node, newBounds); - } } -void Scene::removeNodeFromSpatialIndex(Node *node) { - if (!spatialIndexingEnabled_ || !node) { - return; - } - - spatialManager_.remove(node); +std::vector Scene::queryNodesInArea(const Rect& area) const { + if (!spatialIndexingEnabled_) { + return {}; + } + return spatialManager_.query(area); } -std::vector Scene::queryNodesInArea(const Rect &area) const { - if (!spatialIndexingEnabled_) { - return {}; - } - return spatialManager_.query(area); +std::vector Scene::queryNodesAtPoint(const Vec2& point) const { + if (!spatialIndexingEnabled_) { + return {}; + } + return spatialManager_.query(point); } -std::vector Scene::queryNodesAtPoint(const Vec2 &point) const { - if (!spatialIndexingEnabled_) { - return {}; - } - return spatialManager_.query(point); +std::vector> Scene::queryCollisions() const { + if (!spatialIndexingEnabled_) { + return {}; + } + return spatialManager_.queryCollisions(); } -std::vector> Scene::queryCollisions() const { - if (!spatialIndexingEnabled_) { - return {}; - } - return spatialManager_.queryCollisions(); +Ref Scene::create() { + return ptr::make(); } -void Scene::collectRenderCommands(std::vector &commands, - int parentZOrder) { - if (!isVisible()) - return; - - // 从场景的子节点开始收集渲染命令 - Node::collectRenderCommands(commands, parentZOrder); -} - -Ptr Scene::create() { return makePtr(); } - } // namespace extra2d diff --git a/Extra2D/src/scene/scene_manager.cpp b/Extra2D/src/scene/scene_manager.cpp index f694480..255cc56 100644 --- a/Extra2D/src/scene/scene_manager.cpp +++ b/Extra2D/src/scene/scene_manager.cpp @@ -1,233 +1,208 @@ -#include -#include -#include +#include #include -#include +#include namespace extra2d { -SceneManager &SceneManager::getInstance() { - static SceneManager instance; - return instance; +SceneManager& SceneManager::getInstance() { + static SceneManager instance; + return instance; } -void SceneManager::runWithScene(Ptr scene) { - if (!scene) { - return; - } +void SceneManager::runWithScene(Ref scene) { + if (!scene) { + return; + } - if (!sceneStack_.empty()) { - E2D_LOG_WARN("SceneManager: runWithScene should only be called once"); - return; - } + if (!sceneStack_.empty()) { + E2D_WARN("SceneManager: runWithScene should only be called once"); + return; + } - scene->onEnter(); - scene->onAttachToScene(scene.get()); - sceneStack_.push(scene); + scene->onEnter(); + sceneStack_.push(scene); } -void SceneManager::replaceScene(Ptr scene) { - if (!scene) { - return; - } +void SceneManager::replaceScene(Ref scene) { + if (!scene) { + return; + } - if (sceneStack_.empty()) { - runWithScene(scene); - return; - } + if (sceneStack_.empty()) { + runWithScene(scene); + return; + } - // Pop current scene - auto oldScene = sceneStack_.top(); - oldScene->onExit(); - oldScene->onDetachFromScene(); - sceneStack_.pop(); + auto oldScene = sceneStack_.top(); + oldScene->onExit(); + sceneStack_.pop(); - // Push new scene - scene->onEnter(); - scene->onAttachToScene(scene.get()); - sceneStack_.push(scene); + scene->onEnter(); + sceneStack_.push(scene); } -void SceneManager::enterScene(Ptr scene) { - if (!scene) { - return; - } +void SceneManager::enterScene(Ref scene) { + if (!scene) { + return; + } - if (sceneStack_.empty()) { - runWithScene(scene); - } else { - replaceScene(scene); - } + if (sceneStack_.empty()) { + runWithScene(scene); + } else { + replaceScene(scene); + } } -void SceneManager::pushScene(Ptr scene) { - if (!scene) { - return; - } - // Pause current scene - if (!sceneStack_.empty()) { - sceneStack_.top()->pause(); - } +void SceneManager::pushScene(Ref scene) { + if (!scene) { + return; + } - // Push new scene - scene->onEnter(); - scene->onAttachToScene(scene.get()); - sceneStack_.push(scene); + if (!sceneStack_.empty()) { + sceneStack_.top()->pause(); + } + + scene->onEnter(); + sceneStack_.push(scene); } void SceneManager::popScene() { - if (sceneStack_.size() <= 1) { - return; - } + if (sceneStack_.size() <= 1) { + return; + } - auto current = sceneStack_.top(); - current->onExit(); - current->onDetachFromScene(); - sceneStack_.pop(); + auto current = sceneStack_.top(); + current->onExit(); + sceneStack_.pop(); - // Resume previous scene - if (!sceneStack_.empty()) { - sceneStack_.top()->resume(); - } + if (!sceneStack_.empty()) { + sceneStack_.top()->resume(); + } } void SceneManager::popToRootScene() { - if (sceneStack_.size() <= 1) { - return; - } - - // Exit all scenes except root - while (sceneStack_.size() > 1) { - auto scene = sceneStack_.top(); - scene->onExit(); - scene->onDetachFromScene(); - sceneStack_.pop(); - } - - // Resume root - sceneStack_.top()->resume(); -} - -void SceneManager::popToScene(const std::string &name) { - // Find target scene in stack - std::stack> tempStack; - Ptr target = nullptr; - - while (!sceneStack_.empty()) { - auto scene = sceneStack_.top(); - if (scene->getName() == name) { - target = scene; - break; + if (sceneStack_.size() <= 1) { + return; } - scene->onExit(); - scene->onDetachFromScene(); - sceneStack_.pop(); - } - if (target) { - target->resume(); - } -} - -Ptr SceneManager::getCurrentScene() const { - if (sceneStack_.empty()) { - return nullptr; - } - return sceneStack_.top(); -} - -Ptr SceneManager::getPreviousScene() const { - if (sceneStack_.size() < 2) { - return nullptr; - } - - // Copy stack to access second top - auto tempStack = sceneStack_; - tempStack.pop(); - return tempStack.top(); -} - -Ptr SceneManager::getRootScene() const { - if (sceneStack_.empty()) { - return nullptr; - } - - // Copy stack to access bottom - auto tempStack = sceneStack_; - Ptr root; - while (!tempStack.empty()) { - root = tempStack.top(); - tempStack.pop(); - } - return root; -} - -Ptr SceneManager::getSceneByName(const std::string &name) const { - auto it = namedScenes_.find(name); - if (it != namedScenes_.end()) { - return it->second; - } - - // Search in stack - auto tempStack = sceneStack_; - while (!tempStack.empty()) { - auto scene = tempStack.top(); - if (scene->getName() == name) { - return scene; + while (sceneStack_.size() > 1) { + auto scene = sceneStack_.top(); + scene->onExit(); + sceneStack_.pop(); } - tempStack.pop(); - } - return nullptr; + sceneStack_.top()->resume(); } -bool SceneManager::hasScene(const std::string &name) const { - return getSceneByName(name) != nullptr; +void SceneManager::popToScene(const std::string& name) { + std::stack> tempStack; + Ref target = nullptr; + + while (!sceneStack_.empty()) { + auto scene = sceneStack_.top(); + if (scene->getName() == name) { + target = scene; + break; + } + scene->onExit(); + sceneStack_.pop(); + } + + if (target) { + target->resume(); + } +} + +Ref SceneManager::getCurrentScene() const { + if (sceneStack_.empty()) { + return nullptr; + } + return sceneStack_.top(); +} + +Ref SceneManager::getPreviousScene() const { + if (sceneStack_.size() < 2) { + return nullptr; + } + + auto tempStack = sceneStack_; + tempStack.pop(); + return tempStack.top(); +} + +Ref SceneManager::getRootScene() const { + if (sceneStack_.empty()) { + return nullptr; + } + + auto tempStack = sceneStack_; + Ref root; + while (!tempStack.empty()) { + root = tempStack.top(); + tempStack.pop(); + } + return root; +} + +Ref SceneManager::getSceneByName(const std::string& name) const { + auto it = namedScenes_.find(name); + if (it != namedScenes_.end()) { + return it->second; + } + + auto tempStack = sceneStack_; + while (!tempStack.empty()) { + auto scene = tempStack.top(); + if (scene->getName() == name) { + return scene; + } + tempStack.pop(); + } + + return nullptr; +} + +bool SceneManager::hasScene(const std::string& name) const { + return getSceneByName(name) != nullptr; } void SceneManager::update(float dt) { - if (!sceneStack_.empty()) { - sceneStack_.top()->updateScene(dt); - } + if (!sceneStack_.empty()) { + sceneStack_.top()->updateScene(dt); + } } -void SceneManager::render(Renderer &renderer) { - Color clearColor = Colors::Black; - if (!sceneStack_.empty()) { - clearColor = sceneStack_.top()->getBackgroundColor(); - } +void SceneManager::render(Renderer& renderer) { + Color clearColor = Colors::Black; + if (!sceneStack_.empty()) { + clearColor = sceneStack_.top()->getBackgroundColor(); + } - E2D_LOG_TRACE("SceneManager::render - beginFrame with color({}, {}, {})", - clearColor.r, clearColor.g, clearColor.b); - renderer.beginFrame(clearColor); + E2D_TRACE("SceneManager::render - beginFrame"); + renderer.beginFrame(clearColor); - if (!sceneStack_.empty()) { - E2D_LOG_TRACE("SceneManager::render - rendering scene content"); - sceneStack_.top()->renderContent(renderer); - } else { - E2D_LOG_WARN("SceneManager::render - no scene to render"); - } + if (!sceneStack_.empty()) { + E2D_TRACE("SceneManager::render - rendering scene content"); + sceneStack_.top()->renderContent(renderer); + } else { + E2D_WARN("SceneManager::render - no scene to render"); + } - renderer.endFrame(); - E2D_LOG_TRACE("SceneManager::render - endFrame"); -} - -void SceneManager::collectRenderCommands(std::vector &commands) { - if (!sceneStack_.empty()) { - sceneStack_.top()->collectRenderCommands(commands, 0); - } + renderer.endFrame(); + E2D_TRACE("SceneManager::render - endFrame"); } void SceneManager::end() { - while (!sceneStack_.empty()) { - auto scene = sceneStack_.top(); - scene->onExit(); - scene->onDetachFromScene(); - sceneStack_.pop(); - } - namedScenes_.clear(); + while (!sceneStack_.empty()) { + auto scene = sceneStack_.top(); + scene->onExit(); + sceneStack_.pop(); + } + namedScenes_.clear(); } -void SceneManager::purgeCachedScenes() { namedScenes_.clear(); } +void SceneManager::purgeCachedScenes() { + namedScenes_.clear(); +} } // namespace extra2d diff --git a/Extra2D/src/scene/shape_node.cpp b/Extra2D/src/scene/shape_node.cpp index b354782..1ee0e59 100644 --- a/Extra2D/src/scene/shape_node.cpp +++ b/Extra2D/src/scene/shape_node.cpp @@ -1,7 +1,6 @@ #include #include -#include -#include +#include #include #include @@ -9,340 +8,233 @@ namespace extra2d { ShapeNode::ShapeNode() = default; -Ptr ShapeNode::create() { return makePtr(); } - -Ptr ShapeNode::createPoint(const Vec2 &pos, const Color &color) { - auto node = makePtr(); - node->shapeType_ = ShapeType::Point; - node->color_ = color; - node->points_ = {pos}; - return node; +Ref ShapeNode::create() { + return ptr::make(); } -Ptr ShapeNode::createLine(const Vec2 &start, const Vec2 &end, - const Color &color, float width) { - auto node = makePtr(); - node->shapeType_ = ShapeType::Line; - node->color_ = color; - node->lineWidth_ = width; - node->points_ = {start, end}; - return node; +Ref ShapeNode::createPoint(const Vec2& pos, const Color& color) { + auto node = ptr::make(); + node->shapeType_ = ShapeType::Point; + node->color_ = color; + node->points_ = {pos}; + return node; } -Ptr ShapeNode::createRect(const Rect &rect, const Color &color, - float width) { - auto node = makePtr(); - node->shapeType_ = ShapeType::Rect; - node->color_ = color; - node->lineWidth_ = width; - node->filled_ = false; - node->points_ = { - Vec2(rect.left(), rect.top()), Vec2(rect.right(), rect.top()), - Vec2(rect.right(), rect.bottom()), Vec2(rect.left(), rect.bottom())}; - return node; +Ref ShapeNode::createLine(const Vec2& start, const Vec2& end, + const Color& color, float width) { + auto node = ptr::make(); + node->shapeType_ = ShapeType::Line; + node->color_ = color; + node->lineWidth_ = width; + node->points_ = {start, end}; + return node; } -Ptr ShapeNode::createFilledRect(const Rect &rect, - const Color &color) { - auto node = createRect(rect, color, 0); - node->filled_ = true; - return node; +Ref ShapeNode::createRect(const Rect& rect, const Color& color, float width) { + auto node = ptr::make(); + node->shapeType_ = ShapeType::Rect; + node->color_ = color; + node->lineWidth_ = width; + node->filled_ = false; + node->points_ = { + Vec2(rect.left(), rect.top()), + Vec2(rect.right(), rect.top()), + Vec2(rect.right(), rect.bottom()), + Vec2(rect.left(), rect.bottom()) + }; + return node; } -Ptr ShapeNode::createCircle(const Vec2 ¢er, float radius, - const Color &color, int segments, - float width) { - auto node = makePtr(); - node->shapeType_ = ShapeType::Circle; - node->color_ = color; - node->lineWidth_ = width; - node->segments_ = segments; - node->filled_ = false; - node->points_ = {center}; - // Store radius in a point for simplicity - node->addPoint(Vec2(radius, 0)); - return node; +Ref ShapeNode::createFilledRect(const Rect& rect, const Color& color) { + auto node = createRect(rect, color, 0); + node->filled_ = true; + return node; } -Ptr ShapeNode::createFilledCircle(const Vec2 ¢er, float radius, - const Color &color, int segments) { - auto node = createCircle(center, radius, color, segments, 0); - node->filled_ = true; - return node; +Ref ShapeNode::createCircle(const Vec2& center, float radius, + const Color& color, int segments, float width) { + auto node = ptr::make(); + node->shapeType_ = ShapeType::Circle; + node->color_ = color; + node->lineWidth_ = width; + node->segments_ = segments; + node->filled_ = false; + node->points_ = {center}; + node->addPoint(Vec2(radius, 0)); + return node; } -Ptr ShapeNode::createTriangle(const Vec2 &p1, const Vec2 &p2, - const Vec2 &p3, const Color &color, - float width) { - auto node = makePtr(); - node->shapeType_ = ShapeType::Triangle; - node->color_ = color; - node->lineWidth_ = width; - node->filled_ = false; - node->points_ = {p1, p2, p3}; - return node; +Ref ShapeNode::createFilledCircle(const Vec2& center, float radius, + const Color& color, int segments) { + auto node = createCircle(center, radius, color, segments, 0); + node->filled_ = true; + return node; } -Ptr ShapeNode::createFilledTriangle(const Vec2 &p1, const Vec2 &p2, - const Vec2 &p3, - const Color &color) { - auto node = createTriangle(p1, p2, p3, color, 0); - node->filled_ = true; - return node; +Ref ShapeNode::createTriangle(const Vec2& p1, const Vec2& p2, + const Vec2& p3, const Color& color, float width) { + auto node = ptr::make(); + node->shapeType_ = ShapeType::Triangle; + node->color_ = color; + node->lineWidth_ = width; + node->filled_ = false; + node->points_ = {p1, p2, p3}; + return node; } -Ptr ShapeNode::createPolygon(const std::vector &points, - const Color &color, float width) { - auto node = makePtr(); - node->shapeType_ = ShapeType::Polygon; - node->color_ = color; - node->lineWidth_ = width; - node->filled_ = false; - node->points_ = points; - return node; +Ref ShapeNode::createFilledTriangle(const Vec2& p1, const Vec2& p2, + const Vec2& p3, const Color& color) { + auto node = createTriangle(p1, p2, p3, color, 0); + node->filled_ = true; + return node; } -Ptr ShapeNode::createFilledPolygon(const std::vector &points, - const Color &color) { - auto node = createPolygon(points, color, 0); - node->filled_ = true; - return node; +Ref ShapeNode::createPolygon(const std::vector& points, + const Color& color, float width) { + auto node = ptr::make(); + node->shapeType_ = ShapeType::Polygon; + node->color_ = color; + node->lineWidth_ = width; + node->filled_ = false; + node->points_ = points; + return node; } -void ShapeNode::setPoints(const std::vector &points) { - points_ = points; - updateSpatialIndex(); +Ref ShapeNode::createFilledPolygon(const std::vector& points, + const Color& color) { + auto node = createPolygon(points, color, 0); + node->filled_ = true; + return node; } -void ShapeNode::addPoint(const Vec2 &point) { - points_.push_back(point); - updateSpatialIndex(); +void ShapeNode::setPoints(const std::vector& points) { + points_ = points; + updateSpatialIndex(); +} + +void ShapeNode::addPoint(const Vec2& point) { + points_.push_back(point); + updateSpatialIndex(); } void ShapeNode::clearPoints() { - points_.clear(); - updateSpatialIndex(); + points_.clear(); + updateSpatialIndex(); } Rect ShapeNode::getBoundingBox() const { - if (points_.empty()) { - return Rect(); - } + if (points_.empty()) { + return Rect(); + } - Vec2 offset = getPosition(); + Vec2 offset = getPosition(); - if (shapeType_ == ShapeType::Circle && points_.size() >= 2) { - float radius = std::abs(points_[1].x); - Vec2 center = points_[0] + offset; - return Rect(center.x - radius, center.y - radius, radius * 2.0f, - radius * 2.0f); - } + if (shapeType_ == ShapeType::Circle && points_.size() >= 2) { + float radius = std::abs(points_[1].x); + Vec2 center = points_[0] + offset; + return Rect(center.x - radius, center.y - radius, radius * 2.0f, radius * 2.0f); + } - float minX = std::numeric_limits::infinity(); - float minY = std::numeric_limits::infinity(); - float maxX = -std::numeric_limits::infinity(); - float maxY = -std::numeric_limits::infinity(); + float minX = std::numeric_limits::infinity(); + float minY = std::numeric_limits::infinity(); + float maxX = -std::numeric_limits::infinity(); + float maxY = -std::numeric_limits::infinity(); - for (const auto &p : points_) { - Vec2 world = p + offset; - minX = std::min(minX, world.x); - minY = std::min(minY, world.y); - maxX = std::max(maxX, world.x); - maxY = std::max(maxY, world.y); - } + for (const auto& p : points_) { + Vec2 world = p + offset; + minX = std::min(minX, world.x); + minY = std::min(minY, world.y); + maxX = std::max(maxX, world.x); + maxY = std::max(maxY, world.y); + } - float inflate = 0.0f; - if (!filled_ && - (shapeType_ == ShapeType::Line || shapeType_ == ShapeType::Rect || - shapeType_ == ShapeType::Triangle || shapeType_ == ShapeType::Polygon || - shapeType_ == ShapeType::Point)) { - inflate = std::max(0.0f, lineWidth_ * 0.5f); - } - if (shapeType_ == ShapeType::Point) { - inflate = std::max(inflate, lineWidth_ * 0.5f); - } + float inflate = 0.0f; + if (!filled_ && (shapeType_ == ShapeType::Line || shapeType_ == ShapeType::Rect || + shapeType_ == ShapeType::Triangle || shapeType_ == ShapeType::Polygon || + shapeType_ == ShapeType::Point)) { + inflate = std::max(0.0f, lineWidth_ * 0.5f); + } + if (shapeType_ == ShapeType::Point) { + inflate = std::max(inflate, lineWidth_ * 0.5f); + } - return Rect(minX - inflate, minY - inflate, (maxX - minX) + inflate * 2.0f, - (maxY - minY) + inflate * 2.0f); + return Rect(minX - inflate, minY - inflate, (maxX - minX) + inflate * 2.0f, + (maxY - minY) + inflate * 2.0f); } -void ShapeNode::onDraw(Renderer &renderer) { - if (points_.empty()) { - return; - } - - Vec2 offset = getPosition(); - - switch (shapeType_) { - case ShapeType::Point: - if (!points_.empty()) { - renderer.fillCircle(points_[0] + offset, lineWidth_ * 0.5f, color_, 8); +void ShapeNode::onDraw(Renderer& renderer) { + if (points_.empty()) { + return; } - break; - case ShapeType::Line: - if (points_.size() >= 2) { - renderer.drawLine(points_[0] + offset, points_[1] + offset, color_, - lineWidth_); - } - break; + Vec2 offset = getPosition(); - case ShapeType::Rect: - if (points_.size() >= 4) { - if (filled_) { - Rect rect(points_[0].x, points_[0].y, points_[2].x - points_[0].x, - points_[2].y - points_[0].y); - renderer.fillRect(Rect(rect.origin + offset, rect.size), color_); - } else { - for (size_t i = 0; i < points_.size(); ++i) { - Vec2 start = points_[i] + offset; - Vec2 end = points_[(i + 1) % points_.size()] + offset; - renderer.drawLine(start, end, color_, lineWidth_); + switch (shapeType_) { + case ShapeType::Point: + if (!points_.empty()) { + renderer.fillCircle(points_[0] + offset, lineWidth_ * 0.5f, color_, 8); } - } + break; + + case ShapeType::Line: + if (points_.size() >= 2) { + renderer.drawLine(points_[0] + offset, points_[1] + offset, color_, lineWidth_); + } + break; + + case ShapeType::Rect: + if (points_.size() >= 4) { + Rect rect(points_[0].x, points_[0].y, points_[2].x - points_[0].x, + points_[2].y - points_[0].y); + Rect worldRect(rect.origin + offset, rect.size); + if (filled_) { + renderer.fillRect(worldRect, color_); + } else { + renderer.drawRect(worldRect, color_, lineWidth_); + } + } + break; + + case ShapeType::Circle: + if (points_.size() >= 2) { + float radius = points_[1].x; + if (filled_) { + renderer.fillCircle(points_[0] + offset, radius, color_, segments_); + } else { + renderer.drawCircle(points_[0] + offset, radius, color_, segments_, lineWidth_); + } + } + break; + + case ShapeType::Triangle: + if (points_.size() >= 3) { + Vec2 p1 = points_[0] + offset; + Vec2 p2 = points_[1] + offset; + Vec2 p3 = points_[2] + offset; + if (filled_) { + renderer.fillTriangle(p1, p2, p3, color_); + } else { + renderer.drawTriangle(p1, p2, p3, color_, lineWidth_); + } + } + break; + + case ShapeType::Polygon: + if (!points_.empty()) { + std::vector transformedPoints; + transformedPoints.reserve(points_.size()); + for (const auto& p : points_) { + transformedPoints.push_back(p + offset); + } + + if (filled_) { + renderer.fillPolygon(transformedPoints, color_); + } else { + renderer.drawPolygon(transformedPoints, color_, lineWidth_); + } + } + break; } - break; - - case ShapeType::Circle: - if (points_.size() >= 2) { - float radius = points_[1].x; - if (filled_) { - renderer.fillCircle(points_[0] + offset, radius, color_, segments_); - } else { - renderer.drawCircle(points_[0] + offset, radius, color_, segments_, - lineWidth_); - } - } - break; - - case ShapeType::Triangle: - if (points_.size() >= 3) { - Vec2 p1 = points_[0] + offset; - Vec2 p2 = points_[1] + offset; - Vec2 p3 = points_[2] + offset; - if (filled_) { - renderer.fillTriangle(p1, p2, p3, color_); - } else { - renderer.drawLine(p1, p2, color_, lineWidth_); - renderer.drawLine(p2, p3, color_, lineWidth_); - renderer.drawLine(p3, p1, color_, lineWidth_); - } - } - break; - - case ShapeType::Polygon: - if (!points_.empty()) { - std::vector transformedPoints; - transformedPoints.reserve(points_.size()); - for (const auto &p : points_) { - transformedPoints.push_back(p + offset); - } - - if (filled_) { - renderer.fillPolygon(transformedPoints, color_); - } else { - renderer.drawPolygon(transformedPoints, color_, lineWidth_); - } - } - break; - } -} - -void ShapeNode::generateRenderCommand(std::vector &commands, - int zOrder) { - if (points_.empty()) { - return; - } - - Vec2 offset = getPosition(); - RenderCommand cmd; - cmd.layer = zOrder; - - switch (shapeType_) { - case ShapeType::Point: - if (!points_.empty()) { - cmd.type = RenderCommandType::FilledCircle; - cmd.data = - CircleCommandData{points_[0] + offset, lineWidth_ * 0.5f, color_, 8, 0.0f, true}; - } - break; - - case ShapeType::Line: - if (points_.size() >= 2) { - cmd.type = RenderCommandType::Line; - cmd.data = LineCommandData{points_[0] + offset, points_[1] + offset, color_, - lineWidth_}; - } - break; - - case ShapeType::Rect: - if (points_.size() >= 4) { - if (filled_) { - cmd.type = RenderCommandType::FilledRect; - Rect rect(points_[0].x, points_[0].y, points_[2].x - points_[0].x, - points_[2].y - points_[0].y); - cmd.data = - RectCommandData{Rect(rect.origin + offset, rect.size), color_, 0.0f, true}; - } else { - cmd.type = RenderCommandType::Rect; - Rect rect(points_[0].x, points_[0].y, points_[2].x - points_[0].x, - points_[2].y - points_[0].y); - cmd.data = - RectCommandData{Rect(rect.origin + offset, rect.size), color_, lineWidth_, false}; - } - } - break; - - case ShapeType::Circle: - if (points_.size() >= 2) { - float radius = points_[1].x; - if (filled_) { - cmd.type = RenderCommandType::FilledCircle; - cmd.data = - CircleCommandData{points_[0] + offset, radius, color_, segments_, 0.0f, true}; - } else { - cmd.type = RenderCommandType::Circle; - cmd.data = CircleCommandData{points_[0] + offset, radius, color_, segments_, - lineWidth_, false}; - } - } - break; - - case ShapeType::Triangle: - if (points_.size() >= 3) { - Vec2 p1 = points_[0] + offset; - Vec2 p2 = points_[1] + offset; - Vec2 p3 = points_[2] + offset; - if (filled_) { - cmd.type = RenderCommandType::FilledTriangle; - cmd.data = TriangleCommandData{p1, p2, p3, color_, 0.0f, true}; - } else { - cmd.type = RenderCommandType::Triangle; - cmd.data = TriangleCommandData{p1, p2, p3, color_, lineWidth_, false}; - } - } - break; - - case ShapeType::Polygon: - if (!points_.empty()) { - std::vector transformedPoints; - transformedPoints.reserve(points_.size()); - for (const auto &p : points_) { - transformedPoints.push_back(p + offset); - } - - if (filled_) { - cmd.type = RenderCommandType::FilledPolygon; - cmd.data = PolygonCommandData{transformedPoints, color_, 0.0f, true}; - } else { - cmd.type = RenderCommandType::Polygon; - cmd.data = PolygonCommandData{transformedPoints, color_, lineWidth_, false}; - } - } - break; - } - - commands.push_back(std::move(cmd)); } } // namespace extra2d diff --git a/Extra2D/src/scene/sprite.cpp b/Extra2D/src/scene/sprite.cpp index cc67570..7d4ccc8 100644 --- a/Extra2D/src/scene/sprite.cpp +++ b/Extra2D/src/scene/sprite.cpp @@ -1,167 +1,114 @@ #include #include -#include -#include -#include +#include +#include #include namespace extra2d { Sprite::Sprite() = default; -Sprite::Sprite(Ptr texture) { setTexture(texture); } - -void Sprite::setTexture(Ptr texture) { - texture_ = texture; - if (texture_) { - textureRect_ = Rect(0, 0, static_cast(texture_->getWidth()), - static_cast(texture_->getHeight())); - } - updateSpatialIndex(); +Sprite::Sprite(Ref texture) { + setTexture(texture); } -void Sprite::setTextureRect(const Rect &rect) { - textureRect_ = rect; - updateSpatialIndex(); +void Sprite::setTexture(Ref texture) { + texture_ = texture; + if (texture_) { + textureRect_ = Rect(0, 0, static_cast(texture_->width()), + static_cast(texture_->height())); + } + updateSpatialIndex(); } -void Sprite::setColor(const Color &color) { color_ = color; } - -void Sprite::setFlipX(bool flip) { flipX_ = flip; } - -void Sprite::setFlipY(bool flip) { flipY_ = flip; } - -Ptr Sprite::create() { return makePtr(); } - -Ptr Sprite::create(Ptr texture) { - return makePtr(texture); +void Sprite::setTextureRect(const Rect& rect) { + textureRect_ = rect; + updateSpatialIndex(); } -Ptr Sprite::create(Ptr texture, const Rect &rect) { - auto sprite = makePtr(texture); - sprite->setTextureRect(rect); - return sprite; +void Sprite::setColor(const Color& color) { + color_ = color; +} + +void Sprite::setFlipX(bool flip) { + flipX_ = flip; +} + +void Sprite::setFlipY(bool flip) { + flipY_ = flip; +} + +Ref Sprite::create() { + return ptr::make(); +} + +Ref Sprite::create(Ref texture) { + return ptr::make(texture); +} + +Ref Sprite::create(Ref texture, const Rect& rect) { + auto sprite = ptr::make(texture); + sprite->setTextureRect(rect); + return sprite; } Rect Sprite::getBoundingBox() const { - if (!texture_ || !texture_->isValid()) { - return Rect(); - } + if (!texture_ || !texture_->isValid()) { + return Rect(); + } - float width = textureRect_.width(); - float height = textureRect_.height(); + float width = textureRect_.width(); + float height = textureRect_.height(); - auto pos = getPosition(); - auto anchor = getAnchor(); - auto scale = getScale(); + auto pos = getPosition(); + auto anchor = getAnchor(); + auto scale = getScale(); - float w = width * scale.x; - float h = height * scale.y; - float x0 = pos.x - width * anchor.x * scale.x; - float y0 = pos.y - height * anchor.y * scale.y; - float x1 = x0 + w; - float y1 = y0 + h; + float w = width * scale.x; + float h = height * scale.y; + float x0 = pos.x - width * anchor.x * scale.x; + float y0 = pos.y - height * anchor.y * scale.y; + float x1 = x0 + w; + float y1 = y0 + h; - float l = std::min(x0, x1); - float t = std::min(y0, y1); - return Rect(l, t, std::abs(w), std::abs(h)); + float l = std::min(x0, x1); + float t = std::min(y0, y1); + return Rect(l, t, std::abs(w), std::abs(h)); } -void Sprite::onDraw(Renderer &renderer) { - if (!texture_ || !texture_->isValid()) { - return; - } +void Sprite::onDraw(Renderer& renderer) { + if (!texture_ || !texture_->isValid()) { + return; + } - // Calculate destination rectangle based on texture rect - float width = textureRect_.width(); - float height = textureRect_.height(); + float width = textureRect_.width(); + float height = textureRect_.height(); - // 使用世界变换来获取最终的位置 - auto worldTransform = getWorldTransform(); + auto worldTransform = getWorldTransform(); - // 从世界变换矩阵中提取位置(第四列) - float worldX = worldTransform[3][0]; - float worldY = worldTransform[3][1]; + float worldX = worldTransform[3][0]; + float worldY = worldTransform[3][1]; - // 从世界变换矩阵中提取缩放 - float worldScaleX = - glm::length(glm::vec2(worldTransform[0][0], worldTransform[0][1])); - float worldScaleY = - glm::length(glm::vec2(worldTransform[1][0], worldTransform[1][1])); + float worldScaleX = glm::length(glm::vec2(worldTransform[0][0], worldTransform[0][1])); + float worldScaleY = glm::length(glm::vec2(worldTransform[1][0], worldTransform[1][1])); - auto anchor = getAnchor(); + auto anchor = getAnchor(); - // 锚点由 Renderer 在绘制时处理,这里只传递位置和尺寸 - Rect destRect(worldX, worldY, width * worldScaleX, height * worldScaleY); + Rect destRect(worldX, worldY, width * worldScaleX, height * worldScaleY); - // Adjust source rect for flipping - Rect srcRect = textureRect_; - if (flipX_) { - srcRect.origin.x = srcRect.right(); - srcRect.size.width = -srcRect.size.width; - } - if (flipY_) { - srcRect.origin.y = srcRect.bottom(); - srcRect.size.height = -srcRect.size.height; - } + Rect srcRect = textureRect_; + if (flipX_) { + srcRect.origin.x = srcRect.right(); + srcRect.size.width = -srcRect.size.width; + } + if (flipY_) { + srcRect.origin.y = srcRect.bottom(); + srcRect.size.height = -srcRect.size.height; + } - // 从世界变换矩阵中提取旋转角度 - float worldRotation = std::atan2(worldTransform[0][1], worldTransform[0][0]); + float worldRotation = std::atan2(worldTransform[0][1], worldTransform[0][0]); - renderer.drawSprite(*texture_, destRect, srcRect, color_, worldRotation, - anchor); -} - -void Sprite::generateRenderCommand(std::vector &commands, - int zOrder) { - if (!texture_ || !texture_->isValid()) { - return; - } - - // 计算目标矩形(与 onDraw 一致,使用世界变换) - float width = textureRect_.width(); - float height = textureRect_.height(); - - // 使用世界变换来获取最终的位置 - auto worldTransform = getWorldTransform(); - - // 从世界变换矩阵中提取位置(第四列) - float worldX = worldTransform[3][0]; - float worldY = worldTransform[3][1]; - - // 从世界变换矩阵中提取缩放 - float worldScaleX = - glm::length(glm::vec2(worldTransform[0][0], worldTransform[0][1])); - float worldScaleY = - glm::length(glm::vec2(worldTransform[1][0], worldTransform[1][1])); - - auto anchor = getAnchor(); - - // 锚点由 Renderer 在绘制时处理,这里只传递位置和尺寸 - Rect destRect(worldX, worldY, width * worldScaleX, height * worldScaleY); - - // 调整源矩形(翻转) - Rect srcRect = textureRect_; - if (flipX_) { - srcRect.origin.x = srcRect.right(); - srcRect.size.width = -srcRect.size.width; - } - if (flipY_) { - srcRect.origin.y = srcRect.bottom(); - srcRect.size.height = -srcRect.size.height; - } - - // 从世界变换矩阵中提取旋转角度 - float worldRotation = std::atan2(worldTransform[0][1], worldTransform[0][0]); - - // 创建渲染命令 - RenderCommand cmd; - cmd.type = RenderCommandType::Sprite; - cmd.layer = zOrder; - cmd.data = SpriteCommandData{texture_.get(), destRect, srcRect, color_, - worldRotation, anchor, 0}; - - commands.push_back(std::move(cmd)); + renderer.drawSprite(*texture_, destRect, srcRect, color_, worldRotation, anchor); } } // namespace extra2d diff --git a/Extra2D/src/services/logger_service.cpp b/Extra2D/src/services/logger_service.cpp index 71cf410..0e59e3b 100644 --- a/Extra2D/src/services/logger_service.cpp +++ b/Extra2D/src/services/logger_service.cpp @@ -1,193 +1,267 @@ -#include #include #include #include #include - -#ifdef _WIN32 -#include -#endif +#include namespace extra2d { -#ifdef _WIN32 -static bool enableWindowsConsoleFeatures() { - bool success = true; - - HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); - if (hOut != INVALID_HANDLE_VALUE) { - DWORD dwMode = 0; - if (GetConsoleMode(hOut, &dwMode)) { - dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; - if (!SetConsoleMode(hOut, dwMode)) { - success = false; - } - } else { - success = false; - } - } - - SetConsoleOutputCP(CP_UTF8); - SetConsoleCP(CP_UTF8); - - return success; -} - -static bool g_windowsConsoleInitialized = false; -#endif - class ConsoleLogger::Impl { public: - std::mutex mutex_; + std::mutex mutex_; + SDL_LogPriority sdlPriorities_[7]; + bool customOutputSet_ = false; }; +static SDL_LogPriority toSDLPriority(LogLevel lvl) { + switch (lvl) { + case LogLevel::Trace: return SDL_LOG_PRIORITY_VERBOSE; + case LogLevel::Debug: return SDL_LOG_PRIORITY_DEBUG; + case LogLevel::Info: return SDL_LOG_PRIORITY_INFO; + case LogLevel::Registry: return SDL_LOG_PRIORITY_INFO; + case LogLevel::Warn: return SDL_LOG_PRIORITY_WARN; + case LogLevel::Error: return SDL_LOG_PRIORITY_ERROR; + case LogLevel::Fatal: return SDL_LOG_PRIORITY_CRITICAL; + default: return SDL_LOG_PRIORITY_INFO; + } +} + +static LogLevel fromSDLPriority(SDL_LogPriority priority) { + switch (priority) { + case SDL_LOG_PRIORITY_VERBOSE: return LogLevel::Trace; + case SDL_LOG_PRIORITY_DEBUG: return LogLevel::Debug; + case SDL_LOG_PRIORITY_INFO: return LogLevel::Info; + case SDL_LOG_PRIORITY_WARN: return LogLevel::Warn; + case SDL_LOG_PRIORITY_ERROR: return LogLevel::Error; + case SDL_LOG_PRIORITY_CRITICAL: return LogLevel::Fatal; + default: return LogLevel::Info; + } +} + +static ConsoleLogger* g_loggerInstance = nullptr; + +static void SDLCALL sdlLogOutputFunction(void* userdata, int category, + SDL_LogPriority priority, + const char* message) { + if (!g_loggerInstance) return; + + ConsoleLogger* logger = static_cast(g_loggerInstance); + LogLevel lvl = fromSDLPriority(priority); + + if (!logger->enabled(lvl)) return; + + const char* levelStr = logger->levelString(lvl); + const char* categoryStr = ""; + switch (category) { + case SDL_LOG_CATEGORY_APPLICATION: categoryStr = "APP"; break; + case SDL_LOG_CATEGORY_ERROR: categoryStr = "ERR"; break; + case SDL_LOG_CATEGORY_ASSERT: categoryStr = "ASR"; break; + case SDL_LOG_CATEGORY_SYSTEM: categoryStr = "SYS"; break; + case SDL_LOG_CATEGORY_AUDIO: categoryStr = "AUD"; break; + case SDL_LOG_CATEGORY_VIDEO: categoryStr = "VID"; break; + case SDL_LOG_CATEGORY_RENDER: categoryStr = "RDR"; break; + case SDL_LOG_CATEGORY_INPUT: categoryStr = "INP"; break; + case SDL_LOG_CATEGORY_TEST: categoryStr = "TST"; break; + default: categoryStr = "GEN"; break; + } + + Uint32 ticks = SDL_GetTicks(); + Uint32 seconds = ticks / 1000; + Uint32 minutes = seconds / 60; + Uint32 hours = minutes / 60; + + if (logger->colors()) { + std::string color = logger->ansiColor(lvl); + const char* reset = "\033[0m"; + printf("%s[%02u:%02u:%02u.%03u] [%s][%s] %s%s\n", + color.c_str(), + hours % 24, minutes % 60, seconds % 60, ticks % 1000, + levelStr, categoryStr, message, reset); + } else { + printf("[%02u:%02u:%02u.%03u] [%s][%s] %s\n", + hours % 24, minutes % 60, seconds % 60, ticks % 1000, + levelStr, categoryStr, message); + } +} + ConsoleLogger::ConsoleLogger() : level_(LogLevel::Info), colors_(true), impl_(std::make_unique()) { - info_.name = "ConsoleLogger"; - info_.priority = ServicePriority::Core; + info_.name = "ConsoleLogger"; + info_.priority = ServicePriority::Core; - levelColors_[static_cast(LogLevel::Trace)] = LogColor::Gray(); - levelColors_[static_cast(LogLevel::Debug)] = LogColor::Cyan(); - levelColors_[static_cast(LogLevel::Info)] = LogColor::SkyLight(); - levelColors_[static_cast(LogLevel::Registry)] = LogColor::IndigoLight(); - levelColors_[static_cast(LogLevel::Warn)] = LogColor::Yellow(); - levelColors_[static_cast(LogLevel::Error)] = LogColor::Red(); - levelColors_[static_cast(LogLevel::Fatal)] = LogColor::Magenta(); + levelColors_[static_cast(LogLevel::Trace)] = LogColor::Gray(); + levelColors_[static_cast(LogLevel::Debug)] = LogColor::Cyan(); + levelColors_[static_cast(LogLevel::Info)] = LogColor::SkyLight(); + levelColors_[static_cast(LogLevel::Registry)] = LogColor::IndigoLight(); + levelColors_[static_cast(LogLevel::Warn)] = LogColor::Yellow(); + levelColors_[static_cast(LogLevel::Error)] = LogColor::Red(); + levelColors_[static_cast(LogLevel::Fatal)] = LogColor::Magenta(); -#ifdef _WIN32 - if (!g_windowsConsoleInitialized) { - g_windowsConsoleInitialized = enableWindowsConsoleFeatures(); - } -#endif + for (int i = 0; i < 7; ++i) { + impl_->sdlPriorities_[i] = toSDLPriority(static_cast(i)); + } } -ConsoleLogger::~ConsoleLogger() = default; +ConsoleLogger::~ConsoleLogger() { + if (impl_->customOutputSet_) { + SDL_LogSetOutputFunction(nullptr, nullptr); + } + g_loggerInstance = nullptr; +} bool ConsoleLogger::init() { - setState(ServiceState::Running); - return true; + g_loggerInstance = this; + + SDL_LogSetOutputFunction(sdlLogOutputFunction, this); + impl_->customOutputSet_ = true; + + SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, toSDLPriority(level_)); + + setState(ServiceState::Running); + return true; } -void ConsoleLogger::shutdown() { setState(ServiceState::Stopped); } +void ConsoleLogger::shutdown() { + if (impl_->customOutputSet_) { + SDL_LogSetOutputFunction(nullptr, nullptr); + impl_->customOutputSet_ = false; + } + g_loggerInstance = nullptr; + setState(ServiceState::Stopped); +} -void ConsoleLogger::level(LogLevel lvl) { level_ = lvl; } +void ConsoleLogger::level(LogLevel lvl) { + level_ = lvl; + SDL_LogPriority priority = toSDLPriority(lvl); + SDL_LogSetAllPriority(priority); +} -LogLevel ConsoleLogger::level() const { return level_; } +LogLevel ConsoleLogger::level() const { + return level_; +} bool ConsoleLogger::enabled(LogLevel lvl) const { - return static_cast(lvl) >= static_cast(level_); + return static_cast(lvl) >= static_cast(level_); } void ConsoleLogger::log(LogLevel lvl, const char *fmt, ...) { - if (!enabled(lvl)) - return; + if (!enabled(lvl)) return; - char buffer[1024]; - va_list args; - va_start(args, fmt); - vsnprintf(buffer, sizeof(buffer), fmt, args); - va_end(args); + char buffer[2048]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); - output(lvl, buffer); + SDL_LogPriority priority = toSDLPriority(lvl); + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, priority, "%s", buffer); } void ConsoleLogger::log(LogLevel lvl, const std::string &msg) { - if (!enabled(lvl)) - return; - output(lvl, msg.c_str()); + if (!enabled(lvl)) return; + + SDL_LogPriority priority = toSDLPriority(lvl); + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, priority, "%s", msg.c_str()); } void ConsoleLogger::trace(const char *fmt, ...) { - if (!enabled(LogLevel::Trace)) - return; - char buffer[1024]; - va_list args; - va_start(args, fmt); - vsnprintf(buffer, sizeof(buffer), fmt, args); - va_end(args); - output(LogLevel::Trace, buffer); + if (!enabled(LogLevel::Trace)) return; + + char buffer[2048]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + + SDL_LogVerbose(SDL_LOG_CATEGORY_APPLICATION, "%s", buffer); } void ConsoleLogger::debug(const char *fmt, ...) { - if (!enabled(LogLevel::Debug)) - return; - char buffer[1024]; - va_list args; - va_start(args, fmt); - vsnprintf(buffer, sizeof(buffer), fmt, args); - va_end(args); - output(LogLevel::Debug, buffer); + if (!enabled(LogLevel::Debug)) return; + + char buffer[2048]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + + SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "%s", buffer); } void ConsoleLogger::info(const char *fmt, ...) { - if (!enabled(LogLevel::Info)) - return; - char buffer[1024]; - va_list args; - va_start(args, fmt); - vsnprintf(buffer, sizeof(buffer), fmt, args); - va_end(args); - output(LogLevel::Info, buffer); + if (!enabled(LogLevel::Info)) return; + + char buffer[2048]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "%s", buffer); } void ConsoleLogger::registry(const char *fmt, ...) { - if (!enabled(LogLevel::Registry)) - return; - char buffer[1024]; - va_list args; - va_start(args, fmt); - vsnprintf(buffer, sizeof(buffer), fmt, args); - va_end(args); - output(LogLevel::Registry, buffer); + if (!enabled(LogLevel::Registry)) return; + + char buffer[2048]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[REGISTRY] %s", buffer); } void ConsoleLogger::warn(const char *fmt, ...) { - if (!enabled(LogLevel::Warn)) - return; - char buffer[1024]; - va_list args; - va_start(args, fmt); - vsnprintf(buffer, sizeof(buffer), fmt, args); - va_end(args); - output(LogLevel::Warn, buffer); + if (!enabled(LogLevel::Warn)) return; + + char buffer[2048]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "%s", buffer); } void ConsoleLogger::error(const char *fmt, ...) { - if (!enabled(LogLevel::Error)) - return; - char buffer[1024]; - va_list args; - va_start(args, fmt); - vsnprintf(buffer, sizeof(buffer), fmt, args); - va_end(args); - output(LogLevel::Error, buffer); + if (!enabled(LogLevel::Error)) return; + + char buffer[2048]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s", buffer); } void ConsoleLogger::fatal(const char *fmt, ...) { - if (!enabled(LogLevel::Fatal)) - return; - char buffer[1024]; - va_list args; - va_start(args, fmt); - vsnprintf(buffer, sizeof(buffer), fmt, args); - va_end(args); - output(LogLevel::Fatal, buffer); + if (!enabled(LogLevel::Fatal)) return; + + char buffer[2048]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + + SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "%s", buffer); } void ConsoleLogger::levelColor(LogLevel lvl, const LogColor &c) { - int idx = static_cast(lvl); - if (idx >= 0 && idx < 7) { - levelColors_[idx] = c; - } + int idx = static_cast(lvl); + if (idx >= 0 && idx < 7) { + levelColors_[idx] = c; + } } LogColor ConsoleLogger::levelColor(LogLevel lvl) const { - int idx = static_cast(lvl); - if (idx >= 0 && idx < 7) { - return levelColors_[idx]; - } - return LogColor::White(); + int idx = static_cast(lvl); + if (idx >= 0 && idx < 7) { + return levelColors_[idx]; + } + return LogColor::White(); } void ConsoleLogger::colors(bool on) { colors_ = on; } @@ -195,60 +269,23 @@ void ConsoleLogger::colors(bool on) { colors_ = on; } bool ConsoleLogger::colors() const { return colors_; } std::string ConsoleLogger::ansiColor(LogLevel lvl) { - const LogColor &c = levelColor(lvl); - char buf[32]; - snprintf(buf, sizeof(buf), "\033[38;2;%d;%d;%dm", c.r, c.g, c.b); - return std::string(buf); -} - -void ConsoleLogger::output(LogLevel lvl, const char *msg) { - std::lock_guard lock(impl_->mutex_); - - auto now = std::chrono::system_clock::now(); - auto time = std::chrono::system_clock::to_time_t(now); - auto ms = std::chrono::duration_cast( - now.time_since_epoch()) % - 1000; - - std::tm tm; -#ifdef _WIN32 - localtime_s(&tm, &time); -#else - localtime_r(&time, &tm); -#endif - - const char *levelStr = levelString(lvl); - const char *reset = "\033[0m"; - - if (colors_) { - std::string color = ansiColor(lvl); - printf("%s[%02d:%02d:%02d.%03d] [%s] %s%s\n", color.c_str(), tm.tm_hour, - tm.tm_min, tm.tm_sec, (int)ms.count(), levelStr, msg, reset); - } else { - printf("[%02d:%02d:%02d.%03d] [%s] %s\n", tm.tm_hour, tm.tm_min, tm.tm_sec, - (int)ms.count(), levelStr, msg); - } + const LogColor &c = levelColor(lvl); + char buf[32]; + snprintf(buf, sizeof(buf), "\033[38;2;%d;%d;%dm", c.r, c.g, c.b); + return std::string(buf); } const char *ConsoleLogger::levelString(LogLevel lvl) { - switch (lvl) { - case LogLevel::Trace: - return "TRACE"; - case LogLevel::Debug: - return "DEBUG"; - case LogLevel::Info: - return "INFO"; - case LogLevel::Registry: - return "REGISTRY"; - case LogLevel::Warn: - return "WARN"; - case LogLevel::Error: - return "ERROR"; - case LogLevel::Fatal: - return "FATAL"; - default: - return "UNKNOWN"; - } + switch (lvl) { + case LogLevel::Trace: return "TRACE"; + case LogLevel::Debug: return "DEBUG"; + case LogLevel::Info: return "INFO"; + case LogLevel::Registry: return "REGISTRY"; + case LogLevel::Warn: return "WARN"; + case LogLevel::Error: return "ERROR"; + case LogLevel::Fatal: return "FATAL"; + default: return "UNKNOWN"; + } } } // namespace extra2d diff --git a/Extra2D/src/utils/data.cpp b/Extra2D/src/utils/data.cpp index 52a300a..76f36e9 100644 --- a/Extra2D/src/utils/data.cpp +++ b/Extra2D/src/utils/data.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include // Switch 平台特定头文件 diff --git a/Extra2D/src/utils/logger.cpp b/Extra2D/src/utils/logger.cpp deleted file mode 100644 index 1f03a2f..0000000 --- a/Extra2D/src/utils/logger.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include - -namespace extra2d { - -// 静态成员定义 -LogLevel Logger::level_ = LogLevel::Info; -bool Logger::initialized_ = false; -bool Logger::consoleOutput_ = true; -bool Logger::fileOutput_ = false; -std::string Logger::logFile_; - -/** - * @brief 获取日志级别字符串 - * @param level 日志级别 - * @return 级别字符串 - */ -const char *Logger::getLevelString(LogLevel level) { - switch (level) { - case LogLevel::Trace: - return "TRACE"; - case LogLevel::Debug: - return "DEBUG"; - case LogLevel::Info: - return "INFO "; - case LogLevel::Warn: - return "WARN "; - case LogLevel::Error: - return "ERROR"; - case LogLevel::Fatal: - return "FATAL"; - default: - return "UNKNOWN"; - } -} - -/** - * @brief 初始化日志系统 - */ -void Logger::init() { - if (initialized_) { - return; - } - - // 设置 SDL 日志级别为详细模式(允许所有级别的日志) - SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_VERBOSE); - - initialized_ = true; - log(LogLevel::Info, "Logger initialized with SDL2"); -} - -/** - * @brief 关闭日志系统 - */ -void Logger::shutdown() { - if (initialized_) { - log(LogLevel::Info, "Logger shutting down"); - } - initialized_ = false; -} - -/** - * @brief 设置日志级别 - * @param level 日志级别 - */ -void Logger::setLevel(LogLevel level) { - level_ = level; - // 同时设置 SDL 的日志级别 - if (level != LogLevel::Off) { - SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, - static_cast(level)); - } -} - -/** - * @brief 设置是否输出到控制台 - * @param enable 是否启用 - */ -void Logger::setConsoleOutput(bool enable) { - consoleOutput_ = enable; - // SDL2 日志默认输出到控制台,通过设置日志优先级控制 - if (!enable) { - SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_CRITICAL); - } else { - SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, - static_cast(level_)); - } -} - -/** - * @brief 设置日志输出到文件 - * @param filename 日志文件名 - */ -void Logger::setFileOutput(const std::string &filename) { - logFile_ = filename; - fileOutput_ = !filename.empty(); - - if (fileOutput_) { - // SDL2 使用 SDL_LogSetOutputFunction 可以重定向日志输出 - // 这里我们记录文件路径,实际文件输出可以通过自定义回调实现 - log(LogLevel::Info, "File output configured: {}", filename); - } -} - -} // namespace extra2d diff --git a/Extra2D/src/utils/object_pool.cpp b/Extra2D/src/utils/object_pool.cpp deleted file mode 100644 index 1c929c9..0000000 --- a/Extra2D/src/utils/object_pool.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include - -namespace extra2d { - -// ObjectPoolManager 单例实现 -// 所有对象池通过静态局部变量自动管理生命周期 -// 程序退出时自动清理,无需手动调用 cleanup - -} // namespace extra2d diff --git a/Extra2D/src/window/window.cpp b/Extra2D/src/window/window.cpp index d4d54ab..d786733 100644 --- a/Extra2D/src/window/window.cpp +++ b/Extra2D/src/window/window.cpp @@ -1,63 +1,33 @@ +#include #include -#include -#include #include -#include namespace extra2d { Window::Window() - : sdlWindow_(nullptr), glContext_(nullptr), - width_(1280), height_(720), vsync_(true), shouldClose_(false), - fullscreen_(true) { -} + : sdlWindow_(nullptr), width_(1280), height_(720), fullscreen_(true), + shouldClose_(false) {} Window::~Window() { destroy(); } bool Window::create(const WindowConfig &config) { if (sdlWindow_ != nullptr) { - E2D_LOG_WARN("Window already created"); + E2D_WARN("Window already created"); return false; } width_ = config.width; height_ = config.height; - vsync_ = config.vsync; fullscreen_ = config.fullscreen; - if (!initSDL(config)) { - E2D_LOG_ERROR("Failed to initialize SDL2"); - return false; - } - - input_ = makeUnique(); - input_->init(); - - E2D_LOG_INFO("Window created: {}x{}", width_, height_); - return true; -} - -bool Window::initSDL(const WindowConfig &config) { if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) != 0) { - E2D_LOG_ERROR("SDL_Init failed: {}", SDL_GetError()); + E2D_ERROR("SDL_Init failed: {}", SDL_GetError()); return false; } - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); - - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - Uint32 windowFlags = SDL_WINDOW_OPENGL; - + if (config.fullscreen) { windowFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP; } else { @@ -71,70 +41,23 @@ bool Window::initSDL(const WindowConfig &config) { config.centerWindow ? SDL_WINDOWPOS_CENTERED : SDL_WINDOWPOS_UNDEFINED, config.centerWindow ? SDL_WINDOWPOS_CENTERED : SDL_WINDOWPOS_UNDEFINED, width_, height_, windowFlags); - + if (!sdlWindow_) { - E2D_LOG_ERROR("SDL_CreateWindow failed: {}", SDL_GetError()); + E2D_ERROR("SDL_CreateWindow failed: {}", SDL_GetError()); SDL_Quit(); return false; } - glContext_ = SDL_GL_CreateContext(sdlWindow_); - if (!glContext_) { - E2D_LOG_ERROR("SDL_GL_CreateContext failed: {}", SDL_GetError()); - SDL_DestroyWindow(sdlWindow_); - sdlWindow_ = nullptr; - SDL_Quit(); - return false; - } - - if (SDL_GL_MakeCurrent(sdlWindow_, glContext_) != 0) { - E2D_LOG_ERROR("SDL_GL_MakeCurrent failed: {}", SDL_GetError()); - SDL_GL_DeleteContext(glContext_); - glContext_ = nullptr; - SDL_DestroyWindow(sdlWindow_); - sdlWindow_ = nullptr; - SDL_Quit(); - return false; - } - - if (gladLoadGLES2Loader(reinterpret_cast(SDL_GL_GetProcAddress)) == 0) { - E2D_LOG_ERROR("gladLoadGLES2Loader failed"); - SDL_GL_DeleteContext(glContext_); - glContext_ = nullptr; - SDL_DestroyWindow(sdlWindow_); - sdlWindow_ = nullptr; - SDL_Quit(); - return false; - } - - SDL_GL_SetSwapInterval(vsync_ ? 1 : 0); - - E2D_LOG_INFO("SDL2 + OpenGL ES 3.0 initialized successfully"); - E2D_LOG_INFO("OpenGL Version: {}", reinterpret_cast(glGetString(GL_VERSION))); - E2D_LOG_INFO("OpenGL Renderer: {}", reinterpret_cast(glGetString(GL_RENDERER))); - + E2D_INFO("Window created: {}x{}", width_, height_); return true; } -void Window::deinitSDL() { - if (glContext_) { - SDL_GL_DeleteContext(glContext_); - glContext_ = nullptr; - } - - if (sdlWindow_) { - SDL_DestroyWindow(sdlWindow_); - sdlWindow_ = nullptr; - } - - SDL_Quit(); -} - void Window::destroy() { if (sdlWindow_ != nullptr) { - input_.reset(); - deinitSDL(); - E2D_LOG_INFO("Window destroyed"); + SDL_DestroyWindow(sdlWindow_); + sdlWindow_ = nullptr; + SDL_Quit(); + E2D_INFO("Window destroyed"); } } @@ -155,16 +78,6 @@ void Window::pollEvents() { break; } } - - if (input_) { - input_->update(); - } -} - -void Window::swapBuffers() { - if (sdlWindow_) { - SDL_GL_SwapWindow(sdlWindow_); - } } bool Window::shouldClose() const { return shouldClose_; } @@ -193,9 +106,4 @@ void Window::setFullscreen(bool fullscreen) { } } -void Window::setVSync(bool enabled) { - vsync_ = enabled; - SDL_GL_SetSwapInterval(enabled ? 1 : 0); -} - } // namespace extra2d diff --git a/xmake/engine.lua b/xmake/engine.lua index fa5951c..f8a7e62 100644 --- a/xmake/engine.lua +++ b/xmake/engine.lua @@ -44,7 +44,7 @@ function define_extra2d_engine() add_cxxflags("-Wno-deprecated-copy", "-Wno-class-memaccess", {force = true}) if is_mode("debug") then - add_defines("E2D_DEBUG", "_DEBUG", {public = true}) + add_defines("_DEBUG", {public = true}) add_cxxflags("-O0", "-g", {force = true}) else add_defines("NDEBUG", {public = true})