diff --git a/Extra2D/include/extra2d/app/application.h b/Extra2D/include/extra2d/app/application.h index 53be8fa..69bdefd 100644 --- a/Extra2D/include/extra2d/app/application.h +++ b/Extra2D/include/extra2d/app/application.h @@ -36,7 +36,7 @@ struct AppConfig { */ class Application { public: - static Application &instance(); + static Application &get(); Application(const Application &) = delete; Application &operator=(const Application &) = delete; diff --git a/Extra2D/include/extra2d/graphics/camera.h b/Extra2D/include/extra2d/graphics/camera.h index 5c92804..110b9b5 100644 --- a/Extra2D/include/extra2d/graphics/camera.h +++ b/Extra2D/include/extra2d/graphics/camera.h @@ -22,8 +22,8 @@ public: // ------------------------------------------------------------------------ // 位置和变换 // ------------------------------------------------------------------------ - void setPosition(const Vec2 &position); - void setPosition(float x, float y); + void setPos(const Vec2 &position); + void setPos(float x, float y); Vec2 getPosition() const { return position_; } void setRotation(float degrees); @@ -74,7 +74,7 @@ public: * @brief 设置视口适配器 * @param adapter 视口适配器指针 */ - void setViewportAdapter(ViewportAdapter* adapter); + void setViewportAdapter(ViewportAdapter *adapter); /** * @brief 根据视口适配器自动设置视口 @@ -99,7 +99,7 @@ private: Rect bounds_; bool hasBounds_ = false; - ViewportAdapter* viewportAdapter_ = nullptr; + ViewportAdapter *viewportAdapter_ = nullptr; mutable glm::mat4 viewMatrix_; mutable glm::mat4 projMatrix_; diff --git a/Extra2D/include/extra2d/graphics/gpu_context.h b/Extra2D/include/extra2d/graphics/gpu_context.h index ecd9809..759a56a 100644 --- a/Extra2D/include/extra2d/graphics/gpu_context.h +++ b/Extra2D/include/extra2d/graphics/gpu_context.h @@ -13,7 +13,7 @@ namespace extra2d { class GPUContext { public: /// 获取单例实例 - static GPUContext& getInstance(); + static GPUContext& get(); /// 标记 GPU 上下文为有效(在初始化完成后调用) void markValid(); diff --git a/Extra2D/include/extra2d/graphics/render_target.h b/Extra2D/include/extra2d/graphics/render_target.h index e214c7d..56c4187 100644 --- a/Extra2D/include/extra2d/graphics/render_target.h +++ b/Extra2D/include/extra2d/graphics/render_target.h @@ -233,7 +233,7 @@ private: // ============================================================================ class RenderTargetStack { public: - static RenderTargetStack &getInstance(); + static RenderTargetStack &get(); /** * @brief 压入渲染目标 @@ -271,12 +271,12 @@ private: // ============================================================================ // 渲染目标管理器 - 全局渲染目标管理 // ============================================================================ -class RenderTargetManager { +class RenderTargetMgr { public: /** * @brief 获取单例实例 */ - static RenderTargetManager &getInstance(); + static RenderTargetMgr& get(); /** * @brief 初始化渲染目标管理器 @@ -313,10 +313,10 @@ public: bool isInitialized() const { return initialized_; } private: - RenderTargetManager() = default; - ~RenderTargetManager() = default; - RenderTargetManager(const RenderTargetManager &) = delete; - RenderTargetManager &operator=(const RenderTargetManager &) = delete; + RenderTargetMgr() = default; + ~RenderTargetMgr() = default; + RenderTargetMgr(const RenderTargetMgr &) = delete; + RenderTargetMgr &operator=(const RenderTargetMgr &) = delete; Ptr defaultRenderTarget_; std::vector> renderTargets_; @@ -326,8 +326,7 @@ private: // ============================================================================ // 便捷宏 // ============================================================================ -#define E2D_RENDER_TARGET_STACK() ::extra2d::RenderTargetStack::getInstance() -#define E2D_RENDER_TARGET_MANAGER() \ - ::extra2d::RenderTargetManager::getInstance() +#define E2D_RENDER_TARGET_STACK() ::extra2d::RenderTargetStack::get() +#define E2D_RENDER_TARGET_MGR() ::extra2d::RenderTargetMgr::get() } // namespace extra2d diff --git a/Extra2D/include/extra2d/graphics/shader_system.h b/Extra2D/include/extra2d/graphics/shader_system.h index a3af2fe..11d281a 100644 --- a/Extra2D/include/extra2d/graphics/shader_system.h +++ b/Extra2D/include/extra2d/graphics/shader_system.h @@ -22,7 +22,7 @@ public: // ------------------------------------------------------------------------ // 单例访问 // ------------------------------------------------------------------------ - static ShaderSystem &getInstance(); + static ShaderSystem &get(); // ------------------------------------------------------------------------ // 初始化和关闭 @@ -174,6 +174,6 @@ private: // ============================================================================ // 便捷宏 // ============================================================================ -#define E2D_SHADER_SYSTEM() ::extra2d::ShaderSystem::getInstance() +#define E2D_SHADER_SYSTEM() ::extra2d::ShaderSystem::get() } // namespace extra2d diff --git a/Extra2D/include/extra2d/graphics/texture_atlas.h b/Extra2D/include/extra2d/graphics/texture_atlas.h index a912040..68b891b 100644 --- a/Extra2D/include/extra2d/graphics/texture_atlas.h +++ b/Extra2D/include/extra2d/graphics/texture_atlas.h @@ -146,9 +146,9 @@ private: /** * @brief 全局图集管理器(单例) */ -class TextureAtlasManager { +class TextureAtlasMgr { public: - static TextureAtlasManager& getInstance(); + static TextureAtlasMgr& get(); // 获取主图集 TextureAtlas& getAtlas() { return atlas_; } @@ -172,11 +172,11 @@ public: } private: - TextureAtlasManager() = default; - ~TextureAtlasManager() = default; + TextureAtlasMgr() = default; + ~TextureAtlasMgr() = default; - TextureAtlasManager(const TextureAtlasManager&) = delete; - TextureAtlasManager& operator=(const TextureAtlasManager&) = delete; + TextureAtlasMgr(const TextureAtlasMgr&) = delete; + TextureAtlasMgr& operator=(const TextureAtlasMgr&) = delete; TextureAtlas atlas_; }; diff --git a/Extra2D/include/extra2d/graphics/viewport_adapter.h b/Extra2D/include/extra2d/graphics/viewport_adapter.h index db0ac4d..23db783 100644 --- a/Extra2D/include/extra2d/graphics/viewport_adapter.h +++ b/Extra2D/include/extra2d/graphics/viewport_adapter.h @@ -171,13 +171,13 @@ public: * @brief 获取视口变换矩阵 * @return 视口变换矩阵(从逻辑坐标到屏幕坐标) */ - glm::mat4 getViewportMatrix() const; + glm::mat4 getMatrix() const; /** * @brief 获取反向视口变换矩阵 * @return 反向视口变换矩阵(从屏幕坐标到逻辑坐标) */ - glm::mat4 getInverseViewportMatrix() const; + glm::mat4 getInvMatrix() const; // ------------------------------------------------------------------------ // 区域检测 diff --git a/Extra2D/include/extra2d/graphics/vram_manager.h b/Extra2D/include/extra2d/graphics/vram_manager.h index 1375413..9f5d74b 100644 --- a/Extra2D/include/extra2d/graphics/vram_manager.h +++ b/Extra2D/include/extra2d/graphics/vram_manager.h @@ -9,9 +9,9 @@ namespace extra2d { // ============================================================================ // VRAM 管理器 - 跟踪显存使用情况 // ============================================================================ -class VRAMManager { +class VRAMMgr { public: - static VRAMManager& getInstance(); + static VRAMMgr& get(); // 纹理显存跟踪 void allocTexture(size_t size); @@ -39,10 +39,10 @@ public: void reset(); private: - VRAMManager(); - ~VRAMManager() = default; - VRAMManager(const VRAMManager&) = delete; - VRAMManager& operator=(const VRAMManager&) = delete; + VRAMMgr(); + ~VRAMMgr() = default; + VRAMMgr(const VRAMMgr&) = delete; + VRAMMgr& operator=(const VRAMMgr&) = delete; mutable std::mutex mutex_; diff --git a/Extra2D/include/extra2d/platform/input.h b/Extra2D/include/extra2d/platform/input.h index b0d8b8b..d3c4a9b 100644 --- a/Extra2D/include/extra2d/platform/input.h +++ b/Extra2D/include/extra2d/platform/input.h @@ -96,13 +96,13 @@ public: * @brief 获取逻辑坐标下的鼠标位置 * @return 逻辑坐标 */ - Vec2 getMousePositionLogic() const; + Vec2 getMousePosLogic() const; /** * @brief 获取逻辑坐标下的触摸位置 * @return 逻辑坐标 */ - Vec2 getTouchPositionLogic() const; + Vec2 getTouchPosLogic() const; /** * @brief 获取逻辑坐标下的鼠标增量 diff --git a/Extra2D/include/extra2d/platform/window.h b/Extra2D/include/extra2d/platform/window.h index e6be53f..4824235 100644 --- a/Extra2D/include/extra2d/platform/window.h +++ b/Extra2D/include/extra2d/platform/window.h @@ -66,7 +66,7 @@ public: // 窗口属性 void setTitle(const std::string &title); void setSize(int width, int height); - void setPosition(int x, int y); + void setPos(int x, int y); void setFullscreen(bool fullscreen); void setVSync(bool enabled); void setResizable(bool resizable); diff --git a/Extra2D/include/extra2d/scene/node.h b/Extra2D/include/extra2d/scene/node.h index 7ae8827..8a2cf86 100644 --- a/Extra2D/include/extra2d/scene/node.h +++ b/Extra2D/include/extra2d/scene/node.h @@ -37,19 +37,19 @@ public: void removeChild(Ptr child); void removeChildByName(const std::string &name); - void removeFromParent(); - void removeAllChildren(); + void detach(); + void clearChildren(); 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; + Ptr findChild(const std::string &name) const; + Ptr findChildByTag(int tag) const; // ------------------------------------------------------------------------ // 变换属性 // ------------------------------------------------------------------------ - void setPosition(const Vec2 &pos); - void setPosition(float x, float y); + void setPos(const Vec2 &pos); + void setPos(float x, float y); Vec2 getPosition() const { return position_; } void setRotation(float degrees); @@ -99,8 +99,8 @@ public: // ------------------------------------------------------------------------ // 世界变换 // ------------------------------------------------------------------------ - Vec2 convertToWorldSpace(const Vec2 &localPos) const; - Vec2 convertToNodeSpace(const Vec2 &worldPos) const; + Vec2 toWorld(const Vec2 &localPos) const; + Vec2 toLocal(const Vec2 &worldPos) const; glm::mat4 getLocalTransform() const; glm::mat4 getWorldTransform() const; @@ -114,7 +114,7 @@ public: * @brief 批量更新变换矩阵 * 在渲染前统一计算所有脏节点的变换矩阵,避免逐节点计算时的重复递归 */ - void batchUpdateTransforms(); + void batchTransforms(); /** * @brief 获取变换脏标记状态 @@ -144,7 +144,7 @@ public: // ------------------------------------------------------------------------ // 边界框 // ------------------------------------------------------------------------ - virtual Rect getBoundingBox() const; + virtual Rect getBounds() const; // ------------------------------------------------------------------------ // 事件系统 diff --git a/Extra2D/include/extra2d/scene/scene_manager.h b/Extra2D/include/extra2d/scene/scene_manager.h index 506badc..1f3f14a 100644 --- a/Extra2D/include/extra2d/scene/scene_manager.h +++ b/Extra2D/include/extra2d/scene/scene_manager.h @@ -20,7 +20,7 @@ class SceneManager { public: using TransitionCallback = std::function; - static SceneManager &getInstance(); + static SceneManager &get(); void runWithScene(Ptr scene); void replaceScene(Ptr scene); diff --git a/Extra2D/include/extra2d/scene/shape_node.h b/Extra2D/include/extra2d/scene/shape_node.h index 64550e6..e0af481 100644 --- a/Extra2D/include/extra2d/scene/shape_node.h +++ b/Extra2D/include/extra2d/scene/shape_node.h @@ -85,7 +85,7 @@ public: void addPoint(const Vec2 &point); void clearPoints(); - Rect getBoundingBox() const override; + Rect getBounds() const override; protected: void onDraw(RenderBackend &renderer) override; diff --git a/Extra2D/include/extra2d/scene/sprite.h b/Extra2D/include/extra2d/scene/sprite.h index 0968ec4..185ac29 100644 --- a/Extra2D/include/extra2d/scene/sprite.h +++ b/Extra2D/include/extra2d/scene/sprite.h @@ -37,7 +37,7 @@ public: static Ptr create(Ptr texture); static Ptr create(Ptr texture, const Rect &rect); - Rect getBoundingBox() const override; + Rect getBounds() const override; protected: void onDraw(RenderBackend &renderer) override; diff --git a/Extra2D/include/extra2d/utils/random.h b/Extra2D/include/extra2d/utils/random.h index 3909059..55b76e8 100644 --- a/Extra2D/include/extra2d/utils/random.h +++ b/Extra2D/include/extra2d/utils/random.h @@ -11,7 +11,7 @@ namespace extra2d { class Random { public: /// 获取单例实例 - static Random &getInstance(); + static Random &get(); /// 设置随机种子 void setSeed(uint32 seed); @@ -59,27 +59,27 @@ private: // ============================================================================ /// 获取 [0, 1) 范围内的随机浮点数 -inline float randomFloat() { return Random::getInstance().getFloat(); } +inline float randomFloat() { return Random::get().getFloat(); } /// 获取 [min, max] 范围内的随机浮点数 inline float randomFloat(float min, float max) { - return Random::getInstance().getFloat(min, max); + return Random::get().getFloat(min, max); } /// 获取 [0, max] 范围内的随机整数 -inline int randomInt(int max) { return Random::getInstance().getInt(max); } +inline int randomInt(int max) { return Random::get().getInt(max); } /// 获取 [min, max] 范围内的随机整数 inline int randomInt(int min, int max) { - return Random::getInstance().getInt(min, max); + return Random::get().getInt(min, max); } /// 获取随机布尔值 -inline bool randomBool() { return Random::getInstance().getBool(); } +inline bool randomBool() { return Random::get().getBool(); } /// 获取随机布尔值(带概率) inline bool randomBool(float probability) { - return Random::getInstance().getBool(probability); + return Random::get().getBool(probability); } } // namespace extra2d diff --git a/Extra2D/src/app/application.cpp b/Extra2D/src/app/application.cpp index 244d74c..6376eee 100644 --- a/Extra2D/src/app/application.cpp +++ b/Extra2D/src/app/application.cpp @@ -22,6 +22,10 @@ namespace extra2d { /** * @brief 获取当前时间(秒) + * @return 从某个固定时间点开始的秒数 + * + * 使用高精度时钟获取当前时间,在Switch平台使用clock_gettime, + * 其他平台使用std::chrono::steady_clock */ static double getTimeSeconds() { #ifdef __SWITCH__ @@ -37,13 +41,27 @@ static double getTimeSeconds() { #endif } -Application &Application::instance() { +/** + * @brief 获取Application单例实例 + * @return Application单例的引用 + */ +Application &Application::get() { static Application instance; return instance; } +/** + * @brief 析构函数,自动关闭应用程序 + */ Application::~Application() { shutdown(); } +/** + * @brief 初始化应用程序 + * @param config 应用程序配置 + * @return 初始化成功返回true,失败返回false + * + * 初始化窗口、渲染器、场景管理器、定时器管理器、事件系统、相机和视口适配器等核心组件 + */ bool Application::init(const AppConfig &config) { if (initialized_) { E2D_LOG_WARN("Application already initialized"); @@ -156,13 +174,18 @@ bool Application::init(const AppConfig &config) { return true; } +/** + * @brief 关闭应用程序 + * + * 释放所有资源,包括场景管理器、渲染器、窗口等,并关闭平台相关服务 + */ void Application::shutdown() { if (!initialized_) return; E2D_LOG_INFO("Shutting down application..."); - VRAMManager::getInstance().printStats(); + VRAMMgr::get().printStats(); if (sceneManager_) { sceneManager_->end(); @@ -207,6 +230,11 @@ void Application::shutdown() { E2D_LOG_INFO("Application shutdown complete"); } +/** + * @brief 运行应用程序主循环 + * + * 进入应用程序主循环,持续处理事件、更新和渲染直到应用程序退出 + */ void Application::run() { if (!initialized_) { E2D_LOG_ERROR("Application not initialized"); @@ -226,11 +254,21 @@ void Application::run() { #endif } +/** + * @brief 请求退出应用程序 + * + * 设置退出标志,主循环将在下一次迭代时退出 + */ void Application::quit() { shouldQuit_ = true; running_ = false; } +/** + * @brief 暂停应用程序 + * + * 暂停应用程序更新,渲染继续进行 + */ void Application::pause() { if (!paused_) { paused_ = true; @@ -238,6 +276,11 @@ void Application::pause() { } } +/** + * @brief 恢复应用程序 + * + * 恢复应用程序更新,重置帧时间以避免大的deltaTime跳跃 + */ void Application::resume() { if (paused_) { paused_ = false; @@ -246,6 +289,11 @@ void Application::resume() { } } +/** + * @brief 主循环迭代 + * + * 执行一次主循环迭代,包括计算帧时间、处理事件、更新和渲染 + */ void Application::mainLoop() { double currentTime = getTimeSeconds(); deltaTime_ = static_cast(currentTime - lastFrameTime_); @@ -284,6 +332,11 @@ void Application::mainLoop() { } } +/** + * @brief 更新应用程序状态 + * + * 更新定时器管理器和场景管理器 + */ void Application::update() { if (timerManager_) { timerManager_->update(deltaTime_); @@ -294,6 +347,11 @@ void Application::update() { } } +/** + * @brief 渲染应用程序画面 + * + * 设置视口并渲染当前场景 + */ void Application::render() { if (!renderer_) { E2D_LOG_ERROR("Render failed: renderer is null"); @@ -318,20 +376,54 @@ void Application::render() { window_->swapBuffers(); } +/** + * @brief 获取输入管理器 + * @return 输入管理器的引用 + */ Input &Application::input() { return *window_->getInput(); } +/** + * @brief 获取场景管理器 + * @return 场景管理器的引用 + */ SceneManager &Application::scenes() { return *sceneManager_; } +/** + * @brief 获取定时器管理器 + * @return 定时器管理器的引用 + */ TimerManager &Application::timers() { return *timerManager_; } +/** + * @brief 获取事件队列 + * @return 事件队列的引用 + */ EventQueue &Application::eventQueue() { return *eventQueue_; } +/** + * @brief 获取事件分发器 + * @return 事件分发器的引用 + */ EventDispatcher &Application::eventDispatcher() { return *eventDispatcher_; } +/** + * @brief 获取相机 + * @return 相机的引用 + */ Camera &Application::camera() { return *camera_; } +/** + * @brief 获取视口适配器 + * @return 视口适配器的引用 + */ ViewportAdapter &Application::viewportAdapter() { return *viewportAdapter_; } +/** + * @brief 进入指定场景 + * @param scene 要进入的场景 + * + * 设置场景的视口大小并将其设置为当前场景 + */ void Application::enterScene(Ptr scene) { if (sceneManager_ && scene) { scene->setViewportSize(static_cast(window_->getWidth()), diff --git a/Extra2D/src/event/event.cpp b/Extra2D/src/event/event.cpp index b4b85dc..3e01ed9 100644 --- a/Extra2D/src/event/event.cpp +++ b/Extra2D/src/event/event.cpp @@ -2,6 +2,15 @@ namespace extra2d { +/** + * @brief 创建窗口大小改变事件 + * + * 创建一个表示窗口尺寸变化的Event对象 + * + * @param width 新的窗口宽度(像素) + * @param height 新的窗口高度(像素) + * @return 包含窗口大小改变信息的Event对象 + */ Event Event::createWindowResize(int width, int height) { Event event; event.type = EventType::WindowResize; @@ -9,12 +18,29 @@ Event Event::createWindowResize(int width, int height) { return event; } +/** + * @brief 创建窗口关闭事件 + * + * 创建一个表示窗口请求关闭的Event对象 + * + * @return 表示窗口关闭请求的Event对象 + */ Event Event::createWindowClose() { Event event; event.type = EventType::WindowClose; return event; } +/** + * @brief 创建键盘按键按下事件 + * + * 创建一个表示键盘按键被按下的Event对象 + * + * @param keyCode 按键码 + * @param scancode 扫描码 + * @param mods 修饰键状态(如Shift、Ctrl等) + * @return 包含按键按下信息的Event对象 + */ Event Event::createKeyPress(int keyCode, int scancode, int mods) { Event event; event.type = EventType::KeyPressed; @@ -22,6 +48,16 @@ Event Event::createKeyPress(int keyCode, int scancode, int mods) { return event; } +/** + * @brief 创建键盘按键释放事件 + * + * 创建一个表示键盘按键被释放的Event对象 + * + * @param keyCode 按键码 + * @param scancode 扫描码 + * @param mods 修饰键状态(如Shift、Ctrl等) + * @return 包含按键释放信息的Event对象 + */ Event Event::createKeyRelease(int keyCode, int scancode, int mods) { Event event; event.type = EventType::KeyReleased; @@ -29,6 +65,16 @@ Event Event::createKeyRelease(int keyCode, int scancode, int mods) { return event; } +/** + * @brief 创建鼠标按钮按下事件 + * + * 创建一个表示鼠标按钮被按下的Event对象 + * + * @param button 鼠标按钮编号 + * @param mods 修饰键状态 + * @param pos 鼠标按下时的位置坐标 + * @return 包含鼠标按钮按下信息的Event对象 + */ Event Event::createMouseButtonPress(int button, int mods, const Vec2 &pos) { Event event; event.type = EventType::MouseButtonPressed; @@ -36,6 +82,16 @@ Event Event::createMouseButtonPress(int button, int mods, const Vec2 &pos) { return event; } +/** + * @brief 创建鼠标按钮释放事件 + * + * 创建一个表示鼠标按钮被释放的Event对象 + * + * @param button 鼠标按钮编号 + * @param mods 修饰键状态 + * @param pos 鼠标释放时的位置坐标 + * @return 包含鼠标按钮释放信息的Event对象 + */ Event Event::createMouseButtonRelease(int button, int mods, const Vec2 &pos) { Event event; event.type = EventType::MouseButtonReleased; @@ -43,6 +99,15 @@ Event Event::createMouseButtonRelease(int button, int mods, const Vec2 &pos) { return event; } +/** + * @brief 创建鼠标移动事件 + * + * 创建一个表示鼠标移动的Event对象 + * + * @param pos 鼠标当前位置坐标 + * @param delta 鼠标移动的位移量 + * @return 包含鼠标移动信息的Event对象 + */ Event Event::createMouseMove(const Vec2 &pos, const Vec2 &delta) { Event event; event.type = EventType::MouseMoved; @@ -50,6 +115,15 @@ Event Event::createMouseMove(const Vec2 &pos, const Vec2 &delta) { return event; } +/** + * @brief 创建鼠标滚轮滚动事件 + * + * 创建一个表示鼠标滚轮滚动的Event对象 + * + * @param offset 滚轮滚动的偏移量 + * @param pos 滚动时鼠标的位置坐标 + * @return 包含鼠标滚轮滚动信息的Event对象 + */ Event Event::createMouseScroll(const Vec2 &offset, const Vec2 &pos) { Event event; event.type = EventType::MouseScrolled; diff --git a/Extra2D/src/event/event_dispatcher.cpp b/Extra2D/src/event/event_dispatcher.cpp index 8e69221..1119f7b 100644 --- a/Extra2D/src/event/event_dispatcher.cpp +++ b/Extra2D/src/event/event_dispatcher.cpp @@ -3,8 +3,22 @@ namespace extra2d { +/** + * @brief 默认构造函数 + * + * 初始化事件分发器,设置下一个监听器ID为1 + */ EventDispatcher::EventDispatcher() : nextId_(1) {} +/** + * @brief 添加事件监听器 + * + * 为指定的事件类型注册一个回调函数,返回监听器ID用于后续移除 + * + * @param type 要监听的事件类型 + * @param callback 事件触发时调用的回调函数 + * @return 新注册监听器的唯一ID + */ ListenerId EventDispatcher::addListener(EventType type, EventCallback callback) { ListenerId id = nextId_++; @@ -12,6 +26,13 @@ ListenerId EventDispatcher::addListener(EventType type, return id; } +/** + * @brief 移除指定的事件监听器 + * + * 根据监听器ID移除对应的事件监听器 + * + * @param id 要移除的监听器ID + */ void EventDispatcher::removeListener(ListenerId id) { for (auto &[type, listeners] : listeners_) { auto it = std::remove_if(listeners.begin(), listeners.end(), @@ -23,12 +44,31 @@ void EventDispatcher::removeListener(ListenerId id) { } } +/** + * @brief 移除指定类型的所有监听器 + * + * 移除某个事件类型下的所有已注册监听器 + * + * @param type 要移除监听器的事件类型 + */ void EventDispatcher::removeAllListeners(EventType type) { listeners_.erase(type); } +/** + * @brief 移除所有监听器 + * + * 清除事件分发器中所有已注册的监听器 + */ void EventDispatcher::removeAllListeners() { listeners_.clear(); } +/** + * @brief 分发事件 + * + * 将事件分发给对应类型的所有监听器,直到事件被标记为已处理或所有监听器执行完毕 + * + * @param event 要分发的事件对象(可修改) + */ void EventDispatcher::dispatch(Event &event) { auto it = listeners_.find(event.type); if (it != listeners_.end()) { @@ -40,11 +80,25 @@ void EventDispatcher::dispatch(Event &event) { } } +/** + * @brief 分发事件(常量版本) + * + * 创建事件的副本并分发,适用于常量事件对象 + * + * @param event 要分发的常量事件对象 + */ void EventDispatcher::dispatch(const Event &event) { Event mutableEvent = event; dispatch(mutableEvent); } +/** + * @brief 处理事件队列 + * + * 从事件队列中依次取出所有事件并分发 + * + * @param queue 要处理的事件队列 + */ void EventDispatcher::processQueue(EventQueue &queue) { Event event; while (queue.poll(event)) { @@ -52,11 +106,26 @@ void EventDispatcher::processQueue(EventQueue &queue) { } } +/** + * @brief 获取指定类型监听器的数量 + * + * 返回某个事件类型下已注册的监听器数量 + * + * @param type 要查询的事件类型 + * @return 该类型下的监听器数量 + */ size_t EventDispatcher::getListenerCount(EventType type) const { auto it = listeners_.find(type); return (it != listeners_.end()) ? it->second.size() : 0; } +/** + * @brief 获取所有监听器的总数量 + * + * 返回所有事件类型的监听器总数 + * + * @return 所有监听器的总数量 + */ size_t EventDispatcher::getTotalListenerCount() const { size_t count = 0; for (const auto &[type, listeners] : listeners_) { diff --git a/Extra2D/src/event/event_queue.cpp b/Extra2D/src/event/event_queue.cpp index 538254a..909481e 100644 --- a/Extra2D/src/event/event_queue.cpp +++ b/Extra2D/src/event/event_queue.cpp @@ -2,18 +2,45 @@ namespace extra2d { +/** + * @brief 默认构造函数 + * + * 构造一个空的事件队列对象 + */ EventQueue::EventQueue() = default; +/** + * @brief 将事件压入队列(左值引用版本) + * + * 将事件以拷贝方式添加到队列末尾,线程安全 + * + * @param event 要添加的事件对象 + */ void EventQueue::push(const Event &event) { std::lock_guard lock(mutex_); queue_.push(event); } +/** + * @brief 将事件压入队列(右值引用版本) + * + * 将事件以移动方式添加到队列末尾,线程安全 + * + * @param event 要添加的事件对象(右值引用) + */ void EventQueue::push(Event &&event) { std::lock_guard lock(mutex_); queue_.push(std::move(event)); } +/** + * @brief 从队列中取出事件 + * + * 从队列头部取出一个事件,如果队列不为空则移除该事件,线程安全 + * + * @param event 输出参数,用于存储取出的事件 + * @return 如果成功取出事件返回true,队列为空返回false + */ bool EventQueue::poll(Event &event) { std::lock_guard lock(mutex_); if (queue_.empty()) { @@ -24,6 +51,14 @@ bool EventQueue::poll(Event &event) { return true; } +/** + * @brief 查看队列头部事件 + * + * 获取队列头部的事件但不移除,线程安全 + * + * @param event 输出参数,用于存储查看到的事件 + * @return 如果队列不为空返回true,队列为空返回false + */ bool EventQueue::peek(Event &event) const { std::lock_guard lock(mutex_); if (queue_.empty()) { @@ -33,6 +68,11 @@ bool EventQueue::peek(Event &event) const { return true; } +/** + * @brief 清空队列 + * + * 移除队列中的所有事件,线程安全 + */ void EventQueue::clear() { std::lock_guard lock(mutex_); while (!queue_.empty()) { @@ -40,11 +80,25 @@ void EventQueue::clear() { } } +/** + * @brief 检查队列是否为空 + * + * 线程安全地检查队列中是否有事件 + * + * @return 如果队列为空返回true,否则返回false + */ bool EventQueue::empty() const { std::lock_guard lock(mutex_); return queue_.empty(); } +/** + * @brief 获取队列中的事件数量 + * + * 线程安全地获取队列中当前存储的事件数量 + * + * @return 队列中的事件数量 + */ size_t EventQueue::size() const { std::lock_guard lock(mutex_); return queue_.size(); diff --git a/Extra2D/src/graphics/alpha_mask.cpp b/Extra2D/src/graphics/alpha_mask.cpp index 1a6fde9..2791653 100644 --- a/Extra2D/src/graphics/alpha_mask.cpp +++ b/Extra2D/src/graphics/alpha_mask.cpp @@ -2,9 +2,29 @@ namespace extra2d { +/** + * @brief 构造函数 + * + * 创建指定尺寸的Alpha遮罩,初始时所有像素均为不透明(值为255) + * + * @param width 遮罩宽度(像素) + * @param height 遮罩高度(像素) + */ AlphaMask::AlphaMask(int width, int height) : width_(width), height_(height), data_(width * height, 255) {} +/** + * @brief 从像素数据创建Alpha遮罩 + * + * 根据输入的像素数据提取Alpha通道创建遮罩, + * 支持RGBA(4通道)、RGB(3通道)和灰度(1通道)格式 + * + * @param pixels 像素数据指针 + * @param width 图像宽度 + * @param height 图像高度 + * @param channels 通道数量(1、3或4) + * @return 创建的Alpha遮罩对象 + */ AlphaMask AlphaMask::createFromPixels(const uint8_t *pixels, int width, int height, int channels) { AlphaMask mask(width, height); @@ -37,6 +57,15 @@ AlphaMask AlphaMask::createFromPixels(const uint8_t *pixels, int width, return mask; } +/** + * @brief 获取指定位置的Alpha值 + * + * 返回指定坐标处的Alpha值,如果坐标无效则返回0 + * + * @param x X坐标 + * @param y Y坐标 + * @return Alpha值(0-255),坐标无效时返回0 + */ uint8_t AlphaMask::getAlpha(int x, int y) const { if (!isValid(x, y)) { return 0; @@ -44,10 +73,29 @@ uint8_t AlphaMask::getAlpha(int x, int y) const { return data_[y * width_ + x]; } +/** + * @brief 检查指定位置是否不透明 + * + * 判断指定坐标处的Alpha值是否大于等于给定的阈值 + * + * @param x X坐标 + * @param y Y坐标 + * @param threshold 不透明度阈值(默认为255,即完全不透明) + * @return 如果Alpha值大于等于阈值返回true,否则返回false + */ bool AlphaMask::isOpaque(int x, int y, uint8_t threshold) const { return getAlpha(x, y) >= threshold; } +/** + * @brief 检查坐标是否有效 + * + * 判断给定的坐标是否在遮罩的有效范围内 + * + * @param x X坐标 + * @param y Y坐标 + * @return 如果坐标在有效范围内返回true,否则返回false + */ bool AlphaMask::isValid(int x, int y) const { return x >= 0 && x < width_ && y >= 0 && y < height_; } diff --git a/Extra2D/src/graphics/camera.cpp b/Extra2D/src/graphics/camera.cpp index f8d62d9..81a0383 100644 --- a/Extra2D/src/graphics/camera.cpp +++ b/Extra2D/src/graphics/camera.cpp @@ -1,42 +1,97 @@ #include #include #include -#include #include +#include + namespace extra2d { +/** + * @brief 默认构造函数 + * + * 创建一个默认的正交相机,视口范围为 (-1, -1) 到 (1, 1) + */ Camera::Camera() : left_(-1.0f), right_(1.0f), bottom_(-1.0f), top_(1.0f) {} +/** + * @brief 构造函数 + * @param left 视口左边界 + * @param right 视口右边界 + * @param bottom 视口底边界 + * @param top 视口顶边界 + * + * 创建一个指定视口范围的正交相机 + */ Camera::Camera(float left, float right, float bottom, float top) : left_(left), right_(right), bottom_(bottom), top_(top) {} +/** + * @brief 构造函数 + * @param viewport 视口尺寸 + * + * 根据视口尺寸创建相机,视口原点在左上角 + */ Camera::Camera(const Size &viewport) : left_(0.0f), right_(viewport.width), bottom_(viewport.height), top_(0.0f) {} -void Camera::setPosition(const Vec2 &position) { +/** + * @brief 设置相机位置 + * @param position 新的位置坐标 + * + * 设置相机在世界空间中的位置,会标记视图矩阵为脏 + */ +void Camera::setPos(const Vec2 &position) { position_ = position; viewDirty_ = true; } -void Camera::setPosition(float x, float y) { +/** + * @brief 设置相机位置 + * @param x X坐标 + * @param y Y坐标 + * + * 设置相机在世界空间中的位置,会标记视图矩阵为脏 + */ +void Camera::setPos(float x, float y) { position_.x = x; position_.y = y; viewDirty_ = true; } +/** + * @brief 设置相机旋转角度 + * @param degrees 旋转角度(度数) + * + * 设置相机的旋转角度,会标记视图矩阵为脏 + */ void Camera::setRotation(float degrees) { rotation_ = degrees; viewDirty_ = true; } +/** + * @brief 设置相机缩放级别 + * @param zoom 缩放值(1.0为正常大小) + * + * 设置相机的缩放级别,会同时标记视图矩阵和投影矩阵为脏 + */ void Camera::setZoom(float zoom) { zoom_ = zoom; viewDirty_ = true; projDirty_ = true; } +/** + * @brief 设置视口范围 + * @param left 左边界 + * @param right 右边界 + * @param bottom 底边界 + * @param top 顶边界 + * + * 设置相机的正交投影视口范围,会标记投影矩阵为脏 + */ void Camera::setViewport(float left, float right, float bottom, float top) { left_ = left; right_ = right; @@ -45,6 +100,12 @@ void Camera::setViewport(float left, float right, float bottom, float top) { projDirty_ = true; } +/** + * @brief 设置视口范围 + * @param rect 视口矩形 + * + * 使用矩形设置相机的正交投影视口范围,会标记投影矩阵为脏 + */ void Camera::setViewport(const Rect &rect) { left_ = rect.left(); right_ = rect.right(); @@ -53,6 +114,12 @@ void Camera::setViewport(const Rect &rect) { projDirty_ = true; } +/** + * @brief 获取视口矩形 + * @return 当前视口的矩形表示 + * + * 返回当前相机的视口范围 + */ Rect Camera::getViewport() const { return Rect(left_, top_, right_ - left_, bottom_ - top_); } @@ -60,36 +127,42 @@ Rect Camera::getViewport() const { /** * @brief 获取视图矩阵 * @return 视图矩阵 - * + * * 变换顺序:平移 -> 旋转 -> 缩放(逆序应用) * View = T(-position) × R(-rotation) × S(1/zoom) */ glm::mat4 Camera::getViewMatrix() const { if (viewDirty_) { viewMatrix_ = glm::mat4(1.0f); - + // 1. 平移(最后应用) - viewMatrix_ = glm::translate(viewMatrix_, + viewMatrix_ = glm::translate(viewMatrix_, glm::vec3(-position_.x, -position_.y, 0.0f)); - + // 2. 旋转(中间应用) if (rotation_ != 0.0f) { - viewMatrix_ = glm::rotate(viewMatrix_, - -rotation_ * DEG_TO_RAD, + viewMatrix_ = glm::rotate(viewMatrix_, -rotation_ * DEG_TO_RAD, glm::vec3(0.0f, 0.0f, 1.0f)); } - + // 3. 缩放(最先应用) if (zoom_ != 1.0f) { - viewMatrix_ = glm::scale(viewMatrix_, - glm::vec3(1.0f / zoom_, 1.0f / zoom_, 1.0f)); + viewMatrix_ = + glm::scale(viewMatrix_, glm::vec3(1.0f / zoom_, 1.0f / zoom_, 1.0f)); } - + viewDirty_ = false; } return viewMatrix_; } +/** + * @brief 获取投影矩阵 + * @return 正交投影矩阵 + * + * 对于2D游戏,Y轴向下增长(屏幕坐标系) + * OpenGL默认Y轴向上,所以需要反转Y轴 + */ glm::mat4 Camera::getProjectionMatrix() const { if (projDirty_) { // 对于2D游戏,Y轴向下增长(屏幕坐标系) @@ -120,12 +193,12 @@ glm::mat4 Camera::getViewProjectionMatrix() const { */ Vec2 Camera::screenToWorld(const Vec2 &screenPos) const { Vec2 logicPos = screenPos; - + // 如果有视口适配器,先转换到逻辑坐标 if (viewportAdapter_) { logicPos = viewportAdapter_->screenToLogic(screenPos); } - + // 使用逆视图-投影矩阵转换 glm::mat4 invVP = glm::inverse(getViewProjectionMatrix()); glm::vec4 ndc(logicPos.x, logicPos.y, 0.0f, 1.0f); @@ -142,7 +215,7 @@ Vec2 Camera::worldToScreen(const Vec2 &worldPos) const { glm::vec4 world(worldPos.x, worldPos.y, 0.0f, 1.0f); glm::vec4 screen = getViewProjectionMatrix() * world; Vec2 logicPos(screen.x, screen.y); - + // 如果有视口适配器,转换到屏幕坐标 if (viewportAdapter_) { return viewportAdapter_->logicToScreen(logicPos); @@ -150,32 +223,73 @@ Vec2 Camera::worldToScreen(const Vec2 &worldPos) const { return logicPos; } +/** + * @brief 将屏幕坐标转换为世界坐标 + * @param x 屏幕X坐标 + * @param y 屏幕Y坐标 + * @return 世界坐标 + */ Vec2 Camera::screenToWorld(float x, float y) const { return screenToWorld(Vec2(x, y)); } +/** + * @brief 将世界坐标转换为屏幕坐标 + * @param x 世界X坐标 + * @param y 世界Y坐标 + * @return 屏幕坐标 + */ Vec2 Camera::worldToScreen(float x, float y) const { return worldToScreen(Vec2(x, y)); } +/** + * @brief 移动相机位置 + * @param offset 位置偏移量 + * + * 按指定偏移量移动相机位置,会标记视图矩阵为脏 + */ void Camera::move(const Vec2 &offset) { position_ += offset; viewDirty_ = true; } +/** + * @brief 移动相机位置 + * @param x X方向偏移量 + * @param y Y方向偏移量 + * + * 按指定偏移量移动相机位置,会标记视图矩阵为脏 + */ void Camera::move(float x, float y) { position_.x += x; position_.y += y; viewDirty_ = true; } +/** + * @brief 设置相机边界限制 + * @param bounds 边界矩形 + * + * 设置相机的移动边界,相机位置将被限制在此边界内 + */ void Camera::setBounds(const Rect &bounds) { bounds_ = bounds; hasBounds_ = true; } +/** + * @brief 清除相机边界限制 + * + * 移除相机的移动边界限制 + */ void Camera::clearBounds() { hasBounds_ = false; } +/** + * @brief 将相机位置限制在边界内 + * + * 如果设置了边界,将相机位置限制在边界矩形内 + */ void Camera::clampToBounds() { if (!hasBounds_) return; @@ -203,6 +317,12 @@ void Camera::clampToBounds() { viewDirty_ = true; } +/** + * @brief 将相机移动到目标位置 + * @param target 目标位置 + * + * 设置相机位置到指定的世界坐标 + */ void Camera::lookAt(const Vec2 &target) { position_ = target; viewDirty_ = true; @@ -212,16 +332,18 @@ void Camera::lookAt(const Vec2 &target) { * @brief 设置视口适配器 * @param adapter 视口适配器指针 */ -void Camera::setViewportAdapter(ViewportAdapter* adapter) { +void Camera::setViewportAdapter(ViewportAdapter *adapter) { viewportAdapter_ = adapter; } /** * @brief 根据视口适配器自动设置视口 + * + * 如果设置了视口适配器,根据其配置自动设置相机的视口范围 */ void Camera::applyViewportAdapter() { if (viewportAdapter_) { - const auto& config = viewportAdapter_->getConfig(); + const auto &config = viewportAdapter_->getConfig(); setViewport(0.0f, config.logicWidth, config.logicHeight, 0.0f); } } diff --git a/Extra2D/src/graphics/gpu_context.cpp b/Extra2D/src/graphics/gpu_context.cpp index 959dbfd..7d0a934 100644 --- a/Extra2D/src/graphics/gpu_context.cpp +++ b/Extra2D/src/graphics/gpu_context.cpp @@ -2,19 +2,41 @@ namespace extra2d { -GPUContext& GPUContext::getInstance() { +/** + * @brief 获取GPUContext单例实例 + * @return GPUContext单例的引用 + * + * 使用静态局部变量实现线程安全的单例模式 + */ +GPUContext& GPUContext::get() { static GPUContext instance; return instance; } +/** + * @brief 标记GPU上下文为有效状态 + * + * 使用原子操作设置有效标志为true,使用release内存序 + */ void GPUContext::markValid() { valid_.store(true, std::memory_order_release); } +/** + * @brief 标记GPU上下文为无效状态 + * + * 使用原子操作设置有效标志为false,使用release内存序 + */ void GPUContext::markInvalid() { valid_.store(false, std::memory_order_release); } +/** + * @brief 检查GPU上下文是否有效 + * @return 如果GPU上下文有效返回true,否则返回false + * + * 使用原子操作读取有效标志,使用acquire内存序 + */ bool GPUContext::isValid() const { return valid_.load(std::memory_order_acquire); } diff --git a/Extra2D/src/graphics/opengl/gl_font_atlas.cpp b/Extra2D/src/graphics/opengl/gl_font_atlas.cpp index 037765c..d279f55 100644 --- a/Extra2D/src/graphics/opengl/gl_font_atlas.cpp +++ b/Extra2D/src/graphics/opengl/gl_font_atlas.cpp @@ -13,6 +13,12 @@ namespace extra2d { // ============================================================================ // 构造函数 - 初始化字体图集 // ============================================================================ +/** + * @brief 构造函数,从字体文件初始化字体图集 + * @param filepath 字体文件路径 + * @param fontSize 字体大小(像素) + * @param useSDF 是否使用有符号距离场渲染 + */ 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) { @@ -53,11 +59,19 @@ GLFontAtlas::GLFontAtlas(const std::string &filepath, int fontSize, bool useSDF) // ============================================================================ // 析构函数 // ============================================================================ +/** + * @brief 析构函数 + */ GLFontAtlas::~GLFontAtlas() = default; // ============================================================================ // 获取字形 - 如果字形不存在则缓存它 // ============================================================================ +/** + * @brief 获取字形信息,如果字形不存在则动态缓存 + * @param codepoint Unicode码点 + * @return 字形信息指针,如果获取失败返回nullptr + */ const Glyph *GLFontAtlas::getGlyph(char32_t codepoint) const { auto it = glyphs_.find(codepoint); if (it == glyphs_.end()) { @@ -70,6 +84,11 @@ const Glyph *GLFontAtlas::getGlyph(char32_t codepoint) const { // ============================================================================ // 测量文本尺寸 // ============================================================================ +/** + * @brief 测量文本渲染后的尺寸 + * @param text 要测量的文本 + * @return 文本的宽度和高度 + */ Vec2 GLFontAtlas::measureText(const std::string &text) { float width = 0.0f; float height = getAscent() - getDescent(); @@ -97,6 +116,9 @@ Vec2 GLFontAtlas::measureText(const std::string &text) { // ============================================================================ // 创建图集纹理 - 初始化空白纹理和矩形打包上下文 // ============================================================================ +/** + * @brief 创建字体图集纹理,初始化空白纹理和矩形打包上下文 + */ void GLFontAtlas::createAtlas() { // 统一使用 4 通道格式 int channels = 4; @@ -121,6 +143,10 @@ void GLFontAtlas::createAtlas() { // 缓存字形 - 渲染字形到图集并存储信息 // 使用 stb_rect_pack 进行矩形打包 // ============================================================================ +/** + * @brief 缓存字形到图集,渲染字形位图并存储字形信息 + * @param codepoint Unicode码点 + */ void GLFontAtlas::cacheGlyph(char32_t codepoint) const { int advance = 0; stbtt_GetCodepointHMetrics(&fontInfo_, static_cast(codepoint), &advance, diff --git a/Extra2D/src/graphics/opengl/gl_renderer.cpp b/Extra2D/src/graphics/opengl/gl_renderer.cpp index c7784fe..aa5e263 100644 --- a/Extra2D/src/graphics/opengl/gl_renderer.cpp +++ b/Extra2D/src/graphics/opengl/gl_renderer.cpp @@ -59,6 +59,9 @@ static constexpr BlendState BLEND_STATES[] = { static constexpr size_t BLEND_STATE_COUNT = sizeof(BLEND_STATES) / sizeof(BLEND_STATES[0]); +/** + * @brief 构造函数,初始化OpenGL渲染器成员变量 + */ GLRenderer::GLRenderer() : window_(nullptr), shapeVao_(0), shapeVbo_(0), lineVao_(0), lineVbo_(0), vsync_(true), shapeVertexCount_(0), currentShapeMode_(GL_TRIANGLES), @@ -72,8 +75,16 @@ GLRenderer::GLRenderer() } } +/** + * @brief 析构函数,调用shutdown释放资源 + */ GLRenderer::~GLRenderer() { shutdown(); } +/** + * @brief 初始化OpenGL渲染器 + * @param window 窗口指针 + * @return 初始化成功返回true,失败返回false + */ bool GLRenderer::init(Window *window) { window_ = window; @@ -93,7 +104,7 @@ bool GLRenderer::init(Window *window) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // 标记 GPU 上下文为有效 - GPUContext::getInstance().markValid(); + GPUContext::get().markValid(); E2D_LOG_INFO("OpenGL Renderer initialized"); E2D_LOG_INFO("OpenGL Version: {}", @@ -102,16 +113,19 @@ bool GLRenderer::init(Window *window) { return true; } +/** + * @brief 关闭渲染器,释放所有GPU资源 + */ void GLRenderer::shutdown() { // 标记 GPU 上下文为无效 // 这会在销毁 OpenGL 上下文之前通知所有 GPU 资源 - GPUContext::getInstance().markInvalid(); + GPUContext::get().markInvalid(); spriteBatch_.shutdown(); if (lineVbo_ != 0) { glDeleteBuffers(1, &lineVbo_); - VRAMManager::getInstance().freeBuffer(MAX_LINE_VERTICES * + VRAMMgr::get().freeBuffer(MAX_LINE_VERTICES * sizeof(ShapeVertex)); lineVbo_ = 0; } @@ -121,7 +135,7 @@ void GLRenderer::shutdown() { } if (shapeVbo_ != 0) { glDeleteBuffers(1, &shapeVbo_); - VRAMManager::getInstance().freeBuffer(MAX_SHAPE_VERTICES * + VRAMMgr::get().freeBuffer(MAX_SHAPE_VERTICES * sizeof(ShapeVertex)); shapeVbo_ = 0; } @@ -131,12 +145,19 @@ void GLRenderer::shutdown() { } } +/** + * @brief 开始新帧,清除颜色缓冲区并重置统计信息 + * @param clearColor 清屏颜色 + */ void GLRenderer::beginFrame(const Color &clearColor) { glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); glClear(GL_COLOR_BUFFER_BIT); resetStats(); } +/** + * @brief 结束当前帧,刷新所有待处理的渲染批次 + */ void GLRenderer::endFrame() { // 刷新所有待处理的形状批次 flushShapeBatch(); @@ -144,16 +165,31 @@ void GLRenderer::endFrame() { flushLineBatch(); } +/** + * @brief 设置视口区域 + * @param x 视口左下角X坐标 + * @param y 视口左下角Y坐标 + * @param width 视口宽度 + * @param height 视口高度 + */ void GLRenderer::setViewport(int x, int y, int width, int height) { glViewport(x, y, width, height); } +/** + * @brief 设置垂直同步 + * @param enabled true启用垂直同步,false禁用 + */ void GLRenderer::setVSync(bool enabled) { vsync_ = enabled; // 使用 SDL2 设置交换间隔 SDL_GL_SetSwapInterval(enabled ? 1 : 0); } +/** + * @brief 设置混合模式 + * @param mode 混合模式枚举值 + */ void GLRenderer::setBlendMode(BlendMode mode) { // 状态缓存检查,避免冗余 GL 调用 if (cachedBlendMode_ == mode) { @@ -182,10 +218,18 @@ void GLRenderer::setBlendMode(BlendMode mode) { } } +/** + * @brief 设置视图投影矩阵 + * @param matrix 4x4视图投影矩阵 + */ void GLRenderer::setViewProjection(const glm::mat4 &matrix) { viewProjection_ = matrix; } +/** + * @brief 压入变换矩阵到变换栈 + * @param transform 变换矩阵 + */ void GLRenderer::pushTransform(const glm::mat4 &transform) { if (transformStack_.empty()) { transformStack_.push_back(transform); @@ -194,12 +238,19 @@ void GLRenderer::pushTransform(const glm::mat4 &transform) { } } +/** + * @brief 从变换栈弹出顶部变换矩阵 + */ void GLRenderer::popTransform() { if (!transformStack_.empty()) { transformStack_.pop_back(); } } +/** + * @brief 获取当前累积的变换矩阵 + * @return 当前变换矩阵,如果栈为空则返回单位矩阵 + */ glm::mat4 GLRenderer::getCurrentTransform() const { if (transformStack_.empty()) { return glm::mat4(1.0f); @@ -207,17 +258,42 @@ glm::mat4 GLRenderer::getCurrentTransform() const { return transformStack_.back(); } +/** + * @brief 创建纹理对象 + * @param width 纹理宽度 + * @param height 纹理高度 + * @param pixels 像素数据指针 + * @param channels 颜色通道数 + * @return 创建的纹理智能指针 + */ Ptr GLRenderer::createTexture(int width, int height, const uint8_t *pixels, int channels) { return makePtr(width, height, pixels, channels); } +/** + * @brief 从文件加载纹理 + * @param filepath 纹理文件路径 + * @return 加载的纹理智能指针 + */ Ptr GLRenderer::loadTexture(const std::string &filepath) { return makePtr(filepath); } +/** + * @brief 开始精灵批处理 + */ void GLRenderer::beginSpriteBatch() { spriteBatch_.begin(viewProjection_); } +/** + * @brief 绘制精灵(带完整参数) + * @param texture 纹理引用 + * @param destRect 目标矩形(屏幕坐标) + * @param srcRect 源矩形(纹理坐标) + * @param tint 着色颜色 + * @param rotation 旋转角度(度) + * @param anchor 锚点位置(0-1范围) + */ void GLRenderer::drawSprite(const Texture &texture, const Rect &destRect, const Rect &srcRect, const Color &tint, float rotation, const Vec2 &anchor) { @@ -246,6 +322,12 @@ void GLRenderer::drawSprite(const Texture &texture, const Rect &destRect, spriteBatch_.draw(texture, data); } +/** + * @brief 绘制精灵(简化版本) + * @param texture 纹理引用 + * @param position 绘制位置 + * @param tint 着色颜色 + */ void GLRenderer::drawSprite(const Texture &texture, const Vec2 &position, const Color &tint) { Rect destRect(position.x, position.y, static_cast(texture.getWidth()), @@ -255,11 +337,21 @@ void GLRenderer::drawSprite(const Texture &texture, const Vec2 &position, drawSprite(texture, destRect, srcRect, tint, 0.0f, Vec2(0, 0)); } +/** + * @brief 结束精灵批处理并提交绘制 + */ void GLRenderer::endSpriteBatch() { spriteBatch_.end(); stats_.drawCalls += spriteBatch_.getDrawCallCount(); } +/** + * @brief 绘制线段 + * @param start 起点坐标 + * @param end 终点坐标 + * @param color 线条颜色 + * @param width 线条宽度 + */ void GLRenderer::drawLine(const Vec2 &start, const Vec2 &end, const Color &color, float width) { // 如果线宽改变,需要先刷新线条批次 @@ -300,6 +392,11 @@ void GLRenderer::drawRect(const Rect &rect, const Color &color, float width) { addLineVertex(x1, y1, color); } +/** + * @brief 填充矩形 + * @param rect 矩形区域 + * @param color 填充颜色 + */ void GLRenderer::fillRect(const Rect &rect, const Color &color) { // 提交当前批次(如果模式不同) submitShapeBatch(GL_TRIANGLES); @@ -321,6 +418,14 @@ void GLRenderer::fillRect(const Rect &rect, const Color &color) { addShapeVertex(x1, y2, color); } +/** + * @brief 绘制圆形边框 + * @param center 圆心坐标 + * @param radius 半径 + * @param color 边框颜色 + * @param segments 分段数 + * @param width 线条宽度 + */ void GLRenderer::drawCircle(const Vec2 ¢er, float radius, const Color &color, int segments, float width) { // 限制段数不超过缓存大小 @@ -348,6 +453,13 @@ void GLRenderer::drawCircle(const Vec2 ¢er, float radius, } } +/** + * @brief 填充圆形 + * @param center 圆心坐标 + * @param radius 半径 + * @param color 填充颜色 + * @param segments 分段数 + */ void GLRenderer::fillCircle(const Vec2 ¢er, float radius, const Color &color, int segments) { // 限制段数不超过缓存大小 @@ -375,6 +487,14 @@ void GLRenderer::fillCircle(const Vec2 ¢er, float radius, } } +/** + * @brief 绘制三角形边框 + * @param p1 第一个顶点 + * @param p2 第二个顶点 + * @param p3 第三个顶点 + * @param color 边框颜色 + * @param width 线条宽度 + */ void GLRenderer::drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3, const Color &color, float width) { drawLine(p1, p2, color, width); @@ -382,6 +502,13 @@ void GLRenderer::drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3, drawLine(p3, p1, color, width); } +/** + * @brief 填充三角形 + * @param p1 第一个顶点 + * @param p2 第二个顶点 + * @param p3 第三个顶点 + * @param color 填充颜色 + */ void GLRenderer::fillTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3, const Color &color) { submitShapeBatch(GL_TRIANGLES); @@ -391,6 +518,12 @@ void GLRenderer::fillTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3, addShapeVertex(p3.x, p3.y, color); } +/** + * @brief 绘制多边形边框 + * @param points 顶点数组 + * @param color 边框颜色 + * @param width 线条宽度 + */ void GLRenderer::drawPolygon(const std::vector &points, const Color &color, float width) { if (points.size() < 2) @@ -411,6 +544,11 @@ void GLRenderer::drawPolygon(const std::vector &points, } } +/** + * @brief 填充多边形 + * @param points 顶点数组 + * @param color 填充颜色 + */ void GLRenderer::fillPolygon(const std::vector &points, const Color &color) { if (points.size() < 3) @@ -427,16 +565,38 @@ void GLRenderer::fillPolygon(const std::vector &points, } } +/** + * @brief 创建字体图集 + * @param filepath 字体文件路径 + * @param fontSize 字体大小 + * @param useSDF 是否使用SDF渲染 + * @return 创建的字体图集智能指针 + */ Ptr GLRenderer::createFontAtlas(const std::string &filepath, int fontSize, bool useSDF) { return makePtr(filepath, fontSize, useSDF); } +/** + * @brief 绘制文本(使用Vec2位置) + * @param font 字体图集引用 + * @param text 文本内容 + * @param position 绘制位置 + * @param color 文本颜色 + */ void GLRenderer::drawText(const FontAtlas &font, const std::string &text, const Vec2 &position, const Color &color) { drawText(font, text, position.x, position.y, color); } +/** + * @brief 绘制文本(使用浮点坐标) + * @param font 字体图集引用 + * @param text 文本内容 + * @param x X坐标 + * @param y Y坐标 + * @param color 文本颜色 + */ void GLRenderer::drawText(const FontAtlas &font, const std::string &text, float x, float y, const Color &color) { float cursorX = x; @@ -488,8 +648,14 @@ void GLRenderer::drawText(const FontAtlas &font, const std::string &text, } } +/** + * @brief 重置渲染统计信息 + */ void GLRenderer::resetStats() { stats_ = Stats{}; } +/** + * @brief 初始化形状渲染所需的OpenGL资源(VAO、VBO、着色器) + */ void GLRenderer::initShapeRendering() { // 编译形状着色器 shapeShader_.compileFromSource(SHAPE_VERTEX_SHADER, SHAPE_FRAGMENT_SHADER); @@ -537,12 +703,18 @@ void GLRenderer::initShapeRendering() { glBindVertexArray(0); // VRAM 跟踪 - VRAMManager::getInstance().allocBuffer(MAX_SHAPE_VERTICES * + VRAMMgr::get().allocBuffer(MAX_SHAPE_VERTICES * sizeof(ShapeVertex)); - VRAMManager::getInstance().allocBuffer(MAX_LINE_VERTICES * + VRAMMgr::get().allocBuffer(MAX_LINE_VERTICES * sizeof(ShapeVertex)); } +/** + * @brief 添加形状顶点到缓存 + * @param x X坐标 + * @param y Y坐标 + * @param color 顶点颜色 + */ void GLRenderer::addShapeVertex(float x, float y, const Color &color) { if (shapeVertexCount_ >= MAX_SHAPE_VERTICES) { flushShapeBatch(); @@ -556,6 +728,12 @@ void GLRenderer::addShapeVertex(float x, float y, const Color &color) { v.a = color.a; } +/** + * @brief 添加线条顶点到缓存 + * @param x X坐标 + * @param y Y坐标 + * @param color 顶点颜色 + */ void GLRenderer::addLineVertex(float x, float y, const Color &color) { if (lineVertexCount_ >= MAX_LINE_VERTICES) { flushLineBatch(); @@ -569,6 +747,10 @@ void GLRenderer::addLineVertex(float x, float y, const Color &color) { v.a = color.a; } +/** + * @brief 提交形状批次(如果需要切换绘制模式) + * @param mode OpenGL绘制模式 + */ void GLRenderer::submitShapeBatch(GLenum mode) { if (shapeVertexCount_ == 0) return; @@ -580,6 +762,9 @@ void GLRenderer::submitShapeBatch(GLenum mode) { currentShapeMode_ = mode; } +/** + * @brief 刷新形状批次,执行实际的OpenGL绘制调用 + */ void GLRenderer::flushShapeBatch() { if (shapeVertexCount_ == 0) return; @@ -600,6 +785,9 @@ void GLRenderer::flushShapeBatch() { shapeVertexCount_ = 0; } +/** + * @brief 刷新线条批次,执行实际的OpenGL绘制调用 + */ void GLRenderer::flushLineBatch() { if (lineVertexCount_ == 0) return; diff --git a/Extra2D/src/graphics/opengl/gl_shader.cpp b/Extra2D/src/graphics/opengl/gl_shader.cpp index c20e777..fa8bb2f 100644 --- a/Extra2D/src/graphics/opengl/gl_shader.cpp +++ b/Extra2D/src/graphics/opengl/gl_shader.cpp @@ -5,14 +5,26 @@ namespace extra2d { +/** + * @brief 构造函数,初始化着色器程序ID为0 + */ GLShader::GLShader() : programID_(0) {} +/** + * @brief 析构函数,删除OpenGL着色器程序 + */ GLShader::~GLShader() { if (programID_ != 0) { glDeleteProgram(programID_); } } +/** + * @brief 从源代码编译着色器程序 + * @param vertexSource 顶点着色器源代码 + * @param fragmentSource 片段着色器源代码 + * @return 编译成功返回true,失败返回false + */ bool GLShader::compileFromSource(const char *vertexSource, const char *fragmentSource) { GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexSource); @@ -46,6 +58,12 @@ bool GLShader::compileFromSource(const char *vertexSource, return success == GL_TRUE; } +/** + * @brief 从文件编译着色器程序 + * @param vertexPath 顶点着色器文件路径 + * @param fragmentPath 片段着色器文件路径 + * @return 编译成功返回true,失败返回false + */ bool GLShader::compileFromFile(const std::string &vertexPath, const std::string &fragmentPath) { std::ifstream vShaderFile(vertexPath); @@ -65,38 +83,85 @@ bool GLShader::compileFromFile(const std::string &vertexPath, fShaderStream.str().c_str()); } +/** + * @brief 绑定(使用)当前着色器程序 + */ void GLShader::bind() const { glUseProgram(programID_); } +/** + * @brief 解绑当前着色器程序 + */ void GLShader::unbind() const { glUseProgram(0); } +/** + * @brief 设置布尔类型uniform变量 + * @param name uniform变量名 + * @param value 布尔值 + */ void GLShader::setBool(const std::string &name, bool value) { glUniform1i(getUniformLocation(name), value ? 1 : 0); } +/** + * @brief 设置整数类型uniform变量 + * @param name uniform变量名 + * @param value 整数值 + */ void GLShader::setInt(const std::string &name, int value) { glUniform1i(getUniformLocation(name), value); } +/** + * @brief 设置浮点类型uniform变量 + * @param name uniform变量名 + * @param value 浮点值 + */ void GLShader::setFloat(const std::string &name, float value) { glUniform1f(getUniformLocation(name), value); } +/** + * @brief 设置二维向量类型uniform变量 + * @param name uniform变量名 + * @param value 二维向量值 + */ void GLShader::setVec2(const std::string &name, const glm::vec2 &value) { glUniform2fv(getUniformLocation(name), 1, &value[0]); } +/** + * @brief 设置三维向量类型uniform变量 + * @param name uniform变量名 + * @param value 三维向量值 + */ void GLShader::setVec3(const std::string &name, const glm::vec3 &value) { glUniform3fv(getUniformLocation(name), 1, &value[0]); } +/** + * @brief 设置四维向量类型uniform变量 + * @param name uniform变量名 + * @param value 四维向量值 + */ void GLShader::setVec4(const std::string &name, const glm::vec4 &value) { glUniform4fv(getUniformLocation(name), 1, &value[0]); } +/** + * @brief 设置4x4矩阵类型uniform变量 + * @param name uniform变量名 + * @param value 4x4矩阵值 + */ void GLShader::setMat4(const std::string &name, const glm::mat4 &value) { glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, &value[0][0]); } +/** + * @brief 编译单个着色器 + * @param type 着色器类型(GL_VERTEX_SHADER或GL_FRAGMENT_SHADER) + * @param source 着色器源代码 + * @return 编译成功返回着色器ID,失败返回0 + */ GLuint GLShader::compileShader(GLenum type, const char *source) { GLuint shader = glCreateShader(type); glShaderSource(shader, 1, &source, nullptr); @@ -115,6 +180,11 @@ GLuint GLShader::compileShader(GLenum type, const char *source) { return shader; } +/** + * @brief 获取uniform变量位置,使用缓存避免重复查询 + * @param name uniform变量名 + * @return uniform位置 + */ GLint GLShader::getUniformLocation(const std::string &name) { auto it = uniformCache_.find(name); if (it != uniformCache_.end()) { diff --git a/Extra2D/src/graphics/opengl/gl_sprite_batch.cpp b/Extra2D/src/graphics/opengl/gl_sprite_batch.cpp index 2969e0e..6020c7f 100644 --- a/Extra2D/src/graphics/opengl/gl_sprite_batch.cpp +++ b/Extra2D/src/graphics/opengl/gl_sprite_batch.cpp @@ -8,16 +8,29 @@ namespace extra2d { // ============================================================================ // 三角函数查表 - 避免每帧重复计算 sin/cos // ============================================================================ +/** + * @brief 三角函数查表类,避免每帧重复计算sin/cos + */ class TrigLookup { public: static constexpr size_t TABLE_SIZE = 360 * 4; // 0.25度精度 static constexpr float INDEX_SCALE = 4.0f; // 每度4个采样点 static constexpr float RAD_TO_INDEX = INDEX_SCALE * 180.0f / 3.14159265359f; + /** + * @brief 查表获取sin值 + * @param radians 弧度值 + * @return sin值 + */ static float sinRad(float radians) { return table_.sinTable[normalizeIndexRad(radians)]; } + /** + * @brief 查表获取cos值 + * @param radians 弧度值 + * @return cos值 + */ static float cosRad(float radians) { return table_.cosTable[normalizeIndexRad(radians)]; } @@ -50,6 +63,10 @@ private: const TrigLookup::Tables TrigLookup::table_; // 静态索引生成函数 +/** + * @brief 获取静态索引数组,用于精灵绘制 + * @return 索引数组的常量引用 + */ static const std::array& getIndices() { static std::array indices = []() { std::array arr{}; @@ -114,13 +131,23 @@ void main() { } )"; +/** + * @brief 构造函数,初始化精灵批处理器成员变量 + */ GLSpriteBatch::GLSpriteBatch() : vao_(0), vbo_(0), ibo_(0), vertexCount_(0), currentTexture_(nullptr), currentIsSDF_(false), drawCallCount_(0), spriteCount_(0), batchCount_(0) { } +/** + * @brief 析构函数,调用shutdown释放资源 + */ GLSpriteBatch::~GLSpriteBatch() { shutdown(); } +/** + * @brief 初始化精灵批处理器,创建VAO、VBO、IBO和编译着色器 + * @return 初始化成功返回true,失败返回false + */ bool GLSpriteBatch::init() { // 创建并编译着色器 if (!shader_.compileFromSource(SPRITE_VERTEX_SHADER, @@ -167,6 +194,9 @@ bool GLSpriteBatch::init() { return true; } +/** + * @brief 关闭精灵批处理器,释放OpenGL资源 + */ void GLSpriteBatch::shutdown() { if (vao_ != 0) { glDeleteVertexArrays(1, &vao_); @@ -182,6 +212,10 @@ void GLSpriteBatch::shutdown() { } } +/** + * @brief 开始批处理,重置状态并设置视图投影矩阵 + * @param viewProjection 视图投影矩阵 + */ void GLSpriteBatch::begin(const glm::mat4 &viewProjection) { viewProjection_ = viewProjection; vertexCount_ = 0; @@ -192,6 +226,12 @@ void GLSpriteBatch::begin(const glm::mat4 &viewProjection) { batchCount_ = 0; } +/** + * @brief 检查是否需要刷新批次 + * @param texture 当前纹理 + * @param isSDF 是否为SDF渲染 + * @return 需要刷新返回true,否则返回false + */ bool GLSpriteBatch::needsFlush(const Texture &texture, bool isSDF) const { if (currentTexture_ == nullptr) { return false; @@ -202,6 +242,10 @@ bool GLSpriteBatch::needsFlush(const Texture &texture, bool isSDF) const { (vertexCount_ + VERTICES_PER_SPRITE > MAX_VERTICES); } +/** + * @brief 添加精灵顶点到顶点缓冲区 + * @param data 精灵数据 + */ void GLSpriteBatch::addVertices(const SpriteData &data) { // 计算锚点偏移 float anchorOffsetX = data.size.x * data.anchor.x; @@ -254,6 +298,11 @@ void GLSpriteBatch::addVertices(const SpriteData &data) { }; } +/** + * @brief 绘制单个精灵 + * @param texture 纹理引用 + * @param data 精灵数据 + */ void GLSpriteBatch::draw(const Texture &texture, const SpriteData &data) { // 如果需要刷新,先提交当前批次 if (needsFlush(texture, data.isSDF)) { @@ -267,6 +316,11 @@ void GLSpriteBatch::draw(const Texture &texture, const SpriteData &data) { spriteCount_++; } +/** + * @brief 批量绘制多个精灵 + * @param texture 纹理引用 + * @param sprites 精灵数据数组 + */ void GLSpriteBatch::drawBatch(const Texture &texture, const std::vector &sprites) { if (sprites.empty()) { @@ -303,6 +357,11 @@ void GLSpriteBatch::drawBatch(const Texture &texture, batchCount_++; } +/** + * @brief 立即绘制精灵,不缓存 + * @param texture 纹理引用 + * @param data 精灵数据 + */ void GLSpriteBatch::drawImmediate(const Texture &texture, const SpriteData &data) { // 立即绘制,不缓存 - 用于需要立即显示的情况 @@ -316,12 +375,18 @@ void GLSpriteBatch::drawImmediate(const Texture &texture, flush(); // 立即提交 } +/** + * @brief 结束批处理,提交所有待绘制的精灵 + */ void GLSpriteBatch::end() { if (vertexCount_ > 0) { flush(); } } +/** + * @brief 刷新批次,执行实际的OpenGL绘制调用 + */ void GLSpriteBatch::flush() { if (vertexCount_ == 0 || currentTexture_ == nullptr) { return; diff --git a/Extra2D/src/graphics/opengl/gl_texture.cpp b/Extra2D/src/graphics/opengl/gl_texture.cpp index d914d07..30e2682 100644 --- a/Extra2D/src/graphics/opengl/gl_texture.cpp +++ b/Extra2D/src/graphics/opengl/gl_texture.cpp @@ -80,6 +80,14 @@ struct DDSHeaderDXT10 { static constexpr uint32_t DDS_MAGIC = 0x20534444; // "DDS " static constexpr uint32_t DDPF_FOURCC = 0x04; +/** + * @brief 生成四字符代码(FourCC) + * @param a 第一个字符 + * @param b 第二个字符 + * @param c 第三个字符 + * @param d 第四个字符 + * @return 组合后的32位无符号整数 + */ static uint32_t makeFourCC(char a, char b, char c, char d) { return static_cast(a) | (static_cast(b) << 8) | (static_cast(c) << 16) | (static_cast(d) << 24); @@ -89,6 +97,13 @@ static uint32_t makeFourCC(char a, char b, char c, char d) { // GLTexture 实现 // ============================================================================ +/** + * @brief 从像素数据构造纹理对象 + * @param width 纹理宽度(像素) + * @param height 纹理高度(像素) + * @param pixels 像素数据指针,可为nullptr创建空纹理 + * @param channels 颜色通道数(1=R, 3=RGB, 4=RGBA) + */ GLTexture::GLTexture(int width, int height, const uint8_t *pixels, int channels) : textureID_(0), width_(width), height_(height), channels_(channels), format_(PixelFormat::RGBA8), dataSize_(0) { @@ -100,6 +115,10 @@ GLTexture::GLTexture(int width, int height, const uint8_t *pixels, int channels) createTexture(pixels); } +/** + * @brief 从文件路径构造纹理对象 + * @param filepath 纹理文件路径,支持普通图片格式和压缩格式(KTX/DDS) + */ GLTexture::GLTexture(const std::string &filepath) : textureID_(0), width_(0), height_(0), channels_(0), format_(PixelFormat::RGBA8), dataSize_(0) { @@ -133,12 +152,12 @@ GLTexture::~GLTexture() { if (textureID_ != 0) { // 检查 GPU 上下文是否仍然有效 // 如果 OpenGL 上下文已销毁,则跳过 glDeleteTextures 调用 - if (GPUContext::getInstance().isValid()) { + if (GPUContext::get().isValid()) { glDeleteTextures(1, &textureID_); } // VRAM 跟踪: 释放纹理显存(无论上下文是否有效都需要更新统计) if (dataSize_ > 0) { - VRAMManager::getInstance().freeTexture(dataSize_); + VRAMMgr::get().freeTexture(dataSize_); } } } @@ -164,8 +183,15 @@ void GLTexture::bind(unsigned int slot) const { glBindTexture(GL_TEXTURE_2D, textureID_); } +/** + * @brief 解绑当前纹理 + */ void GLTexture::unbind() const { glBindTexture(GL_TEXTURE_2D, 0); } +/** + * @brief 创建OpenGL纹理对象并上传像素数据 + * @param pixels 像素数据指针 + */ void GLTexture::createTexture(const uint8_t *pixels) { GLenum format = GL_RGBA; GLenum internalFormat = GL_RGBA8; @@ -208,7 +234,7 @@ void GLTexture::createTexture(const uint8_t *pixels) { // VRAM 跟踪 dataSize_ = static_cast(width_ * height_ * channels_); - VRAMManager::getInstance().allocTexture(dataSize_); + VRAMMgr::get().allocTexture(dataSize_); } // ============================================================================ @@ -227,6 +253,11 @@ bool GLTexture::loadCompressed(const std::string &filepath) { return false; } +/** + * @brief 加载KTX格式压缩纹理 + * @param filepath KTX文件路径 + * @return 加载成功返回true,失败返回false + */ bool GLTexture::loadKTX(const std::string &filepath) { std::ifstream file(filepath, std::ios::binary); if (!file.is_open()) { @@ -316,13 +347,18 @@ bool GLTexture::loadKTX(const std::string &filepath) { // VRAM 跟踪 dataSize_ = imageSize; - VRAMManager::getInstance().allocTexture(dataSize_); + VRAMMgr::get().allocTexture(dataSize_); E2D_LOG_INFO("Loaded compressed KTX texture: {} ({}x{}, format={:#06x})", filepath, width_, height_, glInternalFormat); return true; } +/** + * @brief 加载DDS格式压缩纹理 + * @param filepath DDS文件路径 + * @return 加载成功返回true,失败返回false + */ bool GLTexture::loadDDS(const std::string &filepath) { std::ifstream file(filepath, std::ios::binary); if (!file.is_open()) { @@ -415,7 +451,7 @@ bool GLTexture::loadDDS(const std::string &filepath) { // VRAM 跟踪 dataSize_ = imageSize; - VRAMManager::getInstance().allocTexture(dataSize_); + VRAMMgr::get().allocTexture(dataSize_); E2D_LOG_INFO("Loaded compressed DDS texture: {} ({}x{})", filepath, width_, height_); @@ -436,6 +472,13 @@ void GLTexture::generateAlphaMask() { PixelFormat GLTexture::getFormat() const { return format_; } +/** + * @brief 静态工厂方法,创建指定格式的空纹理 + * @param width 纹理宽度 + * @param height 纹理高度 + * @param format 像素格式 + * @return 创建的纹理智能指针 + */ Ptr GLTexture::create(int width, int height, PixelFormat format) { int channels = 4; switch (format) { diff --git a/Extra2D/src/graphics/render_backend.cpp b/Extra2D/src/graphics/render_backend.cpp index 3a4c1db..d2dae52 100644 --- a/Extra2D/src/graphics/render_backend.cpp +++ b/Extra2D/src/graphics/render_backend.cpp @@ -3,6 +3,15 @@ namespace extra2d { +/** + * @brief 创建渲染后端实例 + * + * 根据指定的后端类型创建对应的渲染后端实例, + * 目前支持OpenGL后端 + * + * @param type 渲染后端类型(如OpenGL) + * @return 成功返回渲染后端的唯一指针,不支持的类型返回nullptr + */ UniquePtr RenderBackend::create(BackendType type) { switch (type) { case BackendType::OpenGL: diff --git a/Extra2D/src/graphics/render_command.cpp b/Extra2D/src/graphics/render_command.cpp index 19980cc..a3b6cef 100644 --- a/Extra2D/src/graphics/render_command.cpp +++ b/Extra2D/src/graphics/render_command.cpp @@ -7,6 +7,21 @@ namespace extra2d { // RenderCommand 便捷构造函数 // ============================================================================ +/** + * @brief 创建精灵渲染命令 + * + * 创建一个用于渲染2D精灵的RenderCommand对象,包含纹理、目标区域、源区域、 + * 着色、旋转、锚点和层级等信息 + * + * @param tex 指向纹理对象的指针 + * @param dest 目标渲染区域 + * @param src 源纹理区域 + * @param tint 着色颜色 + * @param rot 旋转角度(弧度) + * @param anc 锚点位置(0.0-1.0范围) + * @param lyr 渲染层级 + * @return 配置好的RenderCommand对象 + */ RenderCommand RenderCommand::makeSprite(const Texture* tex, const Rect& dest, const Rect& src, const Color& tint, float rot, const Vec2& anc, @@ -31,6 +46,18 @@ RenderCommand RenderCommand::makeSprite(const Texture* tex, const Rect& dest, return cmd; } +/** + * @brief 创建线段渲染命令 + * + * 创建一个用于渲染线段的RenderCommand对象 + * + * @param s 线段起点坐标 + * @param e 线段终点坐标 + * @param c 线段颜色 + * @param w 线段宽度 + * @param lyr 渲染层级 + * @return 配置好的RenderCommand对象 + */ RenderCommand RenderCommand::makeLine(const Vec2& s, const Vec2& e, const Color& c, float w, uint32_t lyr) { RenderCommand cmd; @@ -48,6 +75,18 @@ RenderCommand RenderCommand::makeLine(const Vec2& s, const Vec2& e, const Color& return cmd; } +/** + * @brief 创建矩形渲染命令 + * + * 创建一个用于渲染矩形的RenderCommand对象,可选择填充或描边模式 + * + * @param r 矩形区域 + * @param c 矩形颜色 + * @param w 线条宽度(仅描边模式有效) + * @param fill 是否填充矩形 + * @param lyr 渲染层级 + * @return 配置好的RenderCommand对象 + */ RenderCommand RenderCommand::makeRect(const Rect& r, const Color& c, float w, bool fill, uint32_t lyr) { RenderCommand cmd; @@ -69,12 +108,29 @@ RenderCommand RenderCommand::makeRect(const Rect& r, const Color& c, // RenderCommandBuffer 实现 // ============================================================================ +/** + * @brief 默认构造函数 + * + * 初始化渲染命令缓冲区,预留初始容量 + */ RenderCommandBuffer::RenderCommandBuffer() : nextOrder_(0) { commands_.reserve(INITIAL_CAPACITY); } +/** + * @brief 析构函数 + * + * 释放渲染命令缓冲区资源 + */ RenderCommandBuffer::~RenderCommandBuffer() = default; +/** + * @brief 添加渲染命令(左值引用版本) + * + * 将渲染命令以拷贝方式添加到缓冲区,自动分配顺序号 + * + * @param cmd 要添加的渲染命令 + */ void RenderCommandBuffer::addCommand(const RenderCommand& cmd) { if (commands_.size() >= MAX_CAPACITY) { // 缓冲区已满,可能需要立即刷新 @@ -86,6 +142,13 @@ void RenderCommandBuffer::addCommand(const RenderCommand& cmd) { commands_.push_back(std::move(copy)); } +/** + * @brief 添加渲染命令(右值引用版本) + * + * 将渲染命令以移动方式添加到缓冲区,自动分配顺序号 + * + * @param cmd 要添加的渲染命令(右值引用) + */ void RenderCommandBuffer::addCommand(RenderCommand&& cmd) { if (commands_.size() >= MAX_CAPACITY) { return; @@ -95,6 +158,13 @@ void RenderCommandBuffer::addCommand(RenderCommand&& cmd) { commands_.push_back(std::move(cmd)); } +/** + * @brief 原地构造渲染命令 + * + * 在缓冲区中直接构造一个渲染命令对象,避免额外的拷贝或移动操作 + * + * @return 新构造的渲染命令对象的引用 + */ RenderCommand& RenderCommandBuffer::emplaceCommand() { if (commands_.size() >= MAX_CAPACITY) { // 如果已满,返回一个虚拟命令(不应该发生) @@ -107,6 +177,12 @@ RenderCommand& RenderCommandBuffer::emplaceCommand() { return commands_.back(); } +/** + * @brief 对渲染命令进行排序 + * + * 按层级、命令类型、纹理/材质和提交顺序对命令进行排序, + * 以优化渲染性能和批处理效率 + */ void RenderCommandBuffer::sortCommands() { // 按以下优先级排序: // 1. 层级 (layer) - 低层级先渲染 @@ -117,17 +193,38 @@ void RenderCommandBuffer::sortCommands() { std::sort(commands_.begin(), commands_.end(), compareCommands); } +/** + * @brief 清空缓冲区 + * + * 移除所有渲染命令并重置顺序计数器 + */ void RenderCommandBuffer::clear() { commands_.clear(); nextOrder_ = 0; } +/** + * @brief 预留缓冲区容量 + * + * 预先分配缓冲区内存以减少动态分配开销 + * + * @param capacity 要预留的容量大小 + */ void RenderCommandBuffer::reserve(size_t capacity) { if (capacity <= MAX_CAPACITY) { commands_.reserve(capacity); } } +/** + * @brief 渲染命令比较函数 + * + * 用于排序的比较函数,按层级、类型、纹理和顺序进行比较 + * + * @param a 第一个渲染命令 + * @param b 第二个渲染命令 + * @return 如果a应排在b前面返回true,否则返回false + */ bool RenderCommandBuffer::compareCommands(const RenderCommand& a, const RenderCommand& b) { // 首先按层级排序 if (a.layer != b.layer) { diff --git a/Extra2D/src/graphics/render_target.cpp b/Extra2D/src/graphics/render_target.cpp index adac9ac..4454d79 100644 --- a/Extra2D/src/graphics/render_target.cpp +++ b/Extra2D/src/graphics/render_target.cpp @@ -12,10 +12,26 @@ namespace extra2d { // RenderTarget实现 // ============================================================================ +/** + * @brief 默认构造函数 + * + * 创建一个空的渲染目标对象 + */ RenderTarget::RenderTarget() = default; +/** + * @brief 析构函数 + * + * 销毁渲染目标并释放相关资源 + */ RenderTarget::~RenderTarget() { destroy(); } +/** + * @brief 移动构造函数 + * @param other 源渲染目标对象 + * + * 将其他渲染目标的资源转移到新对象 + */ RenderTarget::RenderTarget(RenderTarget &&other) noexcept : fbo_(other.fbo_), rbo_(other.rbo_), colorTexture_(std::move(other.colorTexture_)), @@ -29,6 +45,13 @@ RenderTarget::RenderTarget(RenderTarget &&other) noexcept other.height_ = 0; } +/** + * @brief 移动赋值运算符 + * @param other 源渲染目标对象 + * @return 当前对象引用 + * + * 将其他渲染目标的资源转移到当前对象 + */ RenderTarget &RenderTarget::operator=(RenderTarget &&other) noexcept { if (this != &other) { destroy(); @@ -52,6 +75,13 @@ RenderTarget &RenderTarget::operator=(RenderTarget &&other) noexcept { return *this; } +/** + * @brief 根据配置创建渲染目标 + * @param config 渲染目标配置 + * @return 创建成功返回true,失败返回false + * + * 根据指定的配置参数创建帧缓冲对象 + */ bool RenderTarget::create(const RenderTargetConfig &config) { destroy(); @@ -73,6 +103,14 @@ bool RenderTarget::create(const RenderTargetConfig &config) { return true; } +/** + * @brief 从现有纹理创建渲染目标 + * @param texture 颜色纹理 + * @param hasDepth 是否创建深度缓冲 + * @return 创建成功返回true,失败返回false + * + * 使用现有纹理作为颜色附件创建帧缓冲对象 + */ bool RenderTarget::createFromTexture(Ptr texture, bool hasDepth) { if (!texture || !texture->isValid()) { E2D_ERROR("无效的颜色纹理"); @@ -125,6 +163,11 @@ bool RenderTarget::createFromTexture(Ptr texture, bool hasDepth) { return true; } +/** + * @brief 销毁渲染目标 + * + * 释放帧缓冲对象和相关资源 + */ void RenderTarget::destroy() { deleteFBO(); @@ -135,6 +178,11 @@ void RenderTarget::destroy() { height_ = 0; } +/** + * @brief 绑定渲染目标 + * + * 将此渲染目标绑定为当前渲染目标 + */ void RenderTarget::bind() { if (!isValid()) { return; @@ -144,8 +192,19 @@ void RenderTarget::bind() { glViewport(0, 0, width_, height_); } +/** + * @brief 解绑渲染目标 + * + * 恢复默认帧缓冲 + */ void RenderTarget::unbind() { bindDefault(); } +/** + * @brief 清除渲染目标 + * @param color 清除颜色 + * + * 使用指定颜色清除颜色缓冲,如有深度/模板缓冲也会清除 + */ void RenderTarget::clear(const Color &color) { if (!isValid()) { return; @@ -167,6 +226,15 @@ void RenderTarget::clear(const Color &color) { glClear(mask); } +/** + * @brief 设置视口区域 + * @param x 视口左下角X坐标 + * @param y 视口左下角Y坐标 + * @param width 视口宽度 + * @param height 视口高度 + * + * 设置渲染目标的视口区域 + */ void RenderTarget::setViewport(int x, int y, int width, int height) { if (!isValid()) { return; @@ -176,6 +244,15 @@ void RenderTarget::setViewport(int x, int y, int width, int height) { glViewport(x, y, width, height); } +/** + * @brief 获取完整视口区域 + * @param[out] x 视口左下角X坐标 + * @param[out] y 视口左下角Y坐标 + * @param[out] width 视口宽度 + * @param[out] height 视口高度 + * + * 获取渲染目标的完整视口区域 + */ void RenderTarget::getFullViewport(int &x, int &y, int &width, int &height) const { x = 0; @@ -184,6 +261,14 @@ void RenderTarget::getFullViewport(int &x, int &y, int &width, height = height_; } +/** + * @brief 调整渲染目标大小 + * @param width 新宽度 + * @param height 新高度 + * @return 调整成功返回true,失败返回false + * + * 重新创建指定大小的渲染目标 + */ bool RenderTarget::resize(int width, int height) { if (!isValid()) { return false; @@ -200,6 +285,12 @@ bool RenderTarget::resize(int width, int height) { return create(config); } +/** + * @brief 复制到另一个渲染目标 + * @param target 目标渲染目标 + * + * 使用glBlitFramebuffer将内容复制到目标渲染目标 + */ void RenderTarget::copyTo(RenderTarget &target) { if (!isValid() || !target.isValid()) { return; @@ -220,6 +311,14 @@ void RenderTarget::copyTo(RenderTarget &target) { glBindFramebuffer(GL_FRAMEBUFFER, 0); } +/** + * @brief 将内容传输到另一个渲染目标 + * @param target 目标渲染目标 + * @param color 是否复制颜色缓冲 + * @param depth 是否复制深度缓冲 + * + * 使用glBlitFramebuffer进行选择性复制 + */ void RenderTarget::blitTo(RenderTarget &target, bool color, bool depth) { if (!isValid() || !target.isValid()) { return; @@ -245,6 +344,13 @@ void RenderTarget::blitTo(RenderTarget &target, bool color, bool depth) { glBindFramebuffer(GL_FRAMEBUFFER, 0); } +/** + * @brief 复制到屏幕 + * @param screenWidth 屏幕宽度 + * @param screenHeight 屏幕高度 + * + * 将渲染目标内容复制到默认帧缓冲(屏幕) + */ void RenderTarget::copyToScreen(int screenWidth, int screenHeight) { if (!isValid()) { return; @@ -259,6 +365,13 @@ void RenderTarget::copyToScreen(int screenWidth, int screenHeight) { glBindFramebuffer(GL_FRAMEBUFFER, 0); } +/** + * @brief 保存渲染目标到文件 + * @param filepath 文件路径 + * @return 保存成功返回true,失败返回false + * + * 将渲染目标内容保存为PNG图片文件 + */ bool RenderTarget::saveToFile(const std::string &filepath) { if (!isValid() || !colorTexture_) { return false; @@ -296,6 +409,13 @@ bool RenderTarget::saveToFile(const std::string &filepath) { return true; } +/** + * @brief 根据配置创建渲染目标 + * @param config 渲染目标配置 + * @return 创建成功返回渲染目标指针,失败返回nullptr + * + * 静态工厂方法,创建并初始化渲染目标 + */ Ptr RenderTarget::createFromConfig(const RenderTargetConfig &config) { auto rt = std::make_shared(); @@ -305,18 +425,35 @@ RenderTarget::createFromConfig(const RenderTargetConfig &config) { return nullptr; } +/** + * @brief 获取当前绑定的帧缓冲对象ID + * @return 当前绑定的FBO ID + * + * 查询OpenGL当前绑定的帧缓冲对象 + */ GLuint RenderTarget::getCurrentFBO() { GLint fbo = 0; glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo); return static_cast(fbo); } +/** + * @brief 绑定默认帧缓冲 + * + * 将默认帧缓冲(屏幕)绑定为当前渲染目标 + */ void RenderTarget::bindDefault() { glBindFramebuffer(GL_FRAMEBUFFER, 0); } // ============================================================================ // 内部方法 // ============================================================================ +/** + * @brief 创建帧缓冲对象 + * @return 创建成功返回true,失败返回false + * + * 内部方法,创建FBO及相关附件 + */ bool RenderTarget::createFBO() { // 创建颜色纹理 colorTexture_ = GLTexture::create(width_, height_, colorFormat_); @@ -370,6 +507,11 @@ bool RenderTarget::createFBO() { return true; } +/** + * @brief 删除帧缓冲对象 + * + * 内部方法,删除FBO和渲染缓冲对象 + */ void RenderTarget::deleteFBO() { if (rbo_ != 0) { glDeleteRenderbuffers(1, &rbo_); @@ -386,6 +528,15 @@ void RenderTarget::deleteFBO() { // MultisampleRenderTarget实现 // ============================================================================ +/** + * @brief 创建多重采样渲染目标 + * @param width 宽度 + * @param height 高度 + * @param samples 采样数 + * @return 创建成功返回true,失败返回false + * + * 创建支持多重采样抗锯齿的渲染目标 + */ bool MultisampleRenderTarget::create(int width, int height, int samples) { // 先销毁现有的 destroy(); @@ -433,6 +584,11 @@ bool MultisampleRenderTarget::create(int width, int height, int samples) { return true; } +/** + * @brief 销毁多重采样渲染目标 + * + * 释放多重采样渲染缓冲和帧缓冲对象 + */ void MultisampleRenderTarget::destroy() { // 删除颜色渲染缓冲 if (colorRBO_ != 0) { @@ -444,6 +600,12 @@ void MultisampleRenderTarget::destroy() { RenderTarget::destroy(); } +/** + * @brief 解析多重采样到目标渲染目标 + * @param target 目标渲染目标 + * + * 将多重采样渲染目标解析到普通渲染目标 + */ void MultisampleRenderTarget::resolveTo(RenderTarget &target) { if (!isValid() || !target.isValid()) { return; @@ -463,11 +625,23 @@ void MultisampleRenderTarget::resolveTo(RenderTarget &target) { // RenderTargetStack实现 // ============================================================================ -RenderTargetStack &RenderTargetStack::getInstance() { +/** + * @brief 获取RenderTargetStack单例实例 + * @return RenderTargetStack单例的引用 + * + * 使用静态局部变量实现线程安全的单例模式 + */ +RenderTargetStack &RenderTargetStack::get() { static RenderTargetStack instance; return instance; } +/** + * @brief 压入渲染目标到栈 + * @param target 渲染目标指针 + * + * 将渲染目标压入栈并绑定为当前渲染目标 + */ void RenderTargetStack::push(RenderTarget *target) { std::lock_guard lock(mutex_); @@ -477,6 +651,11 @@ void RenderTargetStack::push(RenderTarget *target) { } } +/** + * @brief 弹出栈顶渲染目标 + * + * 弹出当前渲染目标并恢复前一个渲染目标 + */ void RenderTargetStack::pop() { std::lock_guard lock(mutex_); @@ -492,6 +671,10 @@ void RenderTargetStack::pop() { } } +/** + * @brief 获取当前渲染目标 + * @return 当前渲染目标指针,栈为空返回nullptr + */ RenderTarget *RenderTargetStack::getCurrent() const { std::lock_guard lock(mutex_); @@ -501,11 +684,20 @@ RenderTarget *RenderTargetStack::getCurrent() const { return stack_.back(); } +/** + * @brief 获取栈大小 + * @return 栈中渲染目标的数量 + */ size_t RenderTargetStack::size() const { std::lock_guard lock(mutex_); return stack_.size(); } +/** + * @brief 清空渲染目标栈 + * + * 清空栈并恢复默认帧缓冲 + */ void RenderTargetStack::clear() { std::lock_guard lock(mutex_); stack_.clear(); @@ -513,15 +705,29 @@ void RenderTargetStack::clear() { } // ============================================================================ -// RenderTargetManager实现 +// RenderTargetMgr实现 // ============================================================================ -RenderTargetManager &RenderTargetManager::getInstance() { - static RenderTargetManager instance; +/** + * @brief 获取RenderTargetMgr单例实例 + * @return RenderTargetMgr单例的引用 + * + * 使用静态局部变量实现线程安全的单例模式 + */ +RenderTargetMgr &RenderTargetMgr::get() { + static RenderTargetMgr instance; return instance; } -bool RenderTargetManager::init(int width, int height) { +/** + * @brief 初始化渲染目标管理器 + * @param width 默认渲染目标宽度 + * @param height 默认渲染目标高度 + * @return 初始化成功返回true,失败返回false + * + * 创建默认渲染目标 + */ +bool RenderTargetMgr::init(int width, int height) { if (initialized_) { return true; } @@ -544,7 +750,12 @@ bool RenderTargetManager::init(int width, int height) { return true; } -void RenderTargetManager::shutdown() { +/** + * @brief 关闭渲染目标管理器 + * + * 清理所有渲染目标资源 + */ +void RenderTargetMgr::shutdown() { if (!initialized_) { return; } @@ -556,8 +767,15 @@ void RenderTargetManager::shutdown() { E2D_INFO("渲染目标管理器已关闭"); } +/** + * @brief 创建渲染目标 + * @param config 渲染目标配置 + * @return 创建成功返回渲染目标指针,失败返回nullptr + * + * 创建新的渲染目标并由管理器管理 + */ Ptr -RenderTargetManager::createRenderTarget(const RenderTargetConfig &config) { +RenderTargetMgr::createRenderTarget(const RenderTargetConfig &config) { if (!initialized_) { E2D_ERROR("渲染目标管理器未初始化"); return nullptr; @@ -570,7 +788,14 @@ RenderTargetManager::createRenderTarget(const RenderTargetConfig &config) { return rt; } -void RenderTargetManager::resize(int width, int height) { +/** + * @brief 调整所有渲染目标大小 + * @param width 新宽度 + * @param height 新高度 + * + * 调整默认渲染目标的大小 + */ +void RenderTargetMgr::resize(int width, int height) { if (!initialized_) { return; } diff --git a/Extra2D/src/graphics/shader_preset.cpp b/Extra2D/src/graphics/shader_preset.cpp index e9cce1e..fe05212 100644 --- a/Extra2D/src/graphics/shader_preset.cpp +++ b/Extra2D/src/graphics/shader_preset.cpp @@ -7,6 +7,14 @@ namespace extra2d { // ShaderPreset实现 // ============================================================================ +/** + * @brief 创建水波纹效果着色器 + * + * 创建并配置一个水波纹效果的GLShader对象,包含波动速度、振幅和频率参数 + * + * @param params 水波纹效果参数,包含waveSpeed、waveAmplitude和waveFrequency + * @return 成功返回配置好的着色器智能指针,失败返回nullptr + */ Ptr ShaderPreset::Water(const WaterParams ¶ms) { auto shader = std::make_shared(); @@ -25,6 +33,14 @@ Ptr ShaderPreset::Water(const WaterParams ¶ms) { return shader; } +/** + * @brief 创建描边效果着色器 + * + * 创建并配置一个描边效果的GLShader对象,包含描边颜色和厚度参数 + * + * @param params 描边效果参数,包含color和thickness + * @return 成功返回配置好的着色器智能指针,失败返回nullptr + */ Ptr ShaderPreset::Outline(const OutlineParams ¶ms) { auto shader = std::make_shared(); @@ -43,6 +59,14 @@ Ptr ShaderPreset::Outline(const OutlineParams ¶ms) { return shader; } +/** + * @brief 创建扭曲效果着色器 + * + * 创建并配置一个扭曲效果的GLShader对象,包含扭曲强度和时间缩放参数 + * + * @param params 扭曲效果参数,包含distortionAmount和timeScale + * @return 成功返回配置好的着色器智能指针,失败返回nullptr + */ Ptr ShaderPreset::Distortion(const DistortionParams ¶ms) { auto shader = std::make_shared(); @@ -60,6 +84,14 @@ Ptr ShaderPreset::Distortion(const DistortionParams ¶ms) { return shader; } +/** + * @brief 创建像素化效果着色器 + * + * 创建并配置一个像素化效果的GLShader对象,包含像素大小参数 + * + * @param params 像素化效果参数,包含pixelSize + * @return 成功返回配置好的着色器智能指针,失败返回nullptr + */ Ptr ShaderPreset::Pixelate(const PixelateParams ¶ms) { auto shader = std::make_shared(); @@ -76,6 +108,14 @@ Ptr ShaderPreset::Pixelate(const PixelateParams ¶ms) { return shader; } +/** + * @brief 创建反相效果着色器 + * + * 创建并配置一个颜色反相效果的GLShader对象,包含反相强度参数 + * + * @param params 反相效果参数,包含strength + * @return 成功返回配置好的着色器智能指针,失败返回nullptr + */ Ptr ShaderPreset::Invert(const InvertParams ¶ms) { auto shader = std::make_shared(); @@ -92,6 +132,14 @@ Ptr ShaderPreset::Invert(const InvertParams ¶ms) { return shader; } +/** + * @brief 创建灰度效果着色器 + * + * 创建并配置一个灰度效果的GLShader对象,包含灰度强度参数 + * + * @param params 灰度效果参数,包含intensity + * @return 成功返回配置好的着色器智能指针,失败返回nullptr + */ Ptr ShaderPreset::Grayscale(const GrayscaleParams ¶ms) { auto shader = std::make_shared(); @@ -108,6 +156,14 @@ Ptr ShaderPreset::Grayscale(const GrayscaleParams ¶ms) { return shader; } +/** + * @brief 创建模糊效果着色器 + * + * 创建并配置一个模糊效果的GLShader对象,包含模糊半径参数 + * + * @param params 模糊效果参数,包含radius + * @return 成功返回配置好的着色器智能指针,失败返回nullptr + */ Ptr ShaderPreset::Blur(const BlurParams ¶ms) { auto shader = std::make_shared(); @@ -124,6 +180,15 @@ Ptr ShaderPreset::Blur(const BlurParams ¶ms) { return shader; } +/** + * @brief 创建灰度+描边组合效果着色器 + * + * 创建并配置一个同时应用灰度和描边效果的GLShader对象 + * + * @param grayParams 灰度效果参数,包含intensity + * @param outlineParams 描边效果参数,包含color和thickness + * @return 成功返回配置好的着色器智能指针,失败返回nullptr + */ Ptr ShaderPreset::GrayscaleOutline(const GrayscaleParams &grayParams, const OutlineParams &outlineParams) { @@ -183,6 +248,15 @@ void main() { return shader; } +/** + * @brief 创建像素化+反相组合效果着色器 + * + * 创建并配置一个同时应用像素化和反相效果的GLShader对象 + * + * @param pixParams 像素化效果参数,包含pixelSize + * @param invParams 反相效果参数,包含strength + * @return 成功返回配置好的着色器智能指针,失败返回nullptr + */ Ptr ShaderPreset::PixelateInvert(const PixelateParams &pixParams, const InvertParams &invParams) { // 创建组合效果的片段着色器 (GLES 3.2) diff --git a/Extra2D/src/graphics/shader_system.cpp b/Extra2D/src/graphics/shader_system.cpp index f330f7c..3c189db 100644 --- a/Extra2D/src/graphics/shader_system.cpp +++ b/Extra2D/src/graphics/shader_system.cpp @@ -182,11 +182,23 @@ void main() { // ShaderSystem实现 // ============================================================================ -ShaderSystem &ShaderSystem::getInstance() { +/** + * @brief 获取ShaderSystem单例实例 + * @return ShaderSystem单例的引用 + * + * 使用静态局部变量实现线程安全的单例模式 + */ +ShaderSystem &ShaderSystem::get() { static ShaderSystem instance; return instance; } +/** + * @brief 初始化Shader系统 + * @return 初始化成功返回true,失败返回false + * + * 加载所有内置着色器,包括精灵、粒子、后处理和形状着色器 + */ bool ShaderSystem::init() { E2D_INFO("初始化Shader系统..."); @@ -199,6 +211,11 @@ bool ShaderSystem::init() { return true; } +/** + * @brief 关闭Shader系统 + * + * 清理所有着色器资源,释放内置着色器 + */ void ShaderSystem::shutdown() { E2D_INFO("关闭Shader系统..."); clear(); @@ -209,6 +226,12 @@ void ShaderSystem::shutdown() { builtinShapeShader_.reset(); } +/** + * @brief 加载内置着色器 + * @return 加载成功返回true,失败返回false + * + * 编译并加载所有内置着色器:精灵、粒子、后处理和形状着色器 + */ bool ShaderSystem::loadBuiltinShaders() { // 加载精灵Shader builtinSpriteShader_ = std::make_shared(); @@ -246,6 +269,15 @@ bool ShaderSystem::loadBuiltinShaders() { return true; } +/** + * @brief 从文件加载着色器 + * @param name 着色器名称 + * @param vertPath 顶点着色器文件路径 + * @param fragPath 片段着色器文件路径 + * @return 加载成功返回着色器指针,失败返回nullptr + * + * 从指定路径读取顶点和片段着色器源码并编译 + */ Ptr ShaderSystem::loadFromFile(const std::string &name, const std::string &vertPath, const std::string &fragPath) { @@ -285,6 +317,15 @@ Ptr ShaderSystem::loadFromFile(const std::string &name, return shader; } +/** + * @brief 从源码加载着色器 + * @param name 着色器名称 + * @param vertSource 顶点着色器源码 + * @param fragSource 片段着色器源码 + * @return 加载成功返回着色器指针,失败返回nullptr + * + * 直接从源码字符串编译着色器 + */ Ptr ShaderSystem::loadFromSource(const std::string &name, const std::string &vertSource, const std::string &fragSource) { @@ -306,6 +347,11 @@ Ptr ShaderSystem::loadFromSource(const std::string &name, return shader; } +/** + * @brief 获取指定名称的着色器 + * @param name 着色器名称 + * @return 找到返回着色器指针,未找到返回nullptr + */ Ptr ShaderSystem::get(const std::string &name) { auto it = shaders_.find(name); if (it != shaders_.end()) { @@ -314,14 +360,36 @@ Ptr ShaderSystem::get(const std::string &name) { return nullptr; } +/** + * @brief 检查指定名称的着色器是否存在 + * @param name 着色器名称 + * @return 存在返回true,不存在返回false + */ bool ShaderSystem::has(const std::string &name) const { return shaders_.find(name) != shaders_.end(); } +/** + * @brief 移除指定名称的着色器 + * @param name 着色器名称 + * + * 从着色器管理器中移除指定着色器 + */ void ShaderSystem::remove(const std::string &name) { shaders_.erase(name); } +/** + * @brief 清空所有着色器 + * + * 移除所有已加载的着色器 + */ void ShaderSystem::clear() { shaders_.clear(); } +/** + * @brief 设置文件监视功能 + * @param enable 是否启用 + * + * 启用或禁用着色器文件变化监视功能 + */ void ShaderSystem::setFileWatching(bool enable) { fileWatching_ = enable; if (enable) { @@ -331,6 +399,11 @@ void ShaderSystem::setFileWatching(bool enable) { } } +/** + * @brief 更新文件监视 + * + * 定期检查着色器文件是否发生变化,如有变化则自动重载 + */ void ShaderSystem::updateFileWatching() { if (!fileWatching_) return; @@ -342,6 +415,11 @@ void ShaderSystem::updateFileWatching() { } } +/** + * @brief 检查并重载变化的着色器 + * + * 检查所有着色器文件的修改时间,如有变化则自动重载 + */ void ShaderSystem::checkAndReload() { for (auto &[name, info] : shaders_) { if (info.isBuiltin) @@ -359,6 +437,13 @@ void ShaderSystem::checkAndReload() { } } +/** + * @brief 重载指定着色器 + * @param name 着色器名称 + * @return 重载成功返回true,失败返回false + * + * 重新从文件加载并编译指定着色器 + */ bool ShaderSystem::reload(const std::string &name) { auto it = shaders_.find(name); if (it == shaders_.end()) { @@ -387,6 +472,11 @@ bool ShaderSystem::reload(const std::string &name) { return false; } +/** + * @brief 重载所有着色器 + * + * 重载所有非内置着色器 + */ void ShaderSystem::reloadAll() { for (const auto &[name, info] : shaders_) { if (!info.isBuiltin) { @@ -395,22 +485,45 @@ void ShaderSystem::reloadAll() { } } +/** + * @brief 获取内置精灵着色器 + * @return 精灵着色器指针 + */ Ptr ShaderSystem::getBuiltinSpriteShader() { return builtinSpriteShader_; } +/** + * @brief 获取内置粒子着色器 + * @return 粒子着色器指针 + */ Ptr ShaderSystem::getBuiltinParticleShader() { return builtinParticleShader_; } +/** + * @brief 获取内置后处理着色器 + * @return 后处理着色器指针 + */ Ptr ShaderSystem::getBuiltinPostProcessShader() { return builtinPostProcessShader_; } +/** + * @brief 获取内置形状着色器 + * @return 形状着色器指针 + */ Ptr ShaderSystem::getBuiltinShapeShader() { return builtinShapeShader_; } +/** + * @brief 读取文件内容 + * @param filepath 文件路径 + * @return 文件内容字符串,读取失败返回空字符串 + * + * 以二进制模式读取文件全部内容 + */ std::string ShaderSystem::readFile(const std::string &filepath) { std::ifstream file(filepath, std::ios::in | std::ios::binary); if (!file.is_open()) { @@ -422,6 +535,13 @@ std::string ShaderSystem::readFile(const std::string &filepath) { return buffer.str(); } +/** + * @brief 获取文件修改时间 + * @param filepath 文件路径 + * @return 文件最后修改时间戳,失败返回0 + * + * 获取文件的最后修改时间,用于文件监视功能 + */ uint64_t ShaderSystem::getFileModifiedTime(const std::string &filepath) { #ifdef _WIN32 struct _stat64 statBuf; @@ -441,47 +561,103 @@ uint64_t ShaderSystem::getFileModifiedTime(const std::string &filepath) { // ShaderParams实现 // ============================================================================ +/** + * @brief 构造函数 + * @param shader 关联的着色器对象 + * + * 创建一个着色器参数设置器 + */ ShaderParams::ShaderParams(GLShader &shader) : shader_(shader) {} +/** + * @brief 设置布尔类型uniform变量 + * @param name 变量名 + * @param value 布尔值 + * @return 当前对象引用,支持链式调用 + */ ShaderParams &ShaderParams::setBool(const std::string &name, bool value) { shader_.setBool(name, value); return *this; } +/** + * @brief 设置整数类型uniform变量 + * @param name 变量名 + * @param value 整数值 + * @return 当前对象引用,支持链式调用 + */ ShaderParams &ShaderParams::setInt(const std::string &name, int value) { shader_.setInt(name, value); return *this; } +/** + * @brief 设置浮点类型uniform变量 + * @param name 变量名 + * @param value 浮点值 + * @return 当前对象引用,支持链式调用 + */ ShaderParams &ShaderParams::setFloat(const std::string &name, float value) { shader_.setFloat(name, value); return *this; } +/** + * @brief 设置二维向量类型uniform变量 + * @param name 变量名 + * @param value 二维向量值 + * @return 当前对象引用,支持链式调用 + */ ShaderParams &ShaderParams::setVec2(const std::string &name, const glm::vec2 &value) { shader_.setVec2(name, value); return *this; } +/** + * @brief 设置三维向量类型uniform变量 + * @param name 变量名 + * @param value 三维向量值 + * @return 当前对象引用,支持链式调用 + */ ShaderParams &ShaderParams::setVec3(const std::string &name, const glm::vec3 &value) { shader_.setVec3(name, value); return *this; } +/** + * @brief 设置四维向量类型uniform变量 + * @param name 变量名 + * @param value 四维向量值 + * @return 当前对象引用,支持链式调用 + */ ShaderParams &ShaderParams::setVec4(const std::string &name, const glm::vec4 &value) { shader_.setVec4(name, value); return *this; } +/** + * @brief 设置4x4矩阵类型uniform变量 + * @param name 变量名 + * @param value 4x4矩阵值 + * @return 当前对象引用,支持链式调用 + */ ShaderParams &ShaderParams::setMat4(const std::string &name, const glm::mat4 &value) { shader_.setMat4(name, value); return *this; } +/** + * @brief 设置颜色类型uniform变量 + * @param name 变量名 + * @param color 颜色值 + * @return 当前对象引用,支持链式调用 + * + * 将颜色对象转换为四维向量并设置 + */ ShaderParams &ShaderParams::setColor(const std::string &name, const Color &color) { shader_.setVec4(name, glm::vec4(color.r, color.g, color.b, color.a)); diff --git a/Extra2D/src/graphics/texture_atlas.cpp b/Extra2D/src/graphics/texture_atlas.cpp index ba44b81..0c47469 100644 --- a/Extra2D/src/graphics/texture_atlas.cpp +++ b/Extra2D/src/graphics/texture_atlas.cpp @@ -9,6 +9,13 @@ namespace extra2d { // TextureAtlasPage 实现 // ============================================================================ +/** + * @brief 构造函数 + * @param width 页面宽度 + * @param height 页面高度 + * + * 创建指定尺寸的纹理图集页面,初始化空白纹理和打包根节点 + */ TextureAtlasPage::TextureAtlasPage(int width, int height) : width_(width), height_(height), isFull_(false), usedArea_(0) { // 创建空白纹理 @@ -21,8 +28,24 @@ TextureAtlasPage::TextureAtlasPage(int width, int height) E2D_LOG_INFO("Created texture atlas page: {}x{}", width, height); } +/** + * @brief 析构函数 + * + * 释放纹理图集页面资源 + */ TextureAtlasPage::~TextureAtlasPage() = default; +/** + * @brief 尝试添加纹理到图集页面 + * @param name 纹理名称 + * @param texWidth 纹理宽度 + * @param texHeight 纹理高度 + * @param pixels 像素数据 + * @param[out] outUvRect 输出的UV坐标矩形 + * @return 添加成功返回true,失败返回false + * + * 尝试将纹理添加到图集页面中,使用矩形打包算法找到合适位置 + */ bool TextureAtlasPage::tryAddTexture(const std::string& name, int texWidth, int texHeight, const uint8_t* pixels, Rect& outUvRect) { if (isFull_) { @@ -73,6 +96,15 @@ bool TextureAtlasPage::tryAddTexture(const std::string& name, int texWidth, int return true; } +/** + * @brief 插入纹理到打包树 + * @param node 当前节点 + * @param width 纹理宽度 + * @param height 纹理高度 + * @return 找到合适的节点返回节点指针,否则返回nullptr + * + * 使用二叉树算法递归查找合适的空间位置 + */ TextureAtlasPage::PackNode* TextureAtlasPage::insert(PackNode* node, int width, int height) { if (node == nullptr) { return nullptr; @@ -116,6 +148,16 @@ TextureAtlasPage::PackNode* TextureAtlasPage::insert(PackNode* node, int width, return insert(node->left.get(), width, height); } +/** + * @brief 写入像素数据到纹理 + * @param x 起始X坐标 + * @param y 起始Y坐标 + * @param w 宽度 + * @param h 高度 + * @param pixels 像素数据 + * + * 使用glTexSubImage2D更新纹理的指定区域 + */ void TextureAtlasPage::writePixels(int x, int y, int w, int h, const uint8_t* pixels) { if (texture_ == nullptr || pixels == nullptr) { return; @@ -130,6 +172,11 @@ void TextureAtlasPage::writePixels(int x, int y, int w, int h, const uint8_t* pi glBindTexture(GL_TEXTURE_2D, 0); } +/** + * @brief 获取图集中的纹理条目信息 + * @param name 纹理名称 + * @return 找到返回条目指针,未找到返回nullptr + */ const AtlasEntry* TextureAtlasPage::getEntry(const std::string& name) const { auto it = entries_.find(name); if (it != entries_.end()) { @@ -138,6 +185,12 @@ const AtlasEntry* TextureAtlasPage::getEntry(const std::string& name) const { return nullptr; } +/** + * @brief 获取页面使用率 + * @return 使用率(0.0到1.0之间) + * + * 计算已使用面积占总面积的比例 + */ float TextureAtlasPage::getUsageRatio() const { return static_cast(usedArea_) / (width_ * height_); } @@ -146,6 +199,11 @@ float TextureAtlasPage::getUsageRatio() const { // TextureAtlas 实现 // ============================================================================ +/** + * @brief 默认构造函数 + * + * 创建一个使用默认页面大小的纹理图集 + */ TextureAtlas::TextureAtlas() : pageSize_(TextureAtlasPage::DEFAULT_SIZE), sizeThreshold_(256), @@ -153,14 +211,35 @@ TextureAtlas::TextureAtlas() initialized_(false) { } +/** + * @brief 析构函数 + * + * 释放纹理图集资源 + */ TextureAtlas::~TextureAtlas() = default; +/** + * @brief 初始化纹理图集 + * @param pageSize 页面大小 + * + * 设置图集页面大小并标记为已初始化 + */ void TextureAtlas::init(int pageSize) { pageSize_ = pageSize; initialized_ = true; E2D_LOG_INFO("TextureAtlas initialized with page size: {}", pageSize); } +/** + * @brief 添加纹理到图集 + * @param name 纹理名称 + * @param width 纹理宽度 + * @param height 纹理高度 + * @param pixels 像素数据 + * @return 添加成功返回true,失败返回false + * + * 尝试将纹理添加到现有页面,如空间不足则创建新页面 + */ bool TextureAtlas::addTexture(const std::string& name, int width, int height, const uint8_t* pixels) { if (!enabled_ || !initialized_) { @@ -200,10 +279,20 @@ bool TextureAtlas::addTexture(const std::string& name, int width, int height, return false; } +/** + * @brief 检查纹理是否已存在于图集中 + * @param name 纹理名称 + * @return 存在返回true,不存在返回false + */ bool TextureAtlas::contains(const std::string& name) const { return entryToPage_.find(name) != entryToPage_.end(); } +/** + * @brief 获取纹理所在的图集纹理 + * @param name 纹理名称 + * @return 找到返回纹理指针,未找到返回nullptr + */ const Texture* TextureAtlas::getAtlasTexture(const std::string& name) const { auto it = entryToPage_.find(name); if (it != entryToPage_.end()) { @@ -212,6 +301,11 @@ const Texture* TextureAtlas::getAtlasTexture(const std::string& name) const { return nullptr; } +/** + * @brief 获取纹理在图集中的UV坐标矩形 + * @param name 纹理名称 + * @return UV坐标矩形,未找到返回默认值 + */ Rect TextureAtlas::getUVRect(const std::string& name) const { auto it = entryToPage_.find(name); if (it != entryToPage_.end()) { @@ -223,6 +317,11 @@ Rect TextureAtlas::getUVRect(const std::string& name) const { return Rect(0, 0, 1, 1); // 默认 UV } +/** + * @brief 获取纹理的原始尺寸 + * @param name 纹理名称 + * @return 原始尺寸,未找到返回零向量 + */ Vec2 TextureAtlas::getOriginalSize(const std::string& name) const { auto it = entryToPage_.find(name); if (it != entryToPage_.end()) { @@ -234,6 +333,12 @@ Vec2 TextureAtlas::getOriginalSize(const std::string& name) const { return Vec2(0, 0); } +/** + * @brief 获取总使用率 + * @return 所有页面的平均使用率 + * + * 计算所有页面的平均空间使用率 + */ float TextureAtlas::getTotalUsageRatio() const { if (pages_.empty()) { return 0.0f; @@ -246,6 +351,11 @@ float TextureAtlas::getTotalUsageRatio() const { return total / pages_.size(); } +/** + * @brief 清空图集 + * + * 移除所有页面和条目映射 + */ void TextureAtlas::clear() { pages_.clear(); entryToPage_.clear(); @@ -253,11 +363,17 @@ void TextureAtlas::clear() { } // ============================================================================ -// TextureAtlasManager 单例实现 +// TextureAtlasMgr 单例实现 // ============================================================================ -TextureAtlasManager& TextureAtlasManager::getInstance() { - static TextureAtlasManager instance; +/** + * @brief 获取TextureAtlasMgr单例实例 + * @return TextureAtlasMgr单例的引用 + * + * 使用静态局部变量实现线程安全的单例模式 + */ +TextureAtlasMgr& TextureAtlasMgr::get() { + static TextureAtlasMgr instance; return instance; } diff --git a/Extra2D/src/graphics/texture_pool.cpp b/Extra2D/src/graphics/texture_pool.cpp index e219128..f5eb4dc 100644 --- a/Extra2D/src/graphics/texture_pool.cpp +++ b/Extra2D/src/graphics/texture_pool.cpp @@ -13,6 +13,8 @@ namespace extra2d { /** * @brief 默认构造函数 + * + * 创建一个未初始化的纹理池 */ TexturePool::TexturePool() : scene_(nullptr) @@ -27,6 +29,8 @@ TexturePool::TexturePool() * @brief 构造函数 * @param scene 场景指针 * @param maxMemoryUsage 最大内存使用量(0 表示无限制) + * + * 创建一个指定场景和内存限制的纹理池 */ TexturePool::TexturePool(Scene* scene, size_t maxMemoryUsage) : scene_(scene) @@ -42,6 +46,8 @@ TexturePool::TexturePool(Scene* scene, size_t maxMemoryUsage) * @brief 初始化纹理池 * @param scene 场景指针 * @param maxMemoryUsage 最大内存使用量(0 表示无限制) + * + * 设置纹理池的场景和内存限制 */ void TexturePool::init(Scene* scene, size_t maxMemoryUsage) { scene_ = scene; @@ -51,6 +57,8 @@ void TexturePool::init(Scene* scene, size_t maxMemoryUsage) { /** * @brief 析构函数 + * + * 清理纹理池并释放所有资源 */ TexturePool::~TexturePool() { clear(); @@ -66,6 +74,8 @@ TexturePool::~TexturePool() { * @param path 文件路径 * @param options 加载选项 * @return 纹理引用 + * + * 加载完整纹理文件到纹理池 */ TextureRef TexturePool::load(const std::string& path, const TextureLoadOptions& options) { return load(path, Rect::Zero(), options); @@ -77,6 +87,8 @@ TextureRef TexturePool::load(const std::string& path, const TextureLoadOptions& * @param region 纹理区域 * @param options 加载选项 * @return 纹理引用 + * + * 加载纹理文件的指定区域到纹理池 */ TextureRef TexturePool::load(const std::string& path, const Rect& region, const TextureLoadOptions& options) { @@ -157,6 +169,8 @@ TextureRef TexturePool::load(const std::string& path, const Rect& region, * @param channels 通道数 * @param key 缓存键 * @return 纹理引用 + * + * 从内存中的像素数据创建纹理并加入纹理池 */ TextureRef TexturePool::loadFromMemory(const uint8_t* data, int width, int height, int channels, const std::string& key) { @@ -226,6 +240,8 @@ TextureRef TexturePool::loadFromMemory(const uint8_t* data, int width, int heigh * @param path 文件路径 * @param options 加载选项 * @return 纹理引用 + * + * 如果纹理已缓存则返回缓存,否则加载纹理 */ TextureRef TexturePool::getOrLoad(const std::string& path, const TextureLoadOptions& options) { return getOrLoad(path, Rect::Zero(), options); @@ -237,6 +253,8 @@ TextureRef TexturePool::getOrLoad(const std::string& path, const TextureLoadOpti * @param region 纹理区域 * @param options 加载选项 * @return 纹理引用 + * + * 如果纹理区域已缓存则返回缓存,否则加载纹理区域 */ TextureRef TexturePool::getOrLoad(const std::string& path, const Rect& region, const TextureLoadOptions& options) { @@ -307,6 +325,8 @@ TextureRef TexturePool::getOrLoad(const std::string& path, const Rect& region, * @brief 增加引用计数 * @param key 纹理键 * @return 是否成功 + * + * 增加指定纹理的引用计数 */ bool TexturePool::addRef(const TextureKey& key) { std::lock_guard lock(mutex_); @@ -324,6 +344,8 @@ bool TexturePool::addRef(const TextureKey& key) { * @brief 减少引用计数 * @param key 纹理键 * @return 减少后的引用计数 + * + * 减少指定纹理的引用计数并返回新值 */ uint32_t TexturePool::release(const TextureKey& key) { std::lock_guard lock(mutex_); @@ -340,6 +362,8 @@ uint32_t TexturePool::release(const TextureKey& key) { * @brief 获取引用计数 * @param key 纹理键 * @return 引用计数 + * + * 获取指定纹理的当前引用计数 */ uint32_t TexturePool::getRefCount(const TextureKey& key) const { std::lock_guard lock(mutex_); @@ -359,6 +383,8 @@ uint32_t TexturePool::getRefCount(const TextureKey& key) const { * @brief 检查纹理是否已缓存 * @param key 纹理键 * @return 是否已缓存 + * + * 检查指定纹理是否存在于缓存中 */ bool TexturePool::isCached(const TextureKey& key) const { std::lock_guard lock(mutex_); @@ -369,6 +395,8 @@ bool TexturePool::isCached(const TextureKey& key) const { * @brief 从缓存中移除纹理 * @param key 纹理键 * @return 是否成功 + * + * 从缓存中移除指定的纹理 */ bool TexturePool::removeFromCache(const TextureKey& key) { std::lock_guard lock(mutex_); @@ -386,6 +414,8 @@ bool TexturePool::removeFromCache(const TextureKey& key) { /** * @brief 垃圾回收(移除引用计数为 0 的纹理) * @return 移除的纹理数量 + * + * 清理所有引用计数为0的纹理,释放内存 */ size_t TexturePool::collectGarbage() { std::lock_guard lock(mutex_); @@ -410,6 +440,8 @@ size_t TexturePool::collectGarbage() { /** * @brief 清空所有缓存 + * + * 移除纹理池中的所有纹理 */ void TexturePool::clear() { std::lock_guard lock(mutex_); @@ -427,6 +459,8 @@ void TexturePool::clear() { /** * @brief 获取当前内存使用量 * @return 内存使用量(字节) + * + * 返回纹理池当前的内存使用量 */ size_t TexturePool::getMemoryUsage() const { std::lock_guard lock(mutex_); @@ -436,6 +470,8 @@ size_t TexturePool::getMemoryUsage() const { /** * @brief 设置最大内存使用量 * @param maxMemory 最大内存使用量(0 表示无限制) + * + * 设置纹理池的内存上限,如果当前使用量超过新上限则执行淘汰 */ void TexturePool::setMaxMemoryUsage(size_t maxMemory) { std::lock_guard lock(mutex_); @@ -453,6 +489,8 @@ void TexturePool::setMaxMemoryUsage(size_t maxMemory) { * @brief 执行 LRU 淘汰 * @param targetMemory 目标内存使用量 * @return 淘汰的纹理数量 + * + * 根据LRU算法淘汰最少使用的纹理以达到目标内存使用量 */ size_t TexturePool::evictLRU(size_t targetMemory) { // 注意:调用者应该已持有锁 @@ -506,7 +544,9 @@ size_t TexturePool::evictLRU(size_t targetMemory) { /** * @brief 获取统计信息 - * @return 统计信息 + * @return 统计信息结构体 + * + * 返回纹理池的统计信息,包括纹理数量、内存使用、缓存命中率等 */ TexturePool::Stats TexturePool::getStats() const { std::lock_guard lock(mutex_); @@ -524,6 +564,8 @@ TexturePool::Stats TexturePool::getStats() const { /** * @brief 重置统计信息 + * + * 清零缓存命中、未命中和淘汰计数 */ void TexturePool::resetStats() { cacheHits_.store(0, std::memory_order_relaxed); @@ -539,6 +581,8 @@ void TexturePool::resetStats() { * @brief 计算纹理内存大小 * @param texture 纹理对象 * @return 内存大小(字节) + * + * 根据纹理的尺寸、通道数和像素格式计算内存占用 */ size_t TexturePool::calculateTextureMemory(const Texture* texture) { if (!texture) { @@ -587,6 +631,8 @@ size_t TexturePool::calculateTextureMemory(const Texture* texture) { /** * @brief 检查是否需要淘汰 * @return 是否需要淘汰 + * + * 检查当前内存使用量是否超过限制 */ bool TexturePool::needsEviction() const { return maxMemoryUsage_ > 0 && currentMemoryUsage_ > maxMemoryUsage_; @@ -594,6 +640,8 @@ bool TexturePool::needsEviction() const { /** * @brief 尝试自动淘汰 + * + * 如果内存使用量超过限制,执行LRU淘汰 */ void TexturePool::tryAutoEvict() { if (needsEviction()) { diff --git a/Extra2D/src/graphics/viewport_adapter.cpp b/Extra2D/src/graphics/viewport_adapter.cpp index 14e5738..f2c4c01 100644 --- a/Extra2D/src/graphics/viewport_adapter.cpp +++ b/Extra2D/src/graphics/viewport_adapter.cpp @@ -4,38 +4,88 @@ namespace extra2d { +/** + * @brief 默认构造函数 + * + * 创建一个未配置的视口适配器 + */ ViewportAdapter::ViewportAdapter() = default; +/** + * @brief 构造函数 + * @param logicWidth 逻辑宽度 + * @param logicHeight 逻辑高度 + * + * 创建一个指定逻辑尺寸的视口适配器 + */ ViewportAdapter::ViewportAdapter(float logicWidth, float logicHeight) { config_.logicWidth = logicWidth; config_.logicHeight = logicHeight; } +/** + * @brief 设置视口配置 + * @param config 视口配置 + * + * 设置完整的视口配置并标记矩阵为脏 + */ void ViewportAdapter::setConfig(const ViewportConfig &config) { config_ = config; matrixDirty_ = true; } +/** + * @brief 设置逻辑尺寸 + * @param width 逻辑宽度 + * @param height 逻辑高度 + * + * 设置视口的逻辑尺寸并标记矩阵为脏 + */ void ViewportAdapter::setLogicSize(float width, float height) { config_.logicWidth = width; config_.logicHeight = height; matrixDirty_ = true; } +/** + * @brief 设置视口模式 + * @param mode 视口模式 + * + * 设置视口适配模式(宽高比、拉伸、居中等) + */ void ViewportAdapter::setMode(ViewportMode mode) { config_.mode = mode; matrixDirty_ = true; } +/** + * @brief 设置黑边位置 + * @param position 黑边位置 + * + * 设置黑边相对于视口的位置 + */ void ViewportAdapter::setLetterboxPosition(LetterboxPosition position) { config_.letterboxPosition = position; matrixDirty_ = true; } +/** + * @brief 设置黑边颜色 + * @param color 黑边颜色 + * + * 设置黑边区域的填充颜色 + */ void ViewportAdapter::setLetterboxColor(const Color &color) { config_.letterboxColor = color; } +/** + * @brief 更新视口适配 + * @param screenWidth 屏幕宽度 + * @param screenHeight 屏幕高度 + * + * 根据屏幕尺寸和配置计算视口参数 + */ void ViewportAdapter::update(int screenWidth, int screenHeight) { if (screenWidth_ == screenWidth && screenHeight_ == screenHeight && !matrixDirty_) { @@ -68,6 +118,11 @@ void ViewportAdapter::update(int screenWidth, int screenHeight) { } } +/** + * @brief 计算宽高比适配模式 + * + * 保持逻辑宽高比,根据屏幕尺寸计算缩放和偏移 + */ void ViewportAdapter::calculateAspectRatio() { if (config_.logicHeight <= 0.0f || screenHeight_ <= 0) { result_ = ViewportResult(); @@ -104,6 +159,11 @@ void ViewportAdapter::calculateAspectRatio() { calculateLetterbox(); } +/** + * @brief 计算拉伸模式 + * + * 拉伸逻辑视口以填满整个屏幕 + */ void ViewportAdapter::calculateStretch() { result_.scaleX = static_cast(screenWidth_) / config_.logicWidth; result_.scaleY = static_cast(screenHeight_) / config_.logicHeight; @@ -117,6 +177,11 @@ void ViewportAdapter::calculateStretch() { result_.hasLetterbox = false; } +/** + * @brief 计算居中模式 + * + * 将逻辑视口居中显示,可选自动缩放 + */ void ViewportAdapter::calculateCenter() { float displayWidth = config_.logicWidth; float displayHeight = config_.logicHeight; @@ -155,6 +220,11 @@ void ViewportAdapter::calculateCenter() { calculateLetterbox(); } +/** + * @brief 计算自定义模式 + * + * 使用自定义缩放和偏移参数 + */ void ViewportAdapter::calculateCustom() { result_.scaleX = config_.customScale; result_.scaleY = config_.customScale; @@ -176,6 +246,11 @@ void ViewportAdapter::calculateCustom() { calculateLetterbox(); } +/** + * @brief 计算黑边区域 + * + * 根据视口偏移计算上下左右黑边矩形 + */ void ViewportAdapter::calculateLetterbox() { result_.hasLetterbox = false; @@ -201,6 +276,13 @@ void ViewportAdapter::calculateLetterbox() { } } +/** + * @brief 应用黑边位置 + * @param extraWidth 额外宽度 + * @param extraHeight 额外高度 + * + * 根据配置调整视口偏移以实现不同的黑边位置 + */ void ViewportAdapter::applyLetterboxPosition(float extraWidth, float extraHeight) { if (extraWidth <= 0.0f && extraHeight <= 0.0f) { @@ -251,25 +333,57 @@ void ViewportAdapter::applyLetterboxPosition(float extraWidth, result_.viewport.origin = result_.offset; } +/** + * @brief 将屏幕坐标转换为逻辑坐标 + * @param screenPos 屏幕坐标 + * @return 逻辑坐标 + * + * 根据当前缩放和偏移计算对应的逻辑坐标 + */ Vec2 ViewportAdapter::screenToLogic(const Vec2 &screenPos) const { return Vec2((screenPos.x - result_.offset.x) / result_.scaleX, (screenPos.y - result_.offset.y) / result_.scaleY); } +/** + * @brief 将逻辑坐标转换为屏幕坐标 + * @param logicPos 逻辑坐标 + * @return 屏幕坐标 + * + * 根据当前缩放和偏移计算对应的屏幕坐标 + */ Vec2 ViewportAdapter::logicToScreen(const Vec2 &logicPos) const { return Vec2(logicPos.x * result_.scaleX + result_.offset.x, logicPos.y * result_.scaleY + result_.offset.y); } +/** + * @brief 将屏幕坐标转换为逻辑坐标 + * @param x 屏幕X坐标 + * @param y 屏幕Y坐标 + * @return 逻辑坐标 + */ Vec2 ViewportAdapter::screenToLogic(float x, float y) const { return screenToLogic(Vec2(x, y)); } +/** + * @brief 将逻辑坐标转换为屏幕坐标 + * @param x 逻辑X坐标 + * @param y 逻辑Y坐标 + * @return 屏幕坐标 + */ Vec2 ViewportAdapter::logicToScreen(float x, float y) const { return logicToScreen(Vec2(x, y)); } -glm::mat4 ViewportAdapter::getViewportMatrix() const { +/** + * @brief 获取视口变换矩阵 + * @return 4x4变换矩阵 + * + * 返回用于将逻辑坐标转换为屏幕坐标的变换矩阵 + */ +glm::mat4 ViewportAdapter::getMatrix() const { if (matrixDirty_) { viewportMatrix_ = glm::mat4(1.0f); viewportMatrix_ = glm::translate(viewportMatrix_, @@ -281,18 +395,34 @@ glm::mat4 ViewportAdapter::getViewportMatrix() const { return viewportMatrix_; } -glm::mat4 ViewportAdapter::getInverseViewportMatrix() const { +/** + * @brief 获取视口逆变换矩阵 + * @return 4x4逆变换矩阵 + * + * 返回用于将屏幕坐标转换为逻辑坐标的逆变换矩阵 + */ +glm::mat4 ViewportAdapter::getInvMatrix() const { if (matrixDirty_) { - getViewportMatrix(); + getMatrix(); } inverseViewportMatrix_ = glm::inverse(viewportMatrix_); return inverseViewportMatrix_; } +/** + * @brief 检查屏幕坐标是否在视口内 + * @param screenPos 屏幕坐标 + * @return 在视口内返回true,否则返回false + */ bool ViewportAdapter::isInViewport(const Vec2 &screenPos) const { return result_.viewport.containsPoint(screenPos); } +/** + * @brief 检查屏幕坐标是否在黑边区域内 + * @param screenPos 屏幕坐标 + * @return 在黑边区域内返回true,否则返回false + */ bool ViewportAdapter::isInLetterbox(const Vec2 &screenPos) const { if (!result_.hasLetterbox) { return false; diff --git a/Extra2D/src/graphics/vram_manager.cpp b/Extra2D/src/graphics/vram_manager.cpp index 97dfae4..93994c0 100644 --- a/Extra2D/src/graphics/vram_manager.cpp +++ b/Extra2D/src/graphics/vram_manager.cpp @@ -7,17 +7,34 @@ namespace extra2d { // Switch 推荐 VRAM 预算 ~400MB static constexpr size_t DEFAULT_VRAM_BUDGET = 400 * 1024 * 1024; -VRAMManager::VRAMManager() +/** + * @brief 默认构造函数 + * + * 初始化VRAM管理器,设置默认预算为400MB + */ +VRAMMgr::VRAMMgr() : textureVRAM_(0), bufferVRAM_(0), vramBudget_(DEFAULT_VRAM_BUDGET), textureAllocCount_(0), textureFreeCount_(0), bufferAllocCount_(0), bufferFreeCount_(0), peakTextureVRAM_(0), peakBufferVRAM_(0) {} -VRAMManager &VRAMManager::getInstance() { - static VRAMManager instance; +/** + * @brief 获取VRAMMgr单例实例 + * @return VRAMMgr单例的引用 + * + * 使用静态局部变量实现线程安全的单例模式 + */ +VRAMMgr &VRAMMgr::get() { + static VRAMMgr instance; return instance; } -void VRAMManager::allocTexture(size_t size) { +/** + * @brief 分配纹理VRAM + * @param size 分配的字节数 + * + * 增加纹理VRAM使用量并更新峰值,如果超出预算则输出警告 + */ +void VRAMMgr::allocTexture(size_t size) { std::lock_guard lock(mutex_); textureVRAM_ += size; textureAllocCount_++; @@ -29,7 +46,13 @@ void VRAMManager::allocTexture(size_t size) { } } -void VRAMManager::freeTexture(size_t size) { +/** + * @brief 释放纹理VRAM + * @param size 释放的字节数 + * + * 减少纹理VRAM使用量 + */ +void VRAMMgr::freeTexture(size_t size) { std::lock_guard lock(mutex_); if (size <= textureVRAM_) { textureVRAM_ -= size; @@ -39,7 +62,13 @@ void VRAMManager::freeTexture(size_t size) { textureFreeCount_++; } -void VRAMManager::allocBuffer(size_t size) { +/** + * @brief 分配缓冲VRAM + * @param size 分配的字节数 + * + * 增加缓冲VRAM使用量并更新峰值,如果超出预算则输出警告 + */ +void VRAMMgr::allocBuffer(size_t size) { std::lock_guard lock(mutex_); bufferVRAM_ += size; bufferAllocCount_++; @@ -51,7 +80,13 @@ void VRAMManager::allocBuffer(size_t size) { } } -void VRAMManager::freeBuffer(size_t size) { +/** + * @brief 释放缓冲VRAM + * @param size 释放的字节数 + * + * 减少缓冲VRAM使用量 + */ +void VRAMMgr::freeBuffer(size_t size) { std::lock_guard lock(mutex_); if (size <= bufferVRAM_) { bufferVRAM_ -= size; @@ -61,28 +96,67 @@ void VRAMManager::freeBuffer(size_t size) { bufferFreeCount_++; } -size_t VRAMManager::getUsedVRAM() const { return textureVRAM_ + bufferVRAM_; } +/** + * @brief 获取总VRAM使用量 + * @return 总使用字节数 + * + * 返回纹理和缓冲VRAM使用量的总和 + */ +size_t VRAMMgr::getUsedVRAM() const { return textureVRAM_ + bufferVRAM_; } -size_t VRAMManager::getTextureVRAM() const { return textureVRAM_; } +/** + * @brief 获取纹理VRAM使用量 + * @return 纹理使用字节数 + */ +size_t VRAMMgr::getTextureVRAM() const { return textureVRAM_; } -size_t VRAMManager::getBufferVRAM() const { return bufferVRAM_; } +/** + * @brief 获取缓冲VRAM使用量 + * @return 缓冲使用字节数 + */ +size_t VRAMMgr::getBufferVRAM() const { return bufferVRAM_; } -size_t VRAMManager::getAvailableVRAM() const { +/** + * @brief 获取可用VRAM + * @return 可用字节数 + * + * 返回预算内剩余的VRAM空间 + */ +size_t VRAMMgr::getAvailableVRAM() const { size_t used = getUsedVRAM(); return (used < vramBudget_) ? (vramBudget_ - used) : 0; } -void VRAMManager::setVRAMBudget(size_t budget) { +/** + * @brief 设置VRAM预算 + * @param budget 预算字节数 + * + * 设置VRAM使用上限 + */ +void VRAMMgr::setVRAMBudget(size_t budget) { std::lock_guard lock(mutex_); vramBudget_ = budget; E2D_LOG_INFO("VRAM budget set to {} MB", budget / (1024 * 1024)); } -size_t VRAMManager::getVRAMBudget() const { return vramBudget_; } +/** + * @brief 获取VRAM预算 + * @return 预算字节数 + */ +size_t VRAMMgr::getVRAMBudget() const { return vramBudget_; } -bool VRAMManager::isOverBudget() const { return getUsedVRAM() > vramBudget_; } +/** + * @brief 检查是否超出预算 + * @return 超出预算返回true,否则返回false + */ +bool VRAMMgr::isOverBudget() const { return getUsedVRAM() > vramBudget_; } -void VRAMManager::printStats() const { +/** + * @brief 打印VRAM统计信息 + * + * 输出纹理和缓冲的VRAM使用情况、峰值和分配/释放次数 + */ +void VRAMMgr::printStats() const { std::lock_guard lock(mutex_); E2D_LOG_INFO("=== VRAM Stats ==="); E2D_LOG_INFO(" Texture VRAM: {} MB (peak: {} MB)", @@ -98,7 +172,12 @@ void VRAMManager::printStats() const { bufferFreeCount_); } -void VRAMManager::reset() { +/** + * @brief 重置所有统计信息 + * + * 清零所有VRAM计数器和峰值记录 + */ +void VRAMMgr::reset() { std::lock_guard lock(mutex_); textureVRAM_ = 0; bufferVRAM_ = 0; diff --git a/Extra2D/src/platform/input.cpp b/Extra2D/src/platform/input.cpp index aa90808..48972b1 100644 --- a/Extra2D/src/platform/input.cpp +++ b/Extra2D/src/platform/input.cpp @@ -5,6 +5,12 @@ namespace extra2d { +/** + * @brief 默认构造函数 + * + * 初始化输入系统的所有成员变量为默认值,包括控制器指针、摇杆状态、 + * 鼠标状态、触摸状态等,并将所有按键和按钮状态数组初始化为false。 + */ Input::Input() : controller_(nullptr), leftStickX_(0.0f), leftStickY_(0.0f), @@ -13,7 +19,6 @@ Input::Input() touching_(false), prevTouching_(false), touchCount_(0), viewportAdapter_(nullptr) { - // 初始化所有状态数组 keysDown_.fill(false); prevKeysDown_.fill(false); buttonsDown_.fill(false); @@ -22,10 +27,19 @@ Input::Input() prevMouseButtonsDown_.fill(false); } +/** + * @brief 析构函数 + * + * 自动调用shutdown()方法释放所有资源。 + */ Input::~Input() { shutdown(); } +/** + * @brief 初始化输入系统 + * + * 打开第一个可用的游戏控制器,并在PC端获取初始鼠标位置。 + */ void Input::init() { - // 打开第一个可用的游戏控制器 for (int i = 0; i < SDL_NumJoysticks(); ++i) { if (SDL_IsGameController(i)) { controller_ = SDL_GameControllerOpen(i); @@ -41,7 +55,6 @@ void Input::init() { E2D_LOG_WARN("No game controller found"); } - // PC 端获取初始鼠标状态 #ifndef PLATFORM_SWITCH int mouseX, mouseY; SDL_GetMouseState(&mouseX, &mouseY); @@ -50,6 +63,11 @@ void Input::init() { #endif } +/** + * @brief 关闭输入系统 + * + * 关闭并释放游戏控制器资源。 + */ void Input::shutdown() { if (controller_) { SDL_GameControllerClose(controller_); @@ -57,8 +75,12 @@ void Input::shutdown() { } } +/** + * @brief 更新输入状态 + * + * 保存上一帧的输入状态,并更新键盘、鼠标、手柄和触摸设备的当前状态。 + */ void Input::update() { - // 保存上一帧状态 prevKeysDown_ = keysDown_; prevButtonsDown_ = buttonsDown_; prevMouseButtonsDown_ = mouseButtonsDown_; @@ -67,50 +89,56 @@ void Input::update() { prevTouching_ = touching_; prevTouchPosition_ = touchPosition_; - // 更新各输入设备状态 updateKeyboard(); updateMouse(); updateGamepad(); updateTouch(); } +/** + * @brief 更新键盘状态 + * + * 从SDL获取当前键盘状态并更新按键数组。 + */ void Input::updateKeyboard() { - // 获取当前键盘状态 const Uint8* state = SDL_GetKeyboardState(nullptr); for (int i = 0; i < MAX_KEYS; ++i) { keysDown_[i] = state[i] != 0; } } +/** + * @brief 更新鼠标状态 + * + * 获取当前鼠标位置和按钮状态。仅在非Switch平台执行。 + */ void Input::updateMouse() { #ifndef PLATFORM_SWITCH - // 更新鼠标位置 int mouseX, mouseY; Uint32 buttonState = SDL_GetMouseState(&mouseX, &mouseY); mousePosition_ = Vec2(static_cast(mouseX), static_cast(mouseY)); - // 更新鼠标按钮状态 mouseButtonsDown_[0] = (buttonState & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; mouseButtonsDown_[1] = (buttonState & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0; mouseButtonsDown_[2] = (buttonState & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0; mouseButtonsDown_[3] = (buttonState & SDL_BUTTON(SDL_BUTTON_X1)) != 0; mouseButtonsDown_[4] = (buttonState & SDL_BUTTON(SDL_BUTTON_X2)) != 0; - - // 处理鼠标滚轮事件(需要在事件循环中处理,这里简化处理) - // 实际滚轮值通过 SDL_MOUSEWHEEL 事件更新 #endif } +/** + * @brief 更新手柄状态 + * + * 读取手柄按钮状态和摇杆位置,摇杆值归一化到-1.0~1.0范围。 + */ void Input::updateGamepad() { if (controller_) { - // 更新按钮状态 for (int i = 0; i < MAX_BUTTONS; ++i) { buttonsDown_[i] = SDL_GameControllerGetButton( controller_, static_cast(i)) != 0; } - // 读取摇杆(归一化到 -1.0 ~ 1.0) leftStickX_ = static_cast(SDL_GameControllerGetAxis( controller_, SDL_CONTROLLER_AXIS_LEFTX)) / 32767.0f; leftStickY_ = static_cast(SDL_GameControllerGetAxis( @@ -125,9 +153,14 @@ void Input::updateGamepad() { } } +/** + * @brief 更新触摸状态 + * + * 获取触摸设备状态,将归一化坐标转换为像素坐标。 + * Switch平台使用原生触摸屏支持,PC端支持可选触摸设备。 + */ void Input::updateTouch() { #ifdef PLATFORM_SWITCH - // Switch 原生触摸屏支持 SDL_TouchID touchId = SDL_GetTouchDevice(0); if (touchId != 0) { touchCount_ = SDL_GetNumTouchFingers(touchId); @@ -135,7 +168,6 @@ void Input::updateTouch() { SDL_Finger *finger = SDL_GetTouchFinger(touchId, 0); if (finger) { touching_ = true; - // SDL 触摸坐标是归一化 0.0~1.0,转换为像素坐标 touchPosition_ = Vec2(finger->x * 1280.0f, finger->y * 720.0f); } else { touching_ = false; @@ -148,7 +180,6 @@ void Input::updateTouch() { touching_ = false; } #else - // PC 端:触摸屏可选支持(如果有触摸设备) SDL_TouchID touchId = SDL_GetTouchDevice(0); if (touchId != 0) { touchCount_ = SDL_GetNumTouchFingers(touchId); @@ -156,7 +187,6 @@ void Input::updateTouch() { SDL_Finger *finger = SDL_GetTouchFinger(touchId, 0); if (finger) { touching_ = true; - // PC 端需要根据窗口大小转换坐标 int windowWidth, windowHeight; SDL_Window* window = SDL_GL_GetCurrentWindow(); if (window) { @@ -182,9 +212,16 @@ void Input::updateTouch() { // 键盘输入 // ============================================================================ +/** + * @brief 将键盘按键映射到手柄按钮 + * + * 提供键盘到手柄按钮的映射,用于在Switch平台模拟键盘输入。 + * + * @param keyCode 键盘按键码 + * @return 对应的SDL手柄按钮枚举值 + */ SDL_GameControllerButton Input::mapKeyToButton(int keyCode) const { switch (keyCode) { - // 方向键 → DPad case Key::Up: return SDL_CONTROLLER_BUTTON_DPAD_UP; case Key::Down: @@ -194,7 +231,6 @@ SDL_GameControllerButton Input::mapKeyToButton(int keyCode) const { case Key::Right: return SDL_CONTROLLER_BUTTON_DPAD_RIGHT; - // WASD → 也映射到 DPad case Key::W: return SDL_CONTROLLER_BUTTON_DPAD_UP; case Key::S: @@ -204,7 +240,6 @@ SDL_GameControllerButton Input::mapKeyToButton(int keyCode) const { case Key::D: return SDL_CONTROLLER_BUTTON_DPAD_RIGHT; - // 常用键 → 手柄按钮 case Key::Z: return SDL_CONTROLLER_BUTTON_B; case Key::X: @@ -220,13 +255,11 @@ SDL_GameControllerButton Input::mapKeyToButton(int keyCode) const { case Key::Escape: return SDL_CONTROLLER_BUTTON_START; - // 肩键 case Key::Q: return SDL_CONTROLLER_BUTTON_LEFTSHOULDER; case Key::E: return SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; - // Start/Select case Key::Tab: return SDL_CONTROLLER_BUTTON_BACK; case Key::Backspace: @@ -237,15 +270,22 @@ SDL_GameControllerButton Input::mapKeyToButton(int keyCode) const { } } +/** + * @brief 检查按键是否被按下 + * + * 检测指定按键当前是否处于按下状态。 + * Switch平台映射到手柄按钮,PC端直接读取键盘状态。 + * + * @param keyCode 键盘按键码 + * @return 按键按下返回true,否则返回false + */ bool Input::isKeyDown(int keyCode) const { #ifdef PLATFORM_SWITCH - // Switch: 映射到手柄按钮 SDL_GameControllerButton button = mapKeyToButton(keyCode); if (button == SDL_CONTROLLER_BUTTON_INVALID) return false; return buttonsDown_[button]; #else - // PC: 直接使用键盘扫描码 SDL_Scancode scancode = SDL_GetScancodeFromKey(keyCode); if (scancode >= 0 && scancode < MAX_KEYS) { return keysDown_[scancode]; @@ -254,6 +294,14 @@ bool Input::isKeyDown(int keyCode) const { #endif } +/** + * @brief 检查按键是否刚被按下 + * + * 检测指定按键是否在本帧刚被按下(之前未按下,当前按下)。 + * + * @param keyCode 键盘按键码 + * @return 按键刚按下返回true,否则返回false + */ bool Input::isKeyPressed(int keyCode) const { #ifdef PLATFORM_SWITCH SDL_GameControllerButton button = mapKeyToButton(keyCode); @@ -269,6 +317,14 @@ bool Input::isKeyPressed(int keyCode) const { #endif } +/** + * @brief 检查按键是否刚被释放 + * + * 检测指定按键是否在本帧刚被释放(之前按下,当前未按下)。 + * + * @param keyCode 键盘按键码 + * @return 按键刚释放返回true,否则返回false + */ bool Input::isKeyReleased(int keyCode) const { #ifdef PLATFORM_SWITCH SDL_GameControllerButton button = mapKeyToButton(keyCode); @@ -288,39 +344,74 @@ bool Input::isKeyReleased(int keyCode) const { // 手柄按钮 // ============================================================================ +/** + * @brief 检查手柄按钮是否被按下 + * + * @param button 手柄按钮索引 + * @return 按钮按下返回true,否则返回false + */ bool Input::isButtonDown(int button) const { if (button < 0 || button >= MAX_BUTTONS) return false; return buttonsDown_[button]; } +/** + * @brief 检查手柄按钮是否刚被按下 + * + * @param button 手柄按钮索引 + * @return 按钮刚按下返回true,否则返回false + */ bool Input::isButtonPressed(int button) const { if (button < 0 || button >= MAX_BUTTONS) return false; return buttonsDown_[button] && !prevButtonsDown_[button]; } +/** + * @brief 检查手柄按钮是否刚被释放 + * + * @param button 手柄按钮索引 + * @return 按钮刚释放返回true,否则返回false + */ bool Input::isButtonReleased(int button) const { if (button < 0 || button >= MAX_BUTTONS) return false; return !buttonsDown_[button] && prevButtonsDown_[button]; } +/** + * @brief 获取左摇杆位置 + * + * @return 包含X和Y轴值的二维向量,范围-1.0~1.0 + */ Vec2 Input::getLeftStick() const { return Vec2(leftStickX_, leftStickY_); } +/** + * @brief 获取右摇杆位置 + * + * @return 包含X和Y轴值的二维向量,范围-1.0~1.0 + */ Vec2 Input::getRightStick() const { return Vec2(rightStickX_, rightStickY_); } // ============================================================================ // 鼠标输入 // ============================================================================ +/** + * @brief 检查鼠标按钮是否被按下 + * + * Switch平台左键映射到触摸,右键映射到A键。 + * + * @param button 鼠标按钮枚举值 + * @return 按钮按下返回true,否则返回false + */ bool Input::isMouseDown(MouseButton button) const { int index = static_cast(button); if (index < 0 || index >= 8) return false; #ifdef PLATFORM_SWITCH - // Switch: 左键映射到触摸,右键映射到 A 键 if (button == MouseButton::Left) { return touching_; } @@ -329,11 +420,16 @@ bool Input::isMouseDown(MouseButton button) const { } return false; #else - // PC: 直接使用鼠标按钮 return mouseButtonsDown_[index]; #endif } +/** + * @brief 检查鼠标按钮是否刚被按下 + * + * @param button 鼠标按钮枚举值 + * @return 按钮刚按下返回true,否则返回false + */ bool Input::isMousePressed(MouseButton button) const { int index = static_cast(button); if (index < 0 || index >= 8) @@ -353,6 +449,12 @@ bool Input::isMousePressed(MouseButton button) const { #endif } +/** + * @brief 检查鼠标按钮是否刚被释放 + * + * @param button 鼠标按钮枚举值 + * @return 按钮刚释放返回true,否则返回false + */ bool Input::isMouseReleased(MouseButton button) const { int index = static_cast(button); if (index < 0 || index >= 8) @@ -372,6 +474,13 @@ bool Input::isMouseReleased(MouseButton button) const { #endif } +/** + * @brief 获取鼠标位置 + * + * Switch平台返回触摸位置,PC端返回鼠标位置。 + * + * @return 包含X和Y坐标的二维向量(屏幕像素坐标) + */ Vec2 Input::getMousePosition() const { #ifdef PLATFORM_SWITCH return touchPosition_; @@ -380,6 +489,13 @@ Vec2 Input::getMousePosition() const { #endif } +/** + * @brief 获取鼠标移动增量 + * + * 计算当前帧与上一帧之间的鼠标位置差值。 + * + * @return 包含X和Y移动量的二维向量 + */ Vec2 Input::getMouseDelta() const { #ifdef PLATFORM_SWITCH if (touching_ && prevTouching_) { @@ -391,6 +507,13 @@ Vec2 Input::getMouseDelta() const { #endif } +/** + * @brief 设置鼠标位置 + * + * 将鼠标移动到指定的屏幕坐标位置。仅在PC端有效。 + * + * @param position 目标位置(屏幕像素坐标) + */ void Input::setMousePosition(const Vec2 &position) { #ifndef PLATFORM_SWITCH SDL_WarpMouseInWindow(SDL_GL_GetCurrentWindow(), @@ -401,6 +524,13 @@ void Input::setMousePosition(const Vec2 &position) { #endif } +/** + * @brief 设置鼠标光标可见性 + * + * 显示或隐藏鼠标光标。仅在PC端有效。 + * + * @param visible true显示光标,false隐藏光标 + */ void Input::setMouseVisible(bool visible) { #ifndef PLATFORM_SWITCH SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE); @@ -409,6 +539,13 @@ void Input::setMouseVisible(bool visible) { #endif } +/** + * @brief 设置鼠标锁定模式 + * + * 启用或禁用相对鼠标模式,用于第一人称视角控制等场景。 + * + * @param locked true锁定鼠标到窗口中心,false解锁 + */ void Input::setMouseLocked(bool locked) { #ifndef PLATFORM_SWITCH SDL_SetRelativeMouseMode(locked ? SDL_TRUE : SDL_FALSE); @@ -421,6 +558,13 @@ void Input::setMouseLocked(bool locked) { // 便捷方法 // ============================================================================ +/** + * @brief 检查是否有任意按键被按下 + * + * Switch平台检查手柄按钮,PC端检查键盘按键。 + * + * @return 有按键按下返回true,否则返回false + */ bool Input::isAnyKeyDown() const { #ifdef PLATFORM_SWITCH for (int i = 0; i < MAX_BUTTONS; ++i) { @@ -436,6 +580,13 @@ bool Input::isAnyKeyDown() const { return false; } +/** + * @brief 检查是否有任意鼠标按钮被按下 + * + * Switch平台检查触摸状态,PC端检查鼠标按钮。 + * + * @return 有按钮按下返回true,否则返回false + */ bool Input::isAnyMouseDown() const { #ifdef PLATFORM_SWITCH return touching_; @@ -452,11 +603,25 @@ bool Input::isAnyMouseDown() const { // 视口适配器 // ============================================================================ +/** + * @brief 设置视口适配器 + * + * 用于将屏幕坐标转换为逻辑坐标。 + * + * @param adapter 视口适配器指针 + */ void Input::setViewportAdapter(ViewportAdapter* adapter) { viewportAdapter_ = adapter; } -Vec2 Input::getMousePositionLogic() const { +/** + * @brief 获取逻辑坐标系的鼠标位置 + * + * 通过视口适配器将屏幕坐标转换为逻辑坐标。 + * + * @return 逻辑坐标系的鼠标位置 + */ +Vec2 Input::getMousePosLogic() const { Vec2 screenPos = getMousePosition(); if (viewportAdapter_) { return viewportAdapter_->screenToLogic(screenPos); @@ -464,7 +629,14 @@ Vec2 Input::getMousePositionLogic() const { return screenPos; } -Vec2 Input::getTouchPositionLogic() const { +/** + * @brief 获取逻辑坐标系的触摸位置 + * + * 通过视口适配器将屏幕坐标转换为逻辑坐标。 + * + * @return 逻辑坐标系的触摸位置 + */ +Vec2 Input::getTouchPosLogic() const { Vec2 screenPos = getTouchPosition(); if (viewportAdapter_) { return viewportAdapter_->screenToLogic(screenPos); @@ -472,6 +644,13 @@ Vec2 Input::getTouchPositionLogic() const { return screenPos; } +/** + * @brief 获取逻辑坐标系的鼠标移动增量 + * + * 根据视口缩放比例调整鼠标移动量。 + * + * @return 逻辑坐标系的鼠标移动增量 + */ Vec2 Input::getMouseDeltaLogic() const { Vec2 delta = getMouseDelta(); if (viewportAdapter_) { diff --git a/Extra2D/src/platform/window.cpp b/Extra2D/src/platform/window.cpp index a92ea8e..dbbc221 100644 --- a/Extra2D/src/platform/window.cpp +++ b/Extra2D/src/platform/window.cpp @@ -9,19 +9,38 @@ namespace extra2d { +/** + * @brief 默认构造函数 + * + * 初始化窗口的所有成员变量为默认值,包括SDL窗口指针、OpenGL上下文、 + * 光标数组、窗口尺寸、VSync状态等。 + */ Window::Window() : sdlWindow_(nullptr), glContext_(nullptr), currentCursor_(nullptr), width_(1280), height_(720), vsync_(true), shouldClose_(false), - fullscreen_(true), focused_(true), contentScaleX_(1.0f), contentScaleY_(1.0f), - enableDpiScale_(true), userData_(nullptr), eventQueue_(nullptr) { - // 初始化光标数组 - for (int i = 0; i < 9; ++i) { - sdlCursors_[i] = nullptr; - } + fullscreen_(true), focused_(true), contentScaleX_(1.0f), + contentScaleY_(1.0f), enableDpiScale_(true), userData_(nullptr), + eventQueue_(nullptr) { + for (int i = 0; i < 9; ++i) { + sdlCursors_[i] = nullptr; + } } +/** + * @brief 析构函数 + * + * 自动调用destroy()方法释放所有资源。 + */ Window::~Window() { destroy(); } +/** + * @brief 创建窗口 + * + * 根据配置参数创建SDL窗口和OpenGL ES上下文,初始化输入管理器和光标。 + * + * @param config 窗口配置参数,包含尺寸、标题、全屏模式等信息 + * @return 创建成功返回true,失败返回false + */ bool Window::create(const WindowConfig &config) { if (sdlWindow_ != nullptr) { E2D_LOG_WARN("Window already created"); @@ -34,17 +53,14 @@ bool Window::create(const WindowConfig &config) { fullscreen_ = config.fullscreen; enableDpiScale_ = config.enableDpiScale; - // 初始化 SDL2 + 创建窗口 + GL 上下文 if (!initSDL(config)) { E2D_LOG_ERROR("Failed to initialize SDL2"); return false; } - // 创建输入管理器 input_ = makeUnique(); input_->init(); - // 初始化光标 if (config.enableCursors) { initCursors(); } @@ -53,19 +69,26 @@ bool Window::create(const WindowConfig &config) { return true; } +/** + * @brief 初始化SDL库和OpenGL上下文 + * + * 执行SDL2全局初始化、设置OpenGL ES 3.2上下文属性、创建窗口、 + * 创建OpenGL上下文并加载GLES函数指针。 + * + * @param config 窗口配置参数 + * @return 初始化成功返回true,失败返回false + */ bool Window::initSDL(const WindowConfig &config) { - // SDL2 全局初始化(视频 + 游戏控制器 + 音频) - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER | SDL_INIT_AUDIO) != 0) { + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER | SDL_INIT_AUDIO) != + 0) { E2D_LOG_ERROR("SDL_Init failed: {}", SDL_GetError()); return false; } - // 设置 OpenGL ES 3.2 上下文属性 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, 2); - // 颜色/深度/模板缓冲配置 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); @@ -73,16 +96,11 @@ bool Window::initSDL(const WindowConfig &config) { SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - // 双缓冲 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - // 创建 SDL2 窗口 Uint32 windowFlags = SDL_WINDOW_OPENGL; - - // 根据配置设置窗口模式 + if (config.fullscreen) { - // Switch 平台使用 SDL_WINDOW_FULLSCREEN(固定分辨率) - // PC 平台使用 SDL_WINDOW_FULLSCREEN_DESKTOP(桌面全屏) if (config.fullscreenDesktop) { windowFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP; } else { @@ -92,8 +110,6 @@ bool Window::initSDL(const WindowConfig &config) { if (config.resizable) { windowFlags |= SDL_WINDOW_RESIZABLE; } - // 注意:SDL_WINDOWPOS_CENTERED 是位置参数,不是窗口标志 - // 窗口居中在 SDL_CreateWindow 的位置参数中处理 } sdlWindow_ = SDL_CreateWindow( @@ -101,14 +117,13 @@ 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()); SDL_Quit(); return false; } - // 创建 OpenGL ES 上下文 glContext_ = SDL_GL_CreateContext(sdlWindow_); if (!glContext_) { E2D_LOG_ERROR("SDL_GL_CreateContext failed: {}", SDL_GetError()); @@ -128,8 +143,8 @@ bool Window::initSDL(const WindowConfig &config) { return false; } - // 加载 OpenGL ES 函数指针 - if (gladLoadGLES2Loader(reinterpret_cast(SDL_GL_GetProcAddress)) == 0) { + if (gladLoadGLES2Loader( + reinterpret_cast(SDL_GL_GetProcAddress)) == 0) { E2D_LOG_ERROR("gladLoadGLES2Loader failed"); SDL_GL_DeleteContext(glContext_); glContext_ = nullptr; @@ -139,10 +154,8 @@ bool Window::initSDL(const WindowConfig &config) { return false; } - // 设置 VSync SDL_GL_SetSwapInterval(vsync_ ? 1 : 0); - // 更新 DPI 缩放 if (config.enableDpiScale) { updateContentScale(); } @@ -156,9 +169,14 @@ bool Window::initSDL(const WindowConfig &config) { return true; } +/** + * @brief 反初始化SDL资源 + * + * 释放光标资源、删除OpenGL上下文、销毁SDL窗口并退出SDL库。 + */ void Window::deinitSDL() { deinitCursors(); - + if (glContext_) { SDL_GL_DeleteContext(glContext_); glContext_ = nullptr; @@ -172,6 +190,11 @@ void Window::deinitSDL() { SDL_Quit(); } +/** + * @brief 销毁窗口 + * + * 释放输入管理器并调用deinitSDL()清理所有SDL相关资源。 + */ void Window::destroy() { if (sdlWindow_ != nullptr) { input_.reset(); @@ -180,8 +203,13 @@ void Window::destroy() { } } +/** + * @brief 轮询并处理窗口事件 + * + * 处理SDL事件队列中的所有事件,包括窗口关闭、大小改变、焦点变化等, + * 并更新输入管理器状态。 + */ void Window::pollEvents() { - // SDL2 事件循环 SDL_Event event; while (SDL_PollEvent(&event)) { switch (event.type) { @@ -220,28 +248,53 @@ void Window::pollEvents() { } } - // 输入更新 if (input_) { input_->update(); } } +/** + * @brief 交换前后缓冲区 + * + * 将后台缓冲区内容呈现到屏幕上,实现双缓冲渲染。 + */ void Window::swapBuffers() { if (sdlWindow_) { SDL_GL_SwapWindow(sdlWindow_); } } +/** + * @brief 检查窗口是否应该关闭 + * + * @return 如果窗口应该关闭返回true,否则返回false + */ bool Window::shouldClose() const { return shouldClose_; } +/** + * @brief 设置窗口关闭标志 + * + * @param close 是否应该关闭窗口 + */ void Window::setShouldClose(bool close) { shouldClose_ = close; } +/** + * @brief 设置窗口标题 + * + * @param title 新的窗口标题字符串 + */ void Window::setTitle(const std::string &title) { if (sdlWindow_) { SDL_SetWindowTitle(sdlWindow_, title.c_str()); } } +/** + * @brief 设置窗口大小 + * + * @param width 新的窗口宽度(像素) + * @param height 新的窗口高度(像素) + */ void Window::setSize(int width, int height) { if (sdlWindow_) { SDL_SetWindowSize(sdlWindow_, width, height); @@ -250,32 +303,57 @@ void Window::setSize(int width, int height) { } } -void Window::setPosition(int x, int y) { +/** + * @brief 设置窗口位置 + * + * @param x 窗口左上角的X坐标(屏幕坐标) + * @param y 窗口左上角的Y坐标(屏幕坐标) + */ +void Window::setPos(int x, int y) { if (sdlWindow_) { SDL_SetWindowPosition(sdlWindow_, x, y); } } +/** + * @brief 设置窗口全屏模式 + * + * @param fullscreen true为全屏模式,false为窗口模式 + */ void Window::setFullscreen(bool fullscreen) { if (sdlWindow_) { - // 默认使用桌面全屏模式(PC 平台) Uint32 flags = fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0; SDL_SetWindowFullscreen(sdlWindow_, flags); fullscreen_ = fullscreen; } } +/** + * @brief 设置垂直同步 + * + * @param enabled true启用VSync,false禁用VSync + */ void Window::setVSync(bool enabled) { vsync_ = enabled; SDL_GL_SetSwapInterval(enabled ? 1 : 0); } +/** + * @brief 设置窗口是否可调整大小 + * + * @param resizable true允许用户调整窗口大小,false禁止调整 + */ void Window::setResizable(bool resizable) { if (sdlWindow_) { SDL_SetWindowResizable(sdlWindow_, resizable ? SDL_TRUE : SDL_FALSE); } } +/** + * @brief 获取窗口位置 + * + * @return 包含窗口左上角X和Y坐标的二维向量 + */ Vec2 Window::getPosition() const { if (sdlWindow_) { int x, y; @@ -285,18 +363,42 @@ Vec2 Window::getPosition() const { return Vec2::Zero(); } +/** + * @brief 获取X轴内容缩放比例 + * + * 根据DPI设置返回X轴的内容缩放比例,用于高DPI显示适配。 + * + * @return X轴缩放比例,如果DPI缩放被禁用则返回1.0 + */ float Window::getContentScaleX() const { return enableDpiScale_ ? contentScaleX_ : 1.0f; } +/** + * @brief 获取Y轴内容缩放比例 + * + * 根据DPI设置返回Y轴的内容缩放比例,用于高DPI显示适配。 + * + * @return Y轴缩放比例,如果DPI缩放被禁用则返回1.0 + */ float Window::getContentScaleY() const { return enableDpiScale_ ? contentScaleY_ : 1.0f; } +/** + * @brief 获取内容缩放比例 + * + * @return 包含X和Y轴缩放比例的二维向量 + */ Vec2 Window::getContentScale() const { return Vec2(getContentScaleX(), getContentScaleY()); } +/** + * @brief 检查窗口是否最小化 + * + * @return 如果窗口处于最小化状态返回true,否则返回false + */ bool Window::isMinimized() const { if (sdlWindow_) { Uint32 flags = SDL_GetWindowFlags(sdlWindow_); @@ -305,6 +407,11 @@ bool Window::isMinimized() const { return false; } +/** + * @brief 检查窗口是否最大化 + * + * @return 如果窗口处于最大化状态返回true,否则返回false + */ bool Window::isMaximized() const { if (sdlWindow_) { Uint32 flags = SDL_GetWindowFlags(sdlWindow_); @@ -313,6 +420,12 @@ bool Window::isMaximized() const { return true; } +/** + * @brief 初始化系统光标 + * + * 创建9种常用的系统光标,包括箭头、文本选择、十字、手形、 + * 水平调整、垂直调整、移动、对角线调整等。 + */ void Window::initCursors() { sdlCursors_[0] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); sdlCursors_[1] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); @@ -325,6 +438,11 @@ void Window::initCursors() { sdlCursors_[8] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW); } +/** + * @brief 释放光标资源 + * + * 释放所有已创建的系统光标并重置当前光标指针。 + */ void Window::deinitCursors() { for (int i = 0; i < 9; ++i) { if (sdlCursors_[i]) { @@ -335,6 +453,13 @@ void Window::deinitCursors() { currentCursor_ = nullptr; } +/** + * @brief 设置鼠标光标样式 + * + * 将鼠标光标更改为指定的系统光标样式。 + * + * @param shape 光标形状枚举值 + */ void Window::setCursor(CursorShape shape) { int index = static_cast(shape); if (index >= 0 && index < 9 && sdlCursors_[index]) { @@ -343,23 +468,37 @@ void Window::setCursor(CursorShape shape) { } } +/** + * @brief 重置鼠标光标为默认样式 + * + * 将鼠标光标恢复为系统默认光标。 + */ void Window::resetCursor() { SDL_SetCursor(SDL_GetDefaultCursor()); currentCursor_ = nullptr; } +/** + * @brief 设置鼠标光标可见性 + * + * @param visible true显示鼠标光标,false隐藏鼠标光标 + */ void Window::setMouseVisible(bool visible) { SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE); } +/** + * @brief 更新内容缩放比例 + * + * 根据当前窗口所在显示器的DPI值更新内容缩放比例, + * 以标准96 DPI为基准计算缩放因子。 + */ void Window::updateContentScale() { if (sdlWindow_) { - // 使用 DPI 计算内容缩放比例 int displayIndex = SDL_GetWindowDisplayIndex(sdlWindow_); if (displayIndex >= 0) { float ddpi, hdpi, vdpi; if (SDL_GetDisplayDPI(displayIndex, &ddpi, &hdpi, &vdpi) == 0) { - // 假设标准 DPI 为 96 contentScaleX_ = hdpi / 96.0f; contentScaleY_ = vdpi / 96.0f; } diff --git a/Extra2D/src/scene/node.cpp b/Extra2D/src/scene/node.cpp index e00c733..1054c0d 100644 --- a/Extra2D/src/scene/node.cpp +++ b/Extra2D/src/scene/node.cpp @@ -7,18 +7,32 @@ namespace extra2d { +/** + * @brief 默认构造函数 + * + * 创建一个空的节点对象 + */ Node::Node() = default; -Node::~Node() { - removeAllChildren(); -} +/** + * @brief 析构函数 + * + * 清除所有子节点 + */ +Node::~Node() { clearChildren(); } +/** + * @brief 添加子节点 + * @param child 要添加的子节点智能指针 + * + * 将子节点添加到当前节点的子节点列表中,自动从原父节点分离 + */ void Node::addChild(Ptr child) { if (!child || child.get() == this) { return; } - child->removeFromParent(); + child->detach(); child->parent_ = weak_from_this(); children_.push_back(child); childrenOrderDirty_ = true; @@ -39,6 +53,12 @@ void Node::addChild(Ptr child) { } } +/** + * @brief 批量添加子节点 + * @param children 要添加的子节点数组(右值引用) + * + * 高效地批量添加多个子节点,预分配内存以减少扩容次数 + */ void Node::addChildren(std::vector> &&children) { // 预留空间,避免多次扩容 size_t newSize = children_.size() + children.size(); @@ -51,7 +71,7 @@ void Node::addChildren(std::vector> &&children) { continue; } - child->removeFromParent(); + child->detach(); child->parent_ = weak_from_this(); children_.push_back(child); @@ -76,6 +96,12 @@ void Node::addChildren(std::vector> &&children) { } } +/** + * @brief 移除子节点 + * @param child 要移除的子节点智能指针 + * + * 从子节点列表中移除指定节点,并触发相应的退出回调 + */ void Node::removeChild(Ptr child) { if (!child) return; @@ -98,14 +124,25 @@ void Node::removeChild(Ptr child) { } } +/** + * @brief 通过名称移除子节点 + * @param name 子节点的名称 + * + * 查找并移除具有指定名称的子节点 + */ void Node::removeChildByName(const std::string &name) { - auto child = getChildByName(name); + auto child = findChild(name); if (child) { removeChild(child); } } -void Node::removeFromParent() { +/** + * @brief 从父节点分离 + * + * 将当前节点从其父节点的子节点列表中移除 + */ +void Node::detach() { auto p = parent_.lock(); if (p) { // 安全获取 shared_ptr,避免在对象未由 shared_ptr 管理时崩溃 @@ -121,7 +158,12 @@ void Node::removeFromParent() { } } -void Node::removeAllChildren() { +/** + * @brief 清除所有子节点 + * + * 移除所有子节点并触发相应的退出回调 + */ +void Node::clearChildren() { for (auto &child : children_) { if (running_) { child->onDetachFromScene(); @@ -134,7 +176,14 @@ void Node::removeAllChildren() { tagIndex_.clear(); } -Ptr Node::getChildByName(const std::string &name) const { +/** + * @brief 通过名称查找子节点 + * @param name 子节点的名称 + * @return 找到的子节点智能指针,未找到返回nullptr + * + * 使用哈希索引进行O(1)时间复杂度查找 + */ +Ptr Node::findChild(const std::string &name) const { // 使用哈希索引,O(1) 查找 auto it = nameIndex_.find(name); if (it != nameIndex_.end()) { @@ -143,7 +192,14 @@ Ptr Node::getChildByName(const std::string &name) const { return nullptr; } -Ptr Node::getChildByTag(int tag) const { +/** + * @brief 通过标签查找子节点 + * @param tag 子节点的标签值 + * @return 找到的子节点智能指针,未找到返回nullptr + * + * 使用哈希索引进行O(1)时间复杂度查找 + */ +Ptr Node::findChildByTag(int tag) const { // 使用哈希索引,O(1) 查找 auto it = tagIndex_.find(tag); if (it != tagIndex_.end()) { @@ -152,53 +208,123 @@ Ptr Node::getChildByTag(int tag) const { return nullptr; } -void Node::setPosition(const Vec2 &pos) { +/** + * @brief 设置节点位置 + * @param pos 新的位置坐标 + */ +void Node::setPos(const Vec2 &pos) { position_ = pos; markTransformDirty(); } -void Node::setPosition(float x, float y) { setPosition(Vec2(x, y)); } +/** + * @brief 设置节点位置 + * @param x X坐标 + * @param y Y坐标 + */ +void Node::setPos(float x, float y) { setPos(Vec2(x, y)); } +/** + * @brief 设置节点旋转角度 + * @param degrees 旋转角度(度数) + */ void Node::setRotation(float degrees) { rotation_ = degrees; markTransformDirty(); } +/** + * @brief 设置节点缩放 + * @param scale 缩放向量 + */ void Node::setScale(const Vec2 &scale) { scale_ = scale; markTransformDirty(); } +/** + * @brief 设置节点统一缩放 + * @param scale 统一缩放值 + */ void Node::setScale(float scale) { setScale(Vec2(scale, scale)); } +/** + * @brief 设置节点缩放 + * @param x X轴缩放值 + * @param y Y轴缩放值 + */ void Node::setScale(float x, float y) { setScale(Vec2(x, y)); } +/** + * @brief 设置节点锚点 + * @param anchor 锚点位置(0-1范围) + */ void Node::setAnchor(const Vec2 &anchor) { anchor_ = anchor; markTransformDirty(); } +/** + * @brief 设置节点锚点 + * @param x 锚点X坐标(0-1范围) + * @param y 锚点Y坐标(0-1范围) + */ void Node::setAnchor(float x, float y) { setAnchor(Vec2(x, y)); } +/** + * @brief 设置节点斜切 + * @param skew 斜切角度向量 + */ void Node::setSkew(const Vec2 &skew) { skew_ = skew; markTransformDirty(); } +/** + * @brief 设置节点斜切 + * @param x X轴斜切角度 + * @param y Y轴斜切角度 + */ void Node::setSkew(float x, float y) { setSkew(Vec2(x, y)); } +/** + * @brief 设置节点透明度 + * @param opacity 透明度值(0.0-1.0范围) + */ void Node::setOpacity(float opacity) { opacity_ = std::clamp(opacity, 0.0f, 1.0f); } +/** + * @brief 设置节点可见性 + * @param visible 是否可见 + */ void Node::setVisible(bool visible) { visible_ = visible; } -void Node::setColor(const Color3B& color) { color_ = color; } +/** + * @brief 设置节点颜色 + * @param color RGB颜色值 + */ +void Node::setColor(const Color3B &color) { color_ = color; } +/** + * @brief 设置水平翻转 + * @param flipX 是否水平翻转 + */ void Node::setFlipX(bool flipX) { flipX_ = flipX; } +/** + * @brief 设置垂直翻转 + * @param flipY 是否垂直翻转 + */ void Node::setFlipY(bool flipY) { flipY_ = flipY; } +/** + * @brief 设置Z序 + * @param zOrder 渲染层级顺序 + * + * 较大的Z序值会在上层渲染 + */ void Node::setZOrder(int zOrder) { if (zOrder_ != zOrder) { zOrder_ = zOrder; @@ -206,18 +332,34 @@ void Node::setZOrder(int zOrder) { } } -Vec2 Node::convertToWorldSpace(const Vec2 &localPos) const { +/** + * @brief 将本地坐标转换为世界坐标 + * @param localPos 本地坐标位置 + * @return 世界坐标位置 + */ +Vec2 Node::toWorld(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 { +/** + * @brief 将世界坐标转换为本地坐标 + * @param worldPos 世界坐标位置 + * @return 本地坐标位置 + */ +Vec2 Node::toLocal(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); } +/** + * @brief 获取本地变换矩阵 + * @return 本地变换矩阵 + * + * 计算包含位置、旋转、斜切和缩放的本地变换矩阵 + */ glm::mat4 Node::getLocalTransform() const { if (transformDirty_) { localTransform_ = glm::mat4(1.0f); @@ -249,13 +391,19 @@ glm::mat4 Node::getLocalTransform() const { return localTransform_; } +/** + * @brief 获取世界变换矩阵 + * @return 世界变换矩阵 + * + * 计算从根节点到当前节点的累积变换矩阵 + */ glm::mat4 Node::getWorldTransform() const { if (worldTransformDirty_) { // 使用线程局部存储的固定数组,避免每帧内存分配 // 限制最大深度为 256 层,足以覆盖绝大多数场景 - thread_local std::array nodeChainCache; + thread_local std::array nodeChainCache; thread_local size_t chainCount = 0; - + chainCount = 0; const Node *current = this; while (current && chainCount < nodeChainCache.size()) { @@ -275,6 +423,11 @@ glm::mat4 Node::getWorldTransform() const { return worldTransform_; } +/** + * @brief 标记变换为脏 + * + * 标记本地变换和世界变换需要重新计算,并递归标记所有子节点 + */ void Node::markTransformDirty() { // 避免重复标记,提高性能 if (!transformDirty_ || !worldTransformDirty_) { @@ -288,12 +441,17 @@ void Node::markTransformDirty() { } } -void Node::batchUpdateTransforms() { +/** + * @brief 批量更新变换 + * + * 从父节点到子节点依次更新世界变换矩阵 + */ +void Node::batchTransforms() { // 如果本地变换脏了,先计算本地变换 if (transformDirty_) { (void)getLocalTransform(); // 这会计算并缓存本地变换 } - + // 如果世界变换脏了,需要重新计算 if (worldTransformDirty_) { auto parent = parent_.lock(); @@ -306,13 +464,18 @@ void Node::batchUpdateTransforms() { } worldTransformDirty_ = false; } - + // 递归更新子节点 for (auto &child : children_) { - child->batchUpdateTransforms(); + child->batchTransforms(); } } +/** + * @brief 节点进入时的回调 + * + * 标记节点为运行状态,并递归调用所有子节点的onEnter + */ void Node::onEnter() { running_ = true; for (auto &child : children_) { @@ -320,6 +483,11 @@ void Node::onEnter() { } } +/** + * @brief 节点退出时的回调 + * + * 标记节点为非运行状态,并递归调用所有子节点的onExit + */ void Node::onExit() { running_ = false; for (auto &child : children_) { @@ -327,6 +495,12 @@ void Node::onExit() { } } +/** + * @brief 更新回调 + * @param dt 帧间隔时间(秒) + * + * 先调用节点自身的更新逻辑,再更新所有子节点 + */ void Node::onUpdate(float dt) { onUpdateNode(dt); @@ -336,6 +510,12 @@ void Node::onUpdate(float dt) { } } +/** + * @brief 渲染回调 + * @param renderer 渲染后端引用 + * + * 如果可见则绘制自身,然后递归渲染所有子节点 + */ void Node::onRender(RenderBackend &renderer) { if (!visible_) return; @@ -347,6 +527,12 @@ void Node::onRender(RenderBackend &renderer) { } } +/** + * @brief 附加到场景时的回调 + * @param scene 所属场景指针 + * + * 设置场景引用并递归通知所有子节点 + */ void Node::onAttachToScene(Scene *scene) { scene_ = scene; @@ -355,6 +541,11 @@ void Node::onAttachToScene(Scene *scene) { } } +/** + * @brief 从场景分离时的回调 + * + * 清除场景引用并递归通知所有子节点 + */ void Node::onDetachFromScene() { scene_ = nullptr; for (auto &child : children_) { @@ -362,12 +553,28 @@ void Node::onDetachFromScene() { } } -Rect Node::getBoundingBox() const { - return Rect(position_.x, position_.y, 0, 0); -} +/** + * @brief 获取节点边界矩形 + * @return 节点的边界矩形 + * + * 默认返回以位置为中心的空矩形,子类应重写此方法 + */ +Rect Node::getBounds() const { return Rect(position_.x, position_.y, 0, 0); } +/** + * @brief 更新节点 + * @param dt 帧间隔时间(秒) + * + * 调用onUpdate进行更新 + */ void Node::update(float dt) { onUpdate(dt); } +/** + * @brief 渲染节点 + * @param renderer 渲染后端引用 + * + * 如果需要则对子节点排序,然后调用onRender进行渲染 + */ void Node::render(RenderBackend &renderer) { if (childrenOrderDirty_) { sortChildren(); @@ -375,6 +582,11 @@ void Node::render(RenderBackend &renderer) { onRender(renderer); } +/** + * @brief 对子节点按Z序排序 + * + * 小数组使用插入排序,大数组使用标准排序以优化性能 + */ void Node::sortChildren() { // 使用插入排序优化小范围更新场景 // 插入排序在大部分已有序的情况下性能接近O(n) @@ -409,6 +621,13 @@ void Node::sortChildren() { childrenOrderDirty_ = false; } +/** + * @brief 收集渲染命令 + * @param commands 渲染命令输出向量 + * @param parentZOrder 父节点的Z序 + * + * 递归收集当前节点和所有子节点的渲染命令 + */ void Node::collectRenderCommands(std::vector &commands, int parentZOrder) { if (!visible_) diff --git a/Extra2D/src/scene/scene.cpp b/Extra2D/src/scene/scene.cpp index 3a14b28..c107ea0 100644 --- a/Extra2D/src/scene/scene.cpp +++ b/Extra2D/src/scene/scene.cpp @@ -5,10 +5,26 @@ namespace extra2d { +/** + * @brief 构造函数,初始化场景对象 + * + * 创建默认相机实例 + */ Scene::Scene() { defaultCamera_ = makePtr(); } +/** + * @brief 设置场景相机 + * @param camera 要设置的相机智能指针 + */ void Scene::setCamera(Ptr camera) { camera_ = camera; } +/** + * @brief 设置视口大小 + * @param width 视口宽度 + * @param height 视口高度 + * + * 同时更新活动相机的视口参数 + */ void Scene::setViewportSize(float width, float height) { viewportSize_ = Size(width, height); if (defaultCamera_) { @@ -18,10 +34,20 @@ void Scene::setViewportSize(float width, float height) { } } +/** + * @brief 设置视口大小 + * @param size 视口尺寸结构体 + */ void Scene::setViewportSize(const Size &size) { setViewportSize(size.width, size.height); } +/** + * @brief 渲染场景 + * @param renderer 渲染后端引用 + * + * 如果场景不可见则直接返回,否则开始帧渲染、渲染内容并结束帧 + */ void Scene::renderScene(RenderBackend &renderer) { if (!isVisible()) return; @@ -32,12 +58,18 @@ void Scene::renderScene(RenderBackend &renderer) { renderer.endFrame(); } +/** + * @brief 渲染场景内容 + * @param renderer 渲染后端引用 + * + * 批量更新节点变换,设置活动相机的视图投影矩阵,开始精灵批处理并渲染 + */ void Scene::renderContent(RenderBackend &renderer) { if (!isVisible()) return; // 在渲染前批量更新所有节点的世界变换 - batchUpdateTransforms(); + batchTransforms(); Camera *activeCam = getActiveCamera(); if (activeCam) { @@ -49,20 +81,39 @@ void Scene::renderContent(RenderBackend &renderer) { renderer.endSpriteBatch(); } +/** + * @brief 更新场景 + * @param dt 帧间隔时间(秒) + * + * 如果场景未暂停则调用update方法 + */ void Scene::updateScene(float dt) { if (!paused_) { update(dt); } } -void Scene::onEnter() { - Node::onEnter(); -} +/** + * @brief 场景进入时的回调函数 + * + * 调用父类Node的onEnter方法 + */ +void Scene::onEnter() { Node::onEnter(); } -void Scene::onExit() { - Node::onExit(); -} +/** + * @brief 场景退出时的回调函数 + * + * 调用父类Node的onExit方法 + */ +void Scene::onExit() { Node::onExit(); } +/** + * @brief 收集渲染命令 + * @param commands 渲染命令输出向量 + * @param parentZOrder 父节点的Z序 + * + * 如果场景不可见则直接返回,否则从场景的子节点开始收集渲染命令 + */ void Scene::collectRenderCommands(std::vector &commands, int parentZOrder) { if (!isVisible()) @@ -72,6 +123,10 @@ void Scene::collectRenderCommands(std::vector &commands, Node::collectRenderCommands(commands, parentZOrder); } +/** + * @brief 创建场景对象 + * @return 新创建的场景智能指针 + */ Ptr Scene::create() { return makePtr(); } } // namespace extra2d diff --git a/Extra2D/src/scene/scene_manager.cpp b/Extra2D/src/scene/scene_manager.cpp index 1b12573..1c1cbb8 100644 --- a/Extra2D/src/scene/scene_manager.cpp +++ b/Extra2D/src/scene/scene_manager.cpp @@ -12,6 +12,9 @@ namespace { /** * @brief 命中测试 - 从节点树中找到最上层的可交互节点 + * @param node 要测试的节点 + * @param worldPos 世界坐标位置 + * @return 命中的节点指针,未命中返回nullptr */ Node *hitTestTopmost(const Ptr &node, const Vec2 &worldPos) { if (!node || !node->isVisible()) { @@ -34,7 +37,7 @@ Node *hitTestTopmost(const Ptr &node, const Vec2 &worldPos) { return nullptr; } - Rect bounds = node->getBoundingBox(); + Rect bounds = node->getBounds(); if (!bounds.empty() && bounds.containsPoint(worldPos)) { return node.get(); } @@ -44,6 +47,8 @@ Node *hitTestTopmost(const Ptr &node, const Vec2 &worldPos) { /** * @brief 向节点分发事件 + * @param node 目标节点 + * @param event 要分发的事件 */ void dispatchToNode(Node *node, Event &event) { if (!node) { @@ -54,11 +59,21 @@ void dispatchToNode(Node *node, Event &event) { } // namespace -SceneManager &SceneManager::getInstance() { +/** + * @brief 获取场景管理器单例 + * @return 场景管理器的全局唯一实例引用 + */ +SceneManager &SceneManager::get() { static SceneManager instance; return instance; } +/** + * @brief 运行指定场景 + * @param scene 要运行的场景智能指针 + * + * 此方法应在应用启动时调用一次,设置初始场景 + */ void SceneManager::runWithScene(Ptr scene) { if (!scene) { return; @@ -74,6 +89,12 @@ void SceneManager::runWithScene(Ptr scene) { sceneStack_.push(scene); } +/** + * @brief 替换当前场景 + * @param scene 新场景智能指针 + * + * 移除当前场景并替换为新场景,场景栈大小保持不变 + */ void SceneManager::replaceScene(Ptr scene) { if (!scene || isTransitioning_) { return; @@ -94,6 +115,12 @@ void SceneManager::replaceScene(Ptr scene) { sceneStack_.push(scene); } +/** + * @brief 进入场景 + * @param scene 要进入的场景智能指针 + * + * 如果场景栈为空则运行场景,否则替换当前场景 + */ void SceneManager::enterScene(Ptr scene) { if (!scene || isTransitioning_) { return; @@ -106,6 +133,12 @@ void SceneManager::enterScene(Ptr scene) { } } +/** + * @brief 压入场景到栈顶 + * @param scene 要压入的场景智能指针 + * + * 将新场景压入栈顶,暂停当前场景 + */ void SceneManager::pushScene(Ptr scene) { if (!scene || isTransitioning_) { return; @@ -120,6 +153,11 @@ void SceneManager::pushScene(Ptr scene) { sceneStack_.push(scene); } +/** + * @brief 弹出当前场景 + * + * 移除栈顶场景并恢复上一个场景 + */ void SceneManager::popScene() { if (sceneStack_.size() <= 1 || isTransitioning_) { return; @@ -135,6 +173,11 @@ void SceneManager::popScene() { } } +/** + * @brief 弹出到根场景 + * + * 移除所有场景直到只剩根场景 + */ void SceneManager::popToRootScene() { if (sceneStack_.size() <= 1 || isTransitioning_) { return; @@ -150,6 +193,12 @@ void SceneManager::popToRootScene() { sceneStack_.top()->resume(); } +/** + * @brief 弹出到指定名称的场景 + * @param name 目标场景的名称 + * + * 移除栈顶场景直到找到指定名称的场景 + */ void SceneManager::popToScene(const std::string &name) { if (isTransitioning_) { return; @@ -174,6 +223,10 @@ void SceneManager::popToScene(const std::string &name) { } } +/** + * @brief 获取当前场景 + * @return 当前栈顶场景的智能指针,栈为空时返回nullptr + */ Ptr SceneManager::getCurrentScene() const { if (sceneStack_.empty()) { return nullptr; @@ -181,6 +234,10 @@ Ptr SceneManager::getCurrentScene() const { return sceneStack_.top(); } +/** + * @brief 获取前一个场景 + * @return 栈顶下一个场景的智能指针,不存在时返回nullptr + */ Ptr SceneManager::getPreviousScene() const { if (sceneStack_.size() < 2) { return nullptr; @@ -191,6 +248,10 @@ Ptr SceneManager::getPreviousScene() const { return tempStack.top(); } +/** + * @brief 获取根场景 + * @return 栈底场景的智能指针,栈为空时返回nullptr + */ Ptr SceneManager::getRootScene() const { if (sceneStack_.empty()) { return nullptr; @@ -205,6 +266,11 @@ Ptr SceneManager::getRootScene() const { return root; } +/** + * @brief 通过名称获取场景 + * @param name 场景名称 + * @return 找到的场景智能指针,未找到返回nullptr + */ Ptr SceneManager::getSceneByName(const std::string &name) const { auto it = namedScenes_.find(name); if (it != namedScenes_.end()) { @@ -223,10 +289,21 @@ Ptr SceneManager::getSceneByName(const std::string &name) const { return nullptr; } +/** + * @brief 检查是否存在指定名称的场景 + * @param name 场景名称 + * @return 存在返回true,否则返回false + */ bool SceneManager::hasScene(const std::string &name) const { return getSceneByName(name) != nullptr; } +/** + * @brief 更新场景管理器 + * @param dt 帧间隔时间(秒) + * + * 更新当前场景并分发指针事件 + */ void SceneManager::update(float dt) { if (isTransitioning_) { hoverTarget_ = nullptr; @@ -243,6 +320,12 @@ void SceneManager::update(float dt) { } } +/** + * @brief 渲染当前场景 + * @param renderer 渲染后端引用 + * + * 使用当前场景的背景色清除帧缓冲并渲染场景内容 + */ void SceneManager::render(RenderBackend &renderer) { Color clearColor = Colors::Black; if (!sceneStack_.empty()) { @@ -264,12 +347,23 @@ void SceneManager::render(RenderBackend &renderer) { E2D_LOG_TRACE("SceneManager::render - endFrame"); } +/** + * @brief 收集渲染命令 + * @param commands 渲染命令输出向量 + * + * 从当前场景收集所有渲染命令 + */ void SceneManager::collectRenderCommands(std::vector &commands) { if (!sceneStack_.empty()) { sceneStack_.top()->collectRenderCommands(commands, 0); } } +/** + * @brief 结束场景管理器 + * + * 清空场景栈并触发所有场景的退出回调 + */ void SceneManager::end() { while (!sceneStack_.empty()) { auto scene = sceneStack_.top(); @@ -280,10 +374,21 @@ void SceneManager::end() { namedScenes_.clear(); } +/** + * @brief 清除缓存的场景 + * + * 清除命名场景缓存 + */ void SceneManager::purgeCachedScenes() { namedScenes_.clear(); } +/** + * @brief 分发指针事件 + * @param scene 目标场景 + * + * 处理鼠标悬停、移动、点击和滚轮事件 + */ void SceneManager::dispatchPointerEvents(Scene &scene) { - auto &input = Application::instance().input(); + auto &input = Application::get().input(); Vec2 screenPos = input.getMousePosition(); Vec2 worldPos = screenPos; diff --git a/Extra2D/src/scene/shape_node.cpp b/Extra2D/src/scene/shape_node.cpp index c2ef2f3..98ca690 100644 --- a/Extra2D/src/scene/shape_node.cpp +++ b/Extra2D/src/scene/shape_node.cpp @@ -7,10 +7,25 @@ namespace extra2d { +/** + * @brief 默认构造函数 + * + * 创建一个空的形状节点 + */ ShapeNode::ShapeNode() = default; +/** + * @brief 创建空的形状节点 + * @return 新创建的形状节点智能指针 + */ Ptr ShapeNode::create() { return makePtr(); } +/** + * @brief 创建点形状节点 + * @param pos 点的位置坐标 + * @param color 点的颜色 + * @return 新创建的点形状节点智能指针 + */ Ptr ShapeNode::createPoint(const Vec2 &pos, const Color &color) { auto node = makePtr(); node->shapeType_ = ShapeType::Point; @@ -19,6 +34,14 @@ Ptr ShapeNode::createPoint(const Vec2 &pos, const Color &color) { return node; } +/** + * @brief 创建线段形状节点 + * @param start 线段起点坐标 + * @param end 线段终点坐标 + * @param color 线段颜色 + * @param width 线段宽度 + * @return 新创建的线段形状节点智能指针 + */ Ptr ShapeNode::createLine(const Vec2 &start, const Vec2 &end, const Color &color, float width) { auto node = makePtr(); @@ -29,6 +52,13 @@ Ptr ShapeNode::createLine(const Vec2 &start, const Vec2 &end, return node; } +/** + * @brief 创建矩形形状节点(空心) + * @param rect 矩形区域 + * @param color 矩形边框颜色 + * @param width 边框线宽 + * @return 新创建的矩形形状节点智能指针 + */ Ptr ShapeNode::createRect(const Rect &rect, const Color &color, float width) { auto node = makePtr(); @@ -42,6 +72,12 @@ Ptr ShapeNode::createRect(const Rect &rect, const Color &color, return node; } +/** + * @brief 创建填充矩形形状节点 + * @param rect 矩形区域 + * @param color 矩形填充颜色 + * @return 新创建的填充矩形形状节点智能指针 + */ Ptr ShapeNode::createFilledRect(const Rect &rect, const Color &color) { auto node = createRect(rect, color, 0); @@ -49,6 +85,15 @@ Ptr ShapeNode::createFilledRect(const Rect &rect, return node; } +/** + * @brief 创建圆形形状节点(空心) + * @param center 圆心坐标 + * @param radius 圆的半径 + * @param color 圆的边框颜色 + * @param segments 圆的分段数(边数) + * @param width 边框线宽 + * @return 新创建的圆形形状节点智能指针 + */ Ptr ShapeNode::createCircle(const Vec2 ¢er, float radius, const Color &color, int segments, float width) { @@ -64,6 +109,14 @@ Ptr ShapeNode::createCircle(const Vec2 ¢er, float radius, return node; } +/** + * @brief 创建填充圆形形状节点 + * @param center 圆心坐标 + * @param radius 圆的半径 + * @param color 圆的填充颜色 + * @param segments 圆的分段数(边数) + * @return 新创建的填充圆形形状节点智能指针 + */ Ptr ShapeNode::createFilledCircle(const Vec2 ¢er, float radius, const Color &color, int segments) { auto node = createCircle(center, radius, color, segments, 0); @@ -71,6 +124,15 @@ Ptr ShapeNode::createFilledCircle(const Vec2 ¢er, float radius, return node; } +/** + * @brief 创建三角形形状节点(空心) + * @param p1 三角形第一个顶点坐标 + * @param p2 三角形第二个顶点坐标 + * @param p3 三角形第三个顶点坐标 + * @param color 三角形边框颜色 + * @param width 边框线宽 + * @return 新创建的三角形形状节点智能指针 + */ Ptr ShapeNode::createTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3, const Color &color, float width) { @@ -83,6 +145,14 @@ Ptr ShapeNode::createTriangle(const Vec2 &p1, const Vec2 &p2, return node; } +/** + * @brief 创建填充三角形形状节点 + * @param p1 三角形第一个顶点坐标 + * @param p2 三角形第二个顶点坐标 + * @param p3 三角形第三个顶点坐标 + * @param color 三角形填充颜色 + * @return 新创建的填充三角形形状节点智能指针 + */ Ptr ShapeNode::createFilledTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3, const Color &color) { @@ -91,6 +161,13 @@ Ptr ShapeNode::createFilledTriangle(const Vec2 &p1, const Vec2 &p2, return node; } +/** + * @brief 创建多边形形状节点(空心) + * @param points 多边形顶点坐标数组 + * @param color 多边形边框颜色 + * @param width 边框线宽 + * @return 新创建的多边形形状节点智能指针 + */ Ptr ShapeNode::createPolygon(const std::vector &points, const Color &color, float width) { auto node = makePtr(); @@ -102,6 +179,12 @@ Ptr ShapeNode::createPolygon(const std::vector &points, return node; } +/** + * @brief 创建填充多边形形状节点 + * @param points 多边形顶点坐标数组 + * @param color 多边形填充颜色 + * @return 新创建的填充多边形形状节点智能指针 + */ Ptr ShapeNode::createFilledPolygon(const std::vector &points, const Color &color) { auto node = createPolygon(points, color, 0); @@ -109,19 +192,36 @@ Ptr ShapeNode::createFilledPolygon(const std::vector &points, return node; } +/** + * @brief 设置形状的所有顶点 + * @param points 顶点坐标数组 + */ void ShapeNode::setPoints(const std::vector &points) { points_ = points; } +/** + * @brief 添加一个顶点到形状 + * @param point 要添加的顶点坐标 + */ void ShapeNode::addPoint(const Vec2 &point) { points_.push_back(point); } +/** + * @brief 清除所有顶点 + */ void ShapeNode::clearPoints() { points_.clear(); } -Rect ShapeNode::getBoundingBox() const { +/** + * @brief 获取形状的边界矩形 + * @return 包围形状的轴对齐边界矩形 + * + * 计算形状在世界坐标系中的边界框,考虑位置偏移和线宽 + */ +Rect ShapeNode::getBounds() const { if (points_.empty()) { return Rect(); } @@ -163,6 +263,12 @@ Rect ShapeNode::getBoundingBox() const { (maxY - minY) + inflate * 2.0f); } +/** + * @brief 绘制形状节点 + * @param renderer 渲染后端引用 + * + * 根据形状类型调用相应的渲染方法进行绘制 + */ void ShapeNode::onDraw(RenderBackend &renderer) { if (points_.empty()) { return; @@ -245,6 +351,13 @@ void ShapeNode::onDraw(RenderBackend &renderer) { } } +/** + * @brief 生成渲染命令 + * @param commands 渲染命令输出向量 + * @param zOrder 渲染层级 + * + * 根据形状类型生成对应的渲染命令并添加到命令列表 + */ void ShapeNode::generateRenderCommand(std::vector &commands, int zOrder) { if (points_.empty()) { diff --git a/Extra2D/src/scene/sprite.cpp b/Extra2D/src/scene/sprite.cpp index 7bf7e0a..d5368c4 100644 --- a/Extra2D/src/scene/sprite.cpp +++ b/Extra2D/src/scene/sprite.cpp @@ -7,10 +7,27 @@ namespace extra2d { +/** + * @brief 默认构造函数 + * + * 创建一个空的精灵对象 + */ Sprite::Sprite() = default; +/** + * @brief 带纹理的构造函数 + * @param texture 精灵使用的纹理智能指针 + * + * 创建精灵并设置纹理,纹理区域默认为整个纹理 + */ Sprite::Sprite(Ptr texture) { setTexture(texture); } +/** + * @brief 设置精灵纹理 + * @param texture 要设置的纹理智能指针 + * + * 设置纹理并将纹理区域初始化为整个纹理大小 + */ void Sprite::setTexture(Ptr texture) { texture_ = texture; if (texture_) { @@ -19,27 +36,68 @@ void Sprite::setTexture(Ptr texture) { } } +/** + * @brief 设置纹理区域 + * @param rect 纹理上的矩形区域 + * + * 设置精灵显示纹理的哪一部分 + */ void Sprite::setTextureRect(const Rect &rect) { textureRect_ = rect; } +/** + * @brief 设置精灵颜色 + * @param color 要设置的颜色 + * + * 颜色会与纹理颜色混合 + */ void Sprite::setColor(const Color &color) { color_ = color; } +/** + * @brief 设置水平翻转 + * @param flip 是否水平翻转 + */ void Sprite::setFlipX(bool flip) { flipX_ = flip; } +/** + * @brief 设置垂直翻转 + * @param flip 是否垂直翻转 + */ void Sprite::setFlipY(bool flip) { flipY_ = flip; } +/** + * @brief 创建空精灵 + * @return 新创建的精灵智能指针 + */ Ptr Sprite::create() { return makePtr(); } +/** + * @brief 创建带纹理的精灵 + * @param texture 精灵使用的纹理 + * @return 新创建的精灵智能指针 + */ Ptr Sprite::create(Ptr texture) { return makePtr(texture); } +/** + * @brief 创建带纹理和纹理区域的精灵 + * @param texture 精灵使用的纹理 + * @param rect 纹理区域 + * @return 新创建的精灵智能指针 + */ Ptr Sprite::create(Ptr texture, const Rect &rect) { auto sprite = makePtr(texture); sprite->setTextureRect(rect); return sprite; } -Rect Sprite::getBoundingBox() const { +/** + * @brief 获取精灵的边界矩形 + * @return 精灵在世界坐标系中的轴对齐边界矩形 + * + * 考虑位置、锚点、缩放等因素计算边界框 + */ +Rect Sprite::getBounds() const { if (!texture_ || !texture_->isValid()) { return Rect(); } @@ -63,6 +121,12 @@ Rect Sprite::getBoundingBox() const { return Rect(l, t, std::abs(w), std::abs(h)); } +/** + * @brief 绘制精灵 + * @param renderer 渲染后端引用 + * + * 使用世界变换计算最终位置、缩放和旋转,然后绘制精灵 + */ void Sprite::onDraw(RenderBackend &renderer) { if (!texture_ || !texture_->isValid()) { return; @@ -108,6 +172,13 @@ void Sprite::onDraw(RenderBackend &renderer) { anchor); } +/** + * @brief 生成渲染命令 + * @param commands 渲染命令输出向量 + * @param zOrder 渲染层级 + * + * 根据精灵的纹理、变换和颜色生成精灵渲染命令 + */ void Sprite::generateRenderCommand(std::vector &commands, int zOrder) { if (!texture_ || !texture_->isValid()) { diff --git a/Extra2D/src/utils/logger.cpp b/Extra2D/src/utils/logger.cpp index 1f03a2f..7fdf894 100644 --- a/Extra2D/src/utils/logger.cpp +++ b/Extra2D/src/utils/logger.cpp @@ -12,7 +12,7 @@ std::string Logger::logFile_; /** * @brief 获取日志级别字符串 * @param level 日志级别 - * @return 级别字符串 + * @return 级别对应的字符串表示 */ const char *Logger::getLevelString(LogLevel level) { switch (level) { @@ -35,6 +35,8 @@ const char *Logger::getLevelString(LogLevel level) { /** * @brief 初始化日志系统 + * + * 初始化日志系统并设置SDL日志级别为详细模式,允许所有级别的日志输出 */ void Logger::init() { if (initialized_) { @@ -50,6 +52,8 @@ void Logger::init() { /** * @brief 关闭日志系统 + * + * 关闭日志系统并输出关闭日志 */ void Logger::shutdown() { if (initialized_) { @@ -60,7 +64,9 @@ void Logger::shutdown() { /** * @brief 设置日志级别 - * @param level 日志级别 + * @param level 要设置的日志级别 + * + * 设置日志系统的最低输出级别,低于此级别的日志将被忽略 */ void Logger::setLevel(LogLevel level) { level_ = level; @@ -73,7 +79,9 @@ void Logger::setLevel(LogLevel level) { /** * @brief 设置是否输出到控制台 - * @param enable 是否启用 + * @param enable true启用控制台输出,false禁用 + * + * 控制日志是否输出到控制台,通过调整SDL日志优先级实现 */ void Logger::setConsoleOutput(bool enable) { consoleOutput_ = enable; @@ -88,7 +96,9 @@ void Logger::setConsoleOutput(bool enable) { /** * @brief 设置日志输出到文件 - * @param filename 日志文件名 + * @param filename 日志文件路径 + * + * 配置日志输出到指定文件,空字符串则禁用文件输出 */ void Logger::setFileOutput(const std::string &filename) { logFile_ = filename; diff --git a/Extra2D/src/utils/random.cpp b/Extra2D/src/utils/random.cpp index cc2a528..c30dfa5 100644 --- a/Extra2D/src/utils/random.cpp +++ b/Extra2D/src/utils/random.cpp @@ -3,26 +3,54 @@ namespace extra2d { +/** + * @brief 构造函数,初始化随机数生成器 + * + * 使用当前时间作为默认种子初始化随机数生成器 + */ Random::Random() : floatDist_(0.0f, 1.0f) { // 使用当前时间作为默认种子 randomize(); } -Random &Random::getInstance() { +/** + * @brief 获取Random单例实例 + * @return Random单例的引用 + */ +Random &Random::get() { static Random instance; return instance; } +/** + * @brief 设置随机数种子 + * @param seed 随机数种子值 + */ void Random::setSeed(uint32 seed) { generator_.seed(seed); } +/** + * @brief 使用当前时间随机化种子 + * + * 使用高精度时钟的当前时间作为随机数生成器的种子 + */ void Random::randomize() { auto now = std::chrono::high_resolution_clock::now(); auto time = now.time_since_epoch().count(); generator_.seed(static_cast(time)); } +/** + * @brief 获取[0.0, 1.0]范围内的随机浮点数 + * @return 随机浮点数,范围[0.0, 1.0] + */ float Random::getFloat() { return floatDist_(generator_); } +/** + * @brief 获取指定范围内的随机浮点数 + * @param min 最小值 + * @param max 最大值 + * @return 随机浮点数,范围[min, max] + */ float Random::getFloat(float min, float max) { if (min >= max) { return min; @@ -30,6 +58,11 @@ float Random::getFloat(float min, float max) { return min + floatDist_(generator_) * (max - min); } +/** + * @brief 获取[0, max]范围内的随机整数 + * @param max 最大值(包含) + * @return 随机整数,范围[0, max] + */ int Random::getInt(int max) { if (max <= 0) { return 0; @@ -38,6 +71,12 @@ int Random::getInt(int max) { return dist(generator_); } +/** + * @brief 获取指定范围内的随机整数 + * @param min 最小值(包含) + * @param max 最大值(包含) + * @return 随机整数,范围[min, max] + */ int Random::getInt(int min, int max) { if (min >= max) { return min; @@ -46,8 +85,17 @@ int Random::getInt(int min, int max) { return dist(generator_); } +/** + * @brief 获取随机布尔值(50%概率) + * @return 随机布尔值 + */ bool Random::getBool() { return floatDist_(generator_) >= 0.5f; } +/** + * @brief 以指定概率获取随机布尔值 + * @param probability 返回true的概率,范围[0.0, 1.0] + * @return 随机布尔值 + */ bool Random::getBool(float probability) { if (probability <= 0.0f) { return false; @@ -58,11 +106,19 @@ bool Random::getBool(float probability) { return floatDist_(generator_) < probability; } +/** + * @brief 获取随机角度值 + * @return 随机角度,范围[0, 2π] + */ float Random::getAngle() { static const float TWO_PI = 6.28318530718f; return floatDist_(generator_) * TWO_PI; } +/** + * @brief 获取有符号随机数 + * @return 随机浮点数,范围[-1.0, 1.0] + */ float Random::getSigned() { return floatDist_(generator_) * 2.0f - 1.0f; } } // namespace extra2d diff --git a/Extra2D/src/utils/timer.cpp b/Extra2D/src/utils/timer.cpp index ec1ae7d..09e2c4e 100644 --- a/Extra2D/src/utils/timer.cpp +++ b/Extra2D/src/utils/timer.cpp @@ -5,12 +5,23 @@ namespace extra2d { uint32 Timer::nextId_ = 1; +/** + * @brief 构造函数,创建定时器 + * @param interval 定时间隔(秒) + * @param repeat 是否重复触发 + * @param callback 定时器回调函数 + */ Timer::Timer(float interval, bool repeat, Callback callback) : interval_(interval), elapsed_(0.0f), repeat_(repeat), paused_(false), valid_(true), callback_(std::move(callback)) { id_ = nextId_++; } +/** + * @brief 更新定时器状态 + * @param deltaTime 帧间隔时间(秒) + * @return 如果定时器触发则返回true,否则返回false + */ bool Timer::update(float deltaTime) { if (!valid_ || paused_) { return false; @@ -35,18 +46,38 @@ bool Timer::update(float deltaTime) { return false; } +/** + * @brief 重置定时器 + * + * 重置已过时间,恢复定时器为有效且非暂停状态 + */ void Timer::reset() { elapsed_ = 0.0f; valid_ = true; paused_ = false; } +/** + * @brief 暂停定时器 + */ void Timer::pause() { paused_ = true; } +/** + * @brief 恢复定时器 + */ void Timer::resume() { paused_ = false; } +/** + * @brief 取消定时器 + * + * 将定时器标记为无效状态 + */ void Timer::cancel() { valid_ = false; } +/** + * @brief 获取剩余时间 + * @return 剩余时间(秒),如果定时器无效或已暂停则返回0 + */ float Timer::getRemaining() const { if (!valid_ || paused_) { return 0.0f; @@ -58,6 +89,12 @@ float Timer::getRemaining() const { // TimerManager 实现 // ============================================================================ +/** + * @brief 添加单次定时器 + * @param delay 延迟时间(秒) + * @param callback 定时器回调函数 + * @return 定时器ID + */ uint32 TimerManager::addTimer(float delay, Timer::Callback callback) { auto timer = std::make_unique(delay, false, std::move(callback)); uint32 id = timer->getId(); @@ -65,6 +102,12 @@ uint32 TimerManager::addTimer(float delay, Timer::Callback callback) { return id; } +/** + * @brief 添加重复定时器 + * @param interval 触发间隔(秒) + * @param callback 定时器回调函数 + * @return 定时器ID + */ uint32 TimerManager::addRepeatingTimer(float interval, Timer::Callback callback) { auto timer = std::make_unique(interval, true, std::move(callback)); @@ -73,6 +116,10 @@ uint32 TimerManager::addRepeatingTimer(float interval, return id; } +/** + * @brief 取消指定定时器 + * @param timerId 定时器ID + */ void TimerManager::cancelTimer(uint32 timerId) { auto it = timers_.find(timerId); if (it != timers_.end()) { @@ -81,6 +128,10 @@ void TimerManager::cancelTimer(uint32 timerId) { } } +/** + * @brief 暂停指定定时器 + * @param timerId 定时器ID + */ void TimerManager::pauseTimer(uint32 timerId) { auto it = timers_.find(timerId); if (it != timers_.end()) { @@ -88,6 +139,10 @@ void TimerManager::pauseTimer(uint32 timerId) { } } +/** + * @brief 恢复指定定时器 + * @param timerId 定时器ID + */ void TimerManager::resumeTimer(uint32 timerId) { auto it = timers_.find(timerId); if (it != timers_.end()) { @@ -95,6 +150,12 @@ void TimerManager::resumeTimer(uint32 timerId) { } } +/** + * @brief 更新所有定时器 + * @param deltaTime 帧间隔时间(秒) + * + * 更新所有定时器状态,并移除已失效的定时器 + */ void TimerManager::update(float deltaTime) { timersToRemove_.clear(); @@ -110,6 +171,9 @@ void TimerManager::update(float deltaTime) { } } +/** + * @brief 清除所有定时器 + */ void TimerManager::clear() { timers_.clear(); timersToRemove_.clear(); diff --git a/xmake.lua b/xmake.lua index bb95807..e24dc8b 100644 --- a/xmake.lua +++ b/xmake.lua @@ -79,14 +79,3 @@ includes("xmake/engine.lua") -- 定义引擎库 define_extra2d_engine() --- ============================================== --- 项目信息输出 --- ============================================== - -print("========================================") -print("Extra2D Build Configuration") -print("========================================") -print("Platform: " .. target_plat) -print("Architecture: " .. (get_config("arch") or "auto")) -print("Mode: " .. (is_mode("debug") and "debug" or "release")) -print("========================================")