refactor: 统一方法命名规范并优化代码文档

- 将单例方法名从getInstance统一改为get
- 重命名边界框相关方法为getBounds
- 重命名位置相关方法为setPos/getPos
- 优化代码注释,增加详细文档说明
- 移除调试信息输出
- 统一命名管理器类后缀为Mgr
- 重构节点相关方法名,如removeFromParent改为detach
- 统一坐标转换方法命名为toWorld/toLocal
This commit is contained in:
ChestnutYueyue 2026-02-14 23:59:19 +08:00
parent c6c90a7374
commit 387ea62853
47 changed files with 3059 additions and 233 deletions

View File

@ -36,7 +36,7 @@ struct AppConfig {
*/ */
class Application { class Application {
public: public:
static Application &instance(); static Application &get();
Application(const Application &) = delete; Application(const Application &) = delete;
Application &operator=(const Application &) = delete; Application &operator=(const Application &) = delete;

View File

@ -22,8 +22,8 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 位置和变换 // 位置和变换
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setPosition(const Vec2 &position); void setPos(const Vec2 &position);
void setPosition(float x, float y); void setPos(float x, float y);
Vec2 getPosition() const { return position_; } Vec2 getPosition() const { return position_; }
void setRotation(float degrees); void setRotation(float degrees);
@ -74,7 +74,7 @@ public:
* @brief * @brief
* @param adapter * @param adapter
*/ */
void setViewportAdapter(ViewportAdapter* adapter); void setViewportAdapter(ViewportAdapter *adapter);
/** /**
* @brief * @brief
@ -99,7 +99,7 @@ private:
Rect bounds_; Rect bounds_;
bool hasBounds_ = false; bool hasBounds_ = false;
ViewportAdapter* viewportAdapter_ = nullptr; ViewportAdapter *viewportAdapter_ = nullptr;
mutable glm::mat4 viewMatrix_; mutable glm::mat4 viewMatrix_;
mutable glm::mat4 projMatrix_; mutable glm::mat4 projMatrix_;

View File

@ -13,7 +13,7 @@ namespace extra2d {
class GPUContext { class GPUContext {
public: public:
/// 获取单例实例 /// 获取单例实例
static GPUContext& getInstance(); static GPUContext& get();
/// 标记 GPU 上下文为有效(在初始化完成后调用) /// 标记 GPU 上下文为有效(在初始化完成后调用)
void markValid(); void markValid();

View File

@ -233,7 +233,7 @@ private:
// ============================================================================ // ============================================================================
class RenderTargetStack { class RenderTargetStack {
public: public:
static RenderTargetStack &getInstance(); static RenderTargetStack &get();
/** /**
* @brief * @brief
@ -271,12 +271,12 @@ private:
// ============================================================================ // ============================================================================
// 渲染目标管理器 - 全局渲染目标管理 // 渲染目标管理器 - 全局渲染目标管理
// ============================================================================ // ============================================================================
class RenderTargetManager { class RenderTargetMgr {
public: public:
/** /**
* @brief * @brief
*/ */
static RenderTargetManager &getInstance(); static RenderTargetMgr& get();
/** /**
* @brief * @brief
@ -313,10 +313,10 @@ public:
bool isInitialized() const { return initialized_; } bool isInitialized() const { return initialized_; }
private: private:
RenderTargetManager() = default; RenderTargetMgr() = default;
~RenderTargetManager() = default; ~RenderTargetMgr() = default;
RenderTargetManager(const RenderTargetManager &) = delete; RenderTargetMgr(const RenderTargetMgr &) = delete;
RenderTargetManager &operator=(const RenderTargetManager &) = delete; RenderTargetMgr &operator=(const RenderTargetMgr &) = delete;
Ptr<RenderTarget> defaultRenderTarget_; Ptr<RenderTarget> defaultRenderTarget_;
std::vector<Ptr<RenderTarget>> renderTargets_; std::vector<Ptr<RenderTarget>> renderTargets_;
@ -326,8 +326,7 @@ private:
// ============================================================================ // ============================================================================
// 便捷宏 // 便捷宏
// ============================================================================ // ============================================================================
#define E2D_RENDER_TARGET_STACK() ::extra2d::RenderTargetStack::getInstance() #define E2D_RENDER_TARGET_STACK() ::extra2d::RenderTargetStack::get()
#define E2D_RENDER_TARGET_MANAGER() \ #define E2D_RENDER_TARGET_MGR() ::extra2d::RenderTargetMgr::get()
::extra2d::RenderTargetManager::getInstance()
} // namespace extra2d } // namespace extra2d

View File

@ -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 } // namespace extra2d

View File

@ -146,9 +146,9 @@ private:
/** /**
* @brief * @brief
*/ */
class TextureAtlasManager { class TextureAtlasMgr {
public: public:
static TextureAtlasManager& getInstance(); static TextureAtlasMgr& get();
// 获取主图集 // 获取主图集
TextureAtlas& getAtlas() { return atlas_; } TextureAtlas& getAtlas() { return atlas_; }
@ -172,11 +172,11 @@ public:
} }
private: private:
TextureAtlasManager() = default; TextureAtlasMgr() = default;
~TextureAtlasManager() = default; ~TextureAtlasMgr() = default;
TextureAtlasManager(const TextureAtlasManager&) = delete; TextureAtlasMgr(const TextureAtlasMgr&) = delete;
TextureAtlasManager& operator=(const TextureAtlasManager&) = delete; TextureAtlasMgr& operator=(const TextureAtlasMgr&) = delete;
TextureAtlas atlas_; TextureAtlas atlas_;
}; };

View File

@ -171,13 +171,13 @@ public:
* @brief * @brief
* @return * @return
*/ */
glm::mat4 getViewportMatrix() const; glm::mat4 getMatrix() const;
/** /**
* @brief * @brief
* @return * @return
*/ */
glm::mat4 getInverseViewportMatrix() const; glm::mat4 getInvMatrix() const;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 区域检测 // 区域检测

View File

@ -9,9 +9,9 @@ namespace extra2d {
// ============================================================================ // ============================================================================
// VRAM 管理器 - 跟踪显存使用情况 // VRAM 管理器 - 跟踪显存使用情况
// ============================================================================ // ============================================================================
class VRAMManager { class VRAMMgr {
public: public:
static VRAMManager& getInstance(); static VRAMMgr& get();
// 纹理显存跟踪 // 纹理显存跟踪
void allocTexture(size_t size); void allocTexture(size_t size);
@ -39,10 +39,10 @@ public:
void reset(); void reset();
private: private:
VRAMManager(); VRAMMgr();
~VRAMManager() = default; ~VRAMMgr() = default;
VRAMManager(const VRAMManager&) = delete; VRAMMgr(const VRAMMgr&) = delete;
VRAMManager& operator=(const VRAMManager&) = delete; VRAMMgr& operator=(const VRAMMgr&) = delete;
mutable std::mutex mutex_; mutable std::mutex mutex_;

View File

@ -96,13 +96,13 @@ public:
* @brief * @brief
* @return * @return
*/ */
Vec2 getMousePositionLogic() const; Vec2 getMousePosLogic() const;
/** /**
* @brief * @brief
* @return * @return
*/ */
Vec2 getTouchPositionLogic() const; Vec2 getTouchPosLogic() const;
/** /**
* @brief * @brief

View File

@ -66,7 +66,7 @@ public:
// 窗口属性 // 窗口属性
void setTitle(const std::string &title); void setTitle(const std::string &title);
void setSize(int width, int height); void setSize(int width, int height);
void setPosition(int x, int y); void setPos(int x, int y);
void setFullscreen(bool fullscreen); void setFullscreen(bool fullscreen);
void setVSync(bool enabled); void setVSync(bool enabled);
void setResizable(bool resizable); void setResizable(bool resizable);

View File

@ -37,19 +37,19 @@ public:
void removeChild(Ptr<Node> child); void removeChild(Ptr<Node> child);
void removeChildByName(const std::string &name); void removeChildByName(const std::string &name);
void removeFromParent(); void detach();
void removeAllChildren(); void clearChildren();
Ptr<Node> getParent() const { return parent_.lock(); } Ptr<Node> getParent() const { return parent_.lock(); }
const std::vector<Ptr<Node>> &getChildren() const { return children_; } const std::vector<Ptr<Node>> &getChildren() const { return children_; }
Ptr<Node> getChildByName(const std::string &name) const; Ptr<Node> findChild(const std::string &name) const;
Ptr<Node> getChildByTag(int tag) const; Ptr<Node> findChildByTag(int tag) const;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 变换属性 // 变换属性
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setPosition(const Vec2 &pos); void setPos(const Vec2 &pos);
void setPosition(float x, float y); void setPos(float x, float y);
Vec2 getPosition() const { return position_; } Vec2 getPosition() const { return position_; }
void setRotation(float degrees); void setRotation(float degrees);
@ -99,8 +99,8 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 世界变换 // 世界变换
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
Vec2 convertToWorldSpace(const Vec2 &localPos) const; Vec2 toWorld(const Vec2 &localPos) const;
Vec2 convertToNodeSpace(const Vec2 &worldPos) const; Vec2 toLocal(const Vec2 &worldPos) const;
glm::mat4 getLocalTransform() const; glm::mat4 getLocalTransform() const;
glm::mat4 getWorldTransform() const; glm::mat4 getWorldTransform() const;
@ -114,7 +114,7 @@ public:
* @brief * @brief
* *
*/ */
void batchUpdateTransforms(); void batchTransforms();
/** /**
* @brief * @brief
@ -144,7 +144,7 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 边界框 // 边界框
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
virtual Rect getBoundingBox() const; virtual Rect getBounds() const;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 事件系统 // 事件系统

View File

@ -20,7 +20,7 @@ class SceneManager {
public: public:
using TransitionCallback = std::function<void()>; using TransitionCallback = std::function<void()>;
static SceneManager &getInstance(); static SceneManager &get();
void runWithScene(Ptr<Scene> scene); void runWithScene(Ptr<Scene> scene);
void replaceScene(Ptr<Scene> scene); void replaceScene(Ptr<Scene> scene);

View File

@ -85,7 +85,7 @@ public:
void addPoint(const Vec2 &point); void addPoint(const Vec2 &point);
void clearPoints(); void clearPoints();
Rect getBoundingBox() const override; Rect getBounds() const override;
protected: protected:
void onDraw(RenderBackend &renderer) override; void onDraw(RenderBackend &renderer) override;

View File

@ -37,7 +37,7 @@ public:
static Ptr<Sprite> create(Ptr<Texture> texture); static Ptr<Sprite> create(Ptr<Texture> texture);
static Ptr<Sprite> create(Ptr<Texture> texture, const Rect &rect); static Ptr<Sprite> create(Ptr<Texture> texture, const Rect &rect);
Rect getBoundingBox() const override; Rect getBounds() const override;
protected: protected:
void onDraw(RenderBackend &renderer) override; void onDraw(RenderBackend &renderer) override;

View File

@ -11,7 +11,7 @@ namespace extra2d {
class Random { class Random {
public: public:
/// 获取单例实例 /// 获取单例实例
static Random &getInstance(); static Random &get();
/// 设置随机种子 /// 设置随机种子
void setSeed(uint32 seed); void setSeed(uint32 seed);
@ -59,27 +59,27 @@ private:
// ============================================================================ // ============================================================================
/// 获取 [0, 1) 范围内的随机浮点数 /// 获取 [0, 1) 范围内的随机浮点数
inline float randomFloat() { return Random::getInstance().getFloat(); } inline float randomFloat() { return Random::get().getFloat(); }
/// 获取 [min, max] 范围内的随机浮点数 /// 获取 [min, max] 范围内的随机浮点数
inline float randomFloat(float min, float max) { inline float randomFloat(float min, float max) {
return Random::getInstance().getFloat(min, max); return Random::get().getFloat(min, max);
} }
/// 获取 [0, 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] 范围内的随机整数 /// 获取 [min, max] 范围内的随机整数
inline int randomInt(int min, int 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) { inline bool randomBool(float probability) {
return Random::getInstance().getBool(probability); return Random::get().getBool(probability);
} }
} // namespace extra2d } // namespace extra2d

View File

@ -22,6 +22,10 @@ namespace extra2d {
/** /**
* @brief * @brief
* @return
*
* 使Switch平台使用clock_gettime
* 使std::chrono::steady_clock
*/ */
static double getTimeSeconds() { static double getTimeSeconds() {
#ifdef __SWITCH__ #ifdef __SWITCH__
@ -37,13 +41,27 @@ static double getTimeSeconds() {
#endif #endif
} }
Application &Application::instance() { /**
* @brief Application单例实例
* @return Application单例的引用
*/
Application &Application::get() {
static Application instance; static Application instance;
return instance; return instance;
} }
/**
* @brief
*/
Application::~Application() { shutdown(); } Application::~Application() { shutdown(); }
/**
* @brief
* @param config
* @return truefalse
*
*
*/
bool Application::init(const AppConfig &config) { bool Application::init(const AppConfig &config) {
if (initialized_) { if (initialized_) {
E2D_LOG_WARN("Application already initialized"); E2D_LOG_WARN("Application already initialized");
@ -156,13 +174,18 @@ bool Application::init(const AppConfig &config) {
return true; return true;
} }
/**
* @brief
*
*
*/
void Application::shutdown() { void Application::shutdown() {
if (!initialized_) if (!initialized_)
return; return;
E2D_LOG_INFO("Shutting down application..."); E2D_LOG_INFO("Shutting down application...");
VRAMManager::getInstance().printStats(); VRAMMgr::get().printStats();
if (sceneManager_) { if (sceneManager_) {
sceneManager_->end(); sceneManager_->end();
@ -207,6 +230,11 @@ void Application::shutdown() {
E2D_LOG_INFO("Application shutdown complete"); E2D_LOG_INFO("Application shutdown complete");
} }
/**
* @brief
*
* 退
*/
void Application::run() { void Application::run() {
if (!initialized_) { if (!initialized_) {
E2D_LOG_ERROR("Application not initialized"); E2D_LOG_ERROR("Application not initialized");
@ -226,11 +254,21 @@ void Application::run() {
#endif #endif
} }
/**
* @brief 退
*
* 退退
*/
void Application::quit() { void Application::quit() {
shouldQuit_ = true; shouldQuit_ = true;
running_ = false; running_ = false;
} }
/**
* @brief
*
*
*/
void Application::pause() { void Application::pause() {
if (!paused_) { if (!paused_) {
paused_ = true; paused_ = true;
@ -238,6 +276,11 @@ void Application::pause() {
} }
} }
/**
* @brief
*
* deltaTime跳跃
*/
void Application::resume() { void Application::resume() {
if (paused_) { if (paused_) {
paused_ = false; paused_ = false;
@ -246,6 +289,11 @@ void Application::resume() {
} }
} }
/**
* @brief
*
*
*/
void Application::mainLoop() { void Application::mainLoop() {
double currentTime = getTimeSeconds(); double currentTime = getTimeSeconds();
deltaTime_ = static_cast<float>(currentTime - lastFrameTime_); deltaTime_ = static_cast<float>(currentTime - lastFrameTime_);
@ -284,6 +332,11 @@ void Application::mainLoop() {
} }
} }
/**
* @brief
*
*
*/
void Application::update() { void Application::update() {
if (timerManager_) { if (timerManager_) {
timerManager_->update(deltaTime_); timerManager_->update(deltaTime_);
@ -294,6 +347,11 @@ void Application::update() {
} }
} }
/**
* @brief
*
*
*/
void Application::render() { void Application::render() {
if (!renderer_) { if (!renderer_) {
E2D_LOG_ERROR("Render failed: renderer is null"); E2D_LOG_ERROR("Render failed: renderer is null");
@ -318,20 +376,54 @@ void Application::render() {
window_->swapBuffers(); window_->swapBuffers();
} }
/**
* @brief
* @return
*/
Input &Application::input() { return *window_->getInput(); } Input &Application::input() { return *window_->getInput(); }
/**
* @brief
* @return
*/
SceneManager &Application::scenes() { return *sceneManager_; } SceneManager &Application::scenes() { return *sceneManager_; }
/**
* @brief
* @return
*/
TimerManager &Application::timers() { return *timerManager_; } TimerManager &Application::timers() { return *timerManager_; }
/**
* @brief
* @return
*/
EventQueue &Application::eventQueue() { return *eventQueue_; } EventQueue &Application::eventQueue() { return *eventQueue_; }
/**
* @brief
* @return
*/
EventDispatcher &Application::eventDispatcher() { return *eventDispatcher_; } EventDispatcher &Application::eventDispatcher() { return *eventDispatcher_; }
/**
* @brief
* @return
*/
Camera &Application::camera() { return *camera_; } Camera &Application::camera() { return *camera_; }
/**
* @brief
* @return
*/
ViewportAdapter &Application::viewportAdapter() { return *viewportAdapter_; } ViewportAdapter &Application::viewportAdapter() { return *viewportAdapter_; }
/**
* @brief
* @param scene
*
*
*/
void Application::enterScene(Ptr<Scene> scene) { void Application::enterScene(Ptr<Scene> scene) {
if (sceneManager_ && scene) { if (sceneManager_ && scene) {
scene->setViewportSize(static_cast<float>(window_->getWidth()), scene->setViewportSize(static_cast<float>(window_->getWidth()),

View File

@ -2,6 +2,15 @@
namespace extra2d { namespace extra2d {
/**
* @brief
*
* Event对象
*
* @param width
* @param height
* @return Event对象
*/
Event Event::createWindowResize(int width, int height) { Event Event::createWindowResize(int width, int height) {
Event event; Event event;
event.type = EventType::WindowResize; event.type = EventType::WindowResize;
@ -9,12 +18,29 @@ Event Event::createWindowResize(int width, int height) {
return event; return event;
} }
/**
* @brief
*
* Event对象
*
* @return Event对象
*/
Event Event::createWindowClose() { Event Event::createWindowClose() {
Event event; Event event;
event.type = EventType::WindowClose; event.type = EventType::WindowClose;
return event; return event;
} }
/**
* @brief
*
* Event对象
*
* @param keyCode
* @param scancode
* @param mods ShiftCtrl等
* @return Event对象
*/
Event Event::createKeyPress(int keyCode, int scancode, int mods) { Event Event::createKeyPress(int keyCode, int scancode, int mods) {
Event event; Event event;
event.type = EventType::KeyPressed; event.type = EventType::KeyPressed;
@ -22,6 +48,16 @@ Event Event::createKeyPress(int keyCode, int scancode, int mods) {
return event; return event;
} }
/**
* @brief
*
* Event对象
*
* @param keyCode
* @param scancode
* @param mods ShiftCtrl等
* @return Event对象
*/
Event Event::createKeyRelease(int keyCode, int scancode, int mods) { Event Event::createKeyRelease(int keyCode, int scancode, int mods) {
Event event; Event event;
event.type = EventType::KeyReleased; event.type = EventType::KeyReleased;
@ -29,6 +65,16 @@ Event Event::createKeyRelease(int keyCode, int scancode, int mods) {
return event; return event;
} }
/**
* @brief
*
* Event对象
*
* @param button
* @param mods
* @param pos
* @return Event对象
*/
Event Event::createMouseButtonPress(int button, int mods, const Vec2 &pos) { Event Event::createMouseButtonPress(int button, int mods, const Vec2 &pos) {
Event event; Event event;
event.type = EventType::MouseButtonPressed; event.type = EventType::MouseButtonPressed;
@ -36,6 +82,16 @@ Event Event::createMouseButtonPress(int button, int mods, const Vec2 &pos) {
return event; return event;
} }
/**
* @brief
*
* Event对象
*
* @param button
* @param mods
* @param pos
* @return Event对象
*/
Event Event::createMouseButtonRelease(int button, int mods, const Vec2 &pos) { Event Event::createMouseButtonRelease(int button, int mods, const Vec2 &pos) {
Event event; Event event;
event.type = EventType::MouseButtonReleased; event.type = EventType::MouseButtonReleased;
@ -43,6 +99,15 @@ Event Event::createMouseButtonRelease(int button, int mods, const Vec2 &pos) {
return event; return event;
} }
/**
* @brief
*
* Event对象
*
* @param pos
* @param delta
* @return Event对象
*/
Event Event::createMouseMove(const Vec2 &pos, const Vec2 &delta) { Event Event::createMouseMove(const Vec2 &pos, const Vec2 &delta) {
Event event; Event event;
event.type = EventType::MouseMoved; event.type = EventType::MouseMoved;
@ -50,6 +115,15 @@ Event Event::createMouseMove(const Vec2 &pos, const Vec2 &delta) {
return event; return event;
} }
/**
* @brief
*
* Event对象
*
* @param offset
* @param pos
* @return Event对象
*/
Event Event::createMouseScroll(const Vec2 &offset, const Vec2 &pos) { Event Event::createMouseScroll(const Vec2 &offset, const Vec2 &pos) {
Event event; Event event;
event.type = EventType::MouseScrolled; event.type = EventType::MouseScrolled;

View File

@ -3,8 +3,22 @@
namespace extra2d { namespace extra2d {
/**
* @brief
*
* ID为1
*/
EventDispatcher::EventDispatcher() : nextId_(1) {} EventDispatcher::EventDispatcher() : nextId_(1) {}
/**
* @brief
*
* ID用于后续移除
*
* @param type
* @param callback
* @return ID
*/
ListenerId EventDispatcher::addListener(EventType type, ListenerId EventDispatcher::addListener(EventType type,
EventCallback callback) { EventCallback callback) {
ListenerId id = nextId_++; ListenerId id = nextId_++;
@ -12,6 +26,13 @@ ListenerId EventDispatcher::addListener(EventType type,
return id; return id;
} }
/**
* @brief
*
* ID移除对应的事件监听器
*
* @param id ID
*/
void EventDispatcher::removeListener(ListenerId id) { void EventDispatcher::removeListener(ListenerId id) {
for (auto &[type, listeners] : listeners_) { for (auto &[type, listeners] : listeners_) {
auto it = std::remove_if(listeners.begin(), listeners.end(), 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) { void EventDispatcher::removeAllListeners(EventType type) {
listeners_.erase(type); listeners_.erase(type);
} }
/**
* @brief
*
*
*/
void EventDispatcher::removeAllListeners() { listeners_.clear(); } void EventDispatcher::removeAllListeners() { listeners_.clear(); }
/**
* @brief
*
*
*
* @param event
*/
void EventDispatcher::dispatch(Event &event) { void EventDispatcher::dispatch(Event &event) {
auto it = listeners_.find(event.type); auto it = listeners_.find(event.type);
if (it != listeners_.end()) { if (it != listeners_.end()) {
@ -40,11 +80,25 @@ void EventDispatcher::dispatch(Event &event) {
} }
} }
/**
* @brief
*
*
*
* @param event
*/
void EventDispatcher::dispatch(const Event &event) { void EventDispatcher::dispatch(const Event &event) {
Event mutableEvent = event; Event mutableEvent = event;
dispatch(mutableEvent); dispatch(mutableEvent);
} }
/**
* @brief
*
*
*
* @param queue
*/
void EventDispatcher::processQueue(EventQueue &queue) { void EventDispatcher::processQueue(EventQueue &queue) {
Event event; Event event;
while (queue.poll(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 { size_t EventDispatcher::getListenerCount(EventType type) const {
auto it = listeners_.find(type); auto it = listeners_.find(type);
return (it != listeners_.end()) ? it->second.size() : 0; return (it != listeners_.end()) ? it->second.size() : 0;
} }
/**
* @brief
*
*
*
* @return
*/
size_t EventDispatcher::getTotalListenerCount() const { size_t EventDispatcher::getTotalListenerCount() const {
size_t count = 0; size_t count = 0;
for (const auto &[type, listeners] : listeners_) { for (const auto &[type, listeners] : listeners_) {

View File

@ -2,18 +2,45 @@
namespace extra2d { namespace extra2d {
/**
* @brief
*
*
*/
EventQueue::EventQueue() = default; EventQueue::EventQueue() = default;
/**
* @brief
*
* 线
*
* @param event
*/
void EventQueue::push(const Event &event) { void EventQueue::push(const Event &event) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
queue_.push(event); queue_.push(event);
} }
/**
* @brief
*
* 线
*
* @param event
*/
void EventQueue::push(Event &&event) { void EventQueue::push(Event &&event) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
queue_.push(std::move(event)); queue_.push(std::move(event));
} }
/**
* @brief
*
* 线
*
* @param event
* @return truefalse
*/
bool EventQueue::poll(Event &event) { bool EventQueue::poll(Event &event) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
if (queue_.empty()) { if (queue_.empty()) {
@ -24,6 +51,14 @@ bool EventQueue::poll(Event &event) {
return true; return true;
} }
/**
* @brief
*
* 线
*
* @param event
* @return truefalse
*/
bool EventQueue::peek(Event &event) const { bool EventQueue::peek(Event &event) const {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
if (queue_.empty()) { if (queue_.empty()) {
@ -33,6 +68,11 @@ bool EventQueue::peek(Event &event) const {
return true; return true;
} }
/**
* @brief
*
* 线
*/
void EventQueue::clear() { void EventQueue::clear() {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
while (!queue_.empty()) { while (!queue_.empty()) {
@ -40,11 +80,25 @@ void EventQueue::clear() {
} }
} }
/**
* @brief
*
* 线
*
* @return truefalse
*/
bool EventQueue::empty() const { bool EventQueue::empty() const {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
return queue_.empty(); return queue_.empty();
} }
/**
* @brief
*
* 线
*
* @return
*/
size_t EventQueue::size() const { size_t EventQueue::size() const {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
return queue_.size(); return queue_.size();

View File

@ -2,9 +2,29 @@
namespace extra2d { namespace extra2d {
/**
* @brief
*
* Alpha遮罩255
*
* @param width
* @param height
*/
AlphaMask::AlphaMask(int width, int height) AlphaMask::AlphaMask(int width, int height)
: width_(width), height_(height), data_(width * height, 255) {} : width_(width), height_(height), data_(width * height, 255) {}
/**
* @brief Alpha遮罩
*
* Alpha通道创建遮罩
* RGBA4RGB31
*
* @param pixels
* @param width
* @param height
* @param channels 134
* @return Alpha遮罩对象
*/
AlphaMask AlphaMask::createFromPixels(const uint8_t *pixels, int width, AlphaMask AlphaMask::createFromPixels(const uint8_t *pixels, int width,
int height, int channels) { int height, int channels) {
AlphaMask mask(width, height); AlphaMask mask(width, height);
@ -37,6 +57,15 @@ AlphaMask AlphaMask::createFromPixels(const uint8_t *pixels, int width,
return mask; return mask;
} }
/**
* @brief Alpha值
*
* Alpha值0
*
* @param x X坐标
* @param y Y坐标
* @return Alpha值0-2550
*/
uint8_t AlphaMask::getAlpha(int x, int y) const { uint8_t AlphaMask::getAlpha(int x, int y) const {
if (!isValid(x, y)) { if (!isValid(x, y)) {
return 0; return 0;
@ -44,10 +73,29 @@ uint8_t AlphaMask::getAlpha(int x, int y) const {
return data_[y * width_ + x]; return data_[y * width_ + x];
} }
/**
* @brief
*
* Alpha值是否大于等于给定的阈值
*
* @param x X坐标
* @param y Y坐标
* @param threshold 255
* @return Alpha值大于等于阈值返回truefalse
*/
bool AlphaMask::isOpaque(int x, int y, uint8_t threshold) const { bool AlphaMask::isOpaque(int x, int y, uint8_t threshold) const {
return getAlpha(x, y) >= threshold; return getAlpha(x, y) >= threshold;
} }
/**
* @brief
*
*
*
* @param x X坐标
* @param y Y坐标
* @return truefalse
*/
bool AlphaMask::isValid(int x, int y) const { bool AlphaMask::isValid(int x, int y) const {
return x >= 0 && x < width_ && y >= 0 && y < height_; return x >= 0 && x < width_ && y >= 0 && y < height_;
} }

View File

@ -1,42 +1,97 @@
#include <algorithm> #include <algorithm>
#include <extra2d/graphics/camera.h> #include <extra2d/graphics/camera.h>
#include <extra2d/graphics/viewport_adapter.h> #include <extra2d/graphics/viewport_adapter.h>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/matrix_inverse.hpp> #include <glm/gtc/matrix_inverse.hpp>
#include <glm/gtc/matrix_transform.hpp>
namespace extra2d { namespace extra2d {
/**
* @brief
*
* (-1, -1) (1, 1)
*/
Camera::Camera() : left_(-1.0f), right_(1.0f), bottom_(-1.0f), top_(1.0f) {} 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) Camera::Camera(float left, float right, float bottom, float top)
: left_(left), right_(right), bottom_(bottom), top_(top) {} : left_(left), right_(right), bottom_(bottom), top_(top) {}
/**
* @brief
* @param viewport
*
*
*/
Camera::Camera(const Size &viewport) Camera::Camera(const Size &viewport)
: left_(0.0f), right_(viewport.width), bottom_(viewport.height), : left_(0.0f), right_(viewport.width), bottom_(viewport.height),
top_(0.0f) {} top_(0.0f) {}
void Camera::setPosition(const Vec2 &position) { /**
* @brief
* @param position
*
*
*/
void Camera::setPos(const Vec2 &position) {
position_ = position; position_ = position;
viewDirty_ = true; 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_.x = x;
position_.y = y; position_.y = y;
viewDirty_ = true; viewDirty_ = true;
} }
/**
* @brief
* @param degrees
*
*
*/
void Camera::setRotation(float degrees) { void Camera::setRotation(float degrees) {
rotation_ = degrees; rotation_ = degrees;
viewDirty_ = true; viewDirty_ = true;
} }
/**
* @brief
* @param zoom 1.0
*
*
*/
void Camera::setZoom(float zoom) { void Camera::setZoom(float zoom) {
zoom_ = zoom; zoom_ = zoom;
viewDirty_ = true; viewDirty_ = true;
projDirty_ = true; projDirty_ = true;
} }
/**
* @brief
* @param left
* @param right
* @param bottom
* @param top
*
*
*/
void Camera::setViewport(float left, float right, float bottom, float top) { void Camera::setViewport(float left, float right, float bottom, float top) {
left_ = left; left_ = left;
right_ = right; right_ = right;
@ -45,6 +100,12 @@ void Camera::setViewport(float left, float right, float bottom, float top) {
projDirty_ = true; projDirty_ = true;
} }
/**
* @brief
* @param rect
*
* 使
*/
void Camera::setViewport(const Rect &rect) { void Camera::setViewport(const Rect &rect) {
left_ = rect.left(); left_ = rect.left();
right_ = rect.right(); right_ = rect.right();
@ -53,6 +114,12 @@ void Camera::setViewport(const Rect &rect) {
projDirty_ = true; projDirty_ = true;
} }
/**
* @brief
* @return
*
*
*/
Rect Camera::getViewport() const { Rect Camera::getViewport() const {
return Rect(left_, top_, right_ - left_, bottom_ - top_); return Rect(left_, top_, right_ - left_, bottom_ - top_);
} }
@ -60,36 +127,42 @@ Rect Camera::getViewport() const {
/** /**
* @brief * @brief
* @return * @return
* *
* -> -> * -> ->
* View = T(-position) × R(-rotation) × S(1/zoom) * View = T(-position) × R(-rotation) × S(1/zoom)
*/ */
glm::mat4 Camera::getViewMatrix() const { glm::mat4 Camera::getViewMatrix() const {
if (viewDirty_) { if (viewDirty_) {
viewMatrix_ = glm::mat4(1.0f); viewMatrix_ = glm::mat4(1.0f);
// 1. 平移(最后应用) // 1. 平移(最后应用)
viewMatrix_ = glm::translate(viewMatrix_, viewMatrix_ = glm::translate(viewMatrix_,
glm::vec3(-position_.x, -position_.y, 0.0f)); glm::vec3(-position_.x, -position_.y, 0.0f));
// 2. 旋转(中间应用) // 2. 旋转(中间应用)
if (rotation_ != 0.0f) { if (rotation_ != 0.0f) {
viewMatrix_ = glm::rotate(viewMatrix_, viewMatrix_ = glm::rotate(viewMatrix_, -rotation_ * DEG_TO_RAD,
-rotation_ * DEG_TO_RAD,
glm::vec3(0.0f, 0.0f, 1.0f)); glm::vec3(0.0f, 0.0f, 1.0f));
} }
// 3. 缩放(最先应用) // 3. 缩放(最先应用)
if (zoom_ != 1.0f) { if (zoom_ != 1.0f) {
viewMatrix_ = glm::scale(viewMatrix_, viewMatrix_ =
glm::vec3(1.0f / zoom_, 1.0f / zoom_, 1.0f)); glm::scale(viewMatrix_, glm::vec3(1.0f / zoom_, 1.0f / zoom_, 1.0f));
} }
viewDirty_ = false; viewDirty_ = false;
} }
return viewMatrix_; return viewMatrix_;
} }
/**
* @brief
* @return
*
* 2D游戏Y轴向下增长
* OpenGL默认Y轴向上Y轴
*/
glm::mat4 Camera::getProjectionMatrix() const { glm::mat4 Camera::getProjectionMatrix() const {
if (projDirty_) { if (projDirty_) {
// 对于2D游戏Y轴向下增长屏幕坐标系 // 对于2D游戏Y轴向下增长屏幕坐标系
@ -120,12 +193,12 @@ glm::mat4 Camera::getViewProjectionMatrix() const {
*/ */
Vec2 Camera::screenToWorld(const Vec2 &screenPos) const { Vec2 Camera::screenToWorld(const Vec2 &screenPos) const {
Vec2 logicPos = screenPos; Vec2 logicPos = screenPos;
// 如果有视口适配器,先转换到逻辑坐标 // 如果有视口适配器,先转换到逻辑坐标
if (viewportAdapter_) { if (viewportAdapter_) {
logicPos = viewportAdapter_->screenToLogic(screenPos); logicPos = viewportAdapter_->screenToLogic(screenPos);
} }
// 使用逆视图-投影矩阵转换 // 使用逆视图-投影矩阵转换
glm::mat4 invVP = glm::inverse(getViewProjectionMatrix()); glm::mat4 invVP = glm::inverse(getViewProjectionMatrix());
glm::vec4 ndc(logicPos.x, logicPos.y, 0.0f, 1.0f); 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 world(worldPos.x, worldPos.y, 0.0f, 1.0f);
glm::vec4 screen = getViewProjectionMatrix() * world; glm::vec4 screen = getViewProjectionMatrix() * world;
Vec2 logicPos(screen.x, screen.y); Vec2 logicPos(screen.x, screen.y);
// 如果有视口适配器,转换到屏幕坐标 // 如果有视口适配器,转换到屏幕坐标
if (viewportAdapter_) { if (viewportAdapter_) {
return viewportAdapter_->logicToScreen(logicPos); return viewportAdapter_->logicToScreen(logicPos);
@ -150,32 +223,73 @@ Vec2 Camera::worldToScreen(const Vec2 &worldPos) const {
return logicPos; return logicPos;
} }
/**
* @brief
* @param x X坐标
* @param y Y坐标
* @return
*/
Vec2 Camera::screenToWorld(float x, float y) const { Vec2 Camera::screenToWorld(float x, float y) const {
return screenToWorld(Vec2(x, y)); return screenToWorld(Vec2(x, y));
} }
/**
* @brief
* @param x X坐标
* @param y Y坐标
* @return
*/
Vec2 Camera::worldToScreen(float x, float y) const { Vec2 Camera::worldToScreen(float x, float y) const {
return worldToScreen(Vec2(x, y)); return worldToScreen(Vec2(x, y));
} }
/**
* @brief
* @param offset
*
*
*/
void Camera::move(const Vec2 &offset) { void Camera::move(const Vec2 &offset) {
position_ += offset; position_ += offset;
viewDirty_ = true; viewDirty_ = true;
} }
/**
* @brief
* @param x X方向偏移量
* @param y Y方向偏移量
*
*
*/
void Camera::move(float x, float y) { void Camera::move(float x, float y) {
position_.x += x; position_.x += x;
position_.y += y; position_.y += y;
viewDirty_ = true; viewDirty_ = true;
} }
/**
* @brief
* @param bounds
*
*
*/
void Camera::setBounds(const Rect &bounds) { void Camera::setBounds(const Rect &bounds) {
bounds_ = bounds; bounds_ = bounds;
hasBounds_ = true; hasBounds_ = true;
} }
/**
* @brief
*
*
*/
void Camera::clearBounds() { hasBounds_ = false; } void Camera::clearBounds() { hasBounds_ = false; }
/**
* @brief
*
*
*/
void Camera::clampToBounds() { void Camera::clampToBounds() {
if (!hasBounds_) if (!hasBounds_)
return; return;
@ -203,6 +317,12 @@ void Camera::clampToBounds() {
viewDirty_ = true; viewDirty_ = true;
} }
/**
* @brief
* @param target
*
*
*/
void Camera::lookAt(const Vec2 &target) { void Camera::lookAt(const Vec2 &target) {
position_ = target; position_ = target;
viewDirty_ = true; viewDirty_ = true;
@ -212,16 +332,18 @@ void Camera::lookAt(const Vec2 &target) {
* @brief * @brief
* @param adapter * @param adapter
*/ */
void Camera::setViewportAdapter(ViewportAdapter* adapter) { void Camera::setViewportAdapter(ViewportAdapter *adapter) {
viewportAdapter_ = adapter; viewportAdapter_ = adapter;
} }
/** /**
* @brief * @brief
*
*
*/ */
void Camera::applyViewportAdapter() { void Camera::applyViewportAdapter() {
if (viewportAdapter_) { if (viewportAdapter_) {
const auto& config = viewportAdapter_->getConfig(); const auto &config = viewportAdapter_->getConfig();
setViewport(0.0f, config.logicWidth, config.logicHeight, 0.0f); setViewport(0.0f, config.logicWidth, config.logicHeight, 0.0f);
} }
} }

View File

@ -2,19 +2,41 @@
namespace extra2d { namespace extra2d {
GPUContext& GPUContext::getInstance() { /**
* @brief GPUContext单例实例
* @return GPUContext单例的引用
*
* 使线
*/
GPUContext& GPUContext::get() {
static GPUContext instance; static GPUContext instance;
return instance; return instance;
} }
/**
* @brief GPU上下文为有效状态
*
* 使true使release内存序
*/
void GPUContext::markValid() { void GPUContext::markValid() {
valid_.store(true, std::memory_order_release); valid_.store(true, std::memory_order_release);
} }
/**
* @brief GPU上下文为无效状态
*
* 使false使release内存序
*/
void GPUContext::markInvalid() { void GPUContext::markInvalid() {
valid_.store(false, std::memory_order_release); valid_.store(false, std::memory_order_release);
} }
/**
* @brief GPU上下文是否有效
* @return GPU上下文有效返回truefalse
*
* 使使acquire内存序
*/
bool GPUContext::isValid() const { bool GPUContext::isValid() const {
return valid_.load(std::memory_order_acquire); return valid_.load(std::memory_order_acquire);
} }

View File

@ -13,6 +13,12 @@ namespace extra2d {
// ============================================================================ // ============================================================================
// 构造函数 - 初始化字体图集 // 构造函数 - 初始化字体图集
// ============================================================================ // ============================================================================
/**
* @brief
* @param filepath
* @param fontSize
* @param useSDF 使
*/
GLFontAtlas::GLFontAtlas(const std::string &filepath, int fontSize, bool useSDF) GLFontAtlas::GLFontAtlas(const std::string &filepath, int fontSize, bool useSDF)
: fontSize_(fontSize), useSDF_(useSDF), currentY_(0), scale_(0.0f), : fontSize_(fontSize), useSDF_(useSDF), currentY_(0), scale_(0.0f),
ascent_(0.0f), descent_(0.0f), lineGap_(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; GLFontAtlas::~GLFontAtlas() = default;
// ============================================================================ // ============================================================================
// 获取字形 - 如果字形不存在则缓存它 // 获取字形 - 如果字形不存在则缓存它
// ============================================================================ // ============================================================================
/**
* @brief
* @param codepoint Unicode码点
* @return nullptr
*/
const Glyph *GLFontAtlas::getGlyph(char32_t codepoint) const { const Glyph *GLFontAtlas::getGlyph(char32_t codepoint) const {
auto it = glyphs_.find(codepoint); auto it = glyphs_.find(codepoint);
if (it == glyphs_.end()) { 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) { Vec2 GLFontAtlas::measureText(const std::string &text) {
float width = 0.0f; float width = 0.0f;
float height = getAscent() - getDescent(); float height = getAscent() - getDescent();
@ -97,6 +116,9 @@ Vec2 GLFontAtlas::measureText(const std::string &text) {
// ============================================================================ // ============================================================================
// 创建图集纹理 - 初始化空白纹理和矩形打包上下文 // 创建图集纹理 - 初始化空白纹理和矩形打包上下文
// ============================================================================ // ============================================================================
/**
* @brief
*/
void GLFontAtlas::createAtlas() { void GLFontAtlas::createAtlas() {
// 统一使用 4 通道格式 // 统一使用 4 通道格式
int channels = 4; int channels = 4;
@ -121,6 +143,10 @@ void GLFontAtlas::createAtlas() {
// 缓存字形 - 渲染字形到图集并存储信息 // 缓存字形 - 渲染字形到图集并存储信息
// 使用 stb_rect_pack 进行矩形打包 // 使用 stb_rect_pack 进行矩形打包
// ============================================================================ // ============================================================================
/**
* @brief
* @param codepoint Unicode码点
*/
void GLFontAtlas::cacheGlyph(char32_t codepoint) const { void GLFontAtlas::cacheGlyph(char32_t codepoint) const {
int advance = 0; int advance = 0;
stbtt_GetCodepointHMetrics(&fontInfo_, static_cast<int>(codepoint), &advance, stbtt_GetCodepointHMetrics(&fontInfo_, static_cast<int>(codepoint), &advance,

View File

@ -59,6 +59,9 @@ static constexpr BlendState BLEND_STATES[] = {
static constexpr size_t BLEND_STATE_COUNT = static constexpr size_t BLEND_STATE_COUNT =
sizeof(BLEND_STATES) / sizeof(BLEND_STATES[0]); sizeof(BLEND_STATES) / sizeof(BLEND_STATES[0]);
/**
* @brief OpenGL渲染器成员变量
*/
GLRenderer::GLRenderer() GLRenderer::GLRenderer()
: window_(nullptr), shapeVao_(0), shapeVbo_(0), lineVao_(0), lineVbo_(0), : window_(nullptr), shapeVao_(0), shapeVbo_(0), lineVao_(0), lineVbo_(0),
vsync_(true), shapeVertexCount_(0), currentShapeMode_(GL_TRIANGLES), vsync_(true), shapeVertexCount_(0), currentShapeMode_(GL_TRIANGLES),
@ -72,8 +75,16 @@ GLRenderer::GLRenderer()
} }
} }
/**
* @brief shutdown释放资源
*/
GLRenderer::~GLRenderer() { shutdown(); } GLRenderer::~GLRenderer() { shutdown(); }
/**
* @brief OpenGL渲染器
* @param window
* @return truefalse
*/
bool GLRenderer::init(Window *window) { bool GLRenderer::init(Window *window) {
window_ = window; window_ = window;
@ -93,7 +104,7 @@ bool GLRenderer::init(Window *window) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// 标记 GPU 上下文为有效 // 标记 GPU 上下文为有效
GPUContext::getInstance().markValid(); GPUContext::get().markValid();
E2D_LOG_INFO("OpenGL Renderer initialized"); E2D_LOG_INFO("OpenGL Renderer initialized");
E2D_LOG_INFO("OpenGL Version: {}", E2D_LOG_INFO("OpenGL Version: {}",
@ -102,16 +113,19 @@ bool GLRenderer::init(Window *window) {
return true; return true;
} }
/**
* @brief GPU资源
*/
void GLRenderer::shutdown() { void GLRenderer::shutdown() {
// 标记 GPU 上下文为无效 // 标记 GPU 上下文为无效
// 这会在销毁 OpenGL 上下文之前通知所有 GPU 资源 // 这会在销毁 OpenGL 上下文之前通知所有 GPU 资源
GPUContext::getInstance().markInvalid(); GPUContext::get().markInvalid();
spriteBatch_.shutdown(); spriteBatch_.shutdown();
if (lineVbo_ != 0) { if (lineVbo_ != 0) {
glDeleteBuffers(1, &lineVbo_); glDeleteBuffers(1, &lineVbo_);
VRAMManager::getInstance().freeBuffer(MAX_LINE_VERTICES * VRAMMgr::get().freeBuffer(MAX_LINE_VERTICES *
sizeof(ShapeVertex)); sizeof(ShapeVertex));
lineVbo_ = 0; lineVbo_ = 0;
} }
@ -121,7 +135,7 @@ void GLRenderer::shutdown() {
} }
if (shapeVbo_ != 0) { if (shapeVbo_ != 0) {
glDeleteBuffers(1, &shapeVbo_); glDeleteBuffers(1, &shapeVbo_);
VRAMManager::getInstance().freeBuffer(MAX_SHAPE_VERTICES * VRAMMgr::get().freeBuffer(MAX_SHAPE_VERTICES *
sizeof(ShapeVertex)); sizeof(ShapeVertex));
shapeVbo_ = 0; shapeVbo_ = 0;
} }
@ -131,12 +145,19 @@ void GLRenderer::shutdown() {
} }
} }
/**
* @brief
* @param clearColor
*/
void GLRenderer::beginFrame(const Color &clearColor) { void GLRenderer::beginFrame(const Color &clearColor) {
glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
resetStats(); resetStats();
} }
/**
* @brief
*/
void GLRenderer::endFrame() { void GLRenderer::endFrame() {
// 刷新所有待处理的形状批次 // 刷新所有待处理的形状批次
flushShapeBatch(); flushShapeBatch();
@ -144,16 +165,31 @@ void GLRenderer::endFrame() {
flushLineBatch(); flushLineBatch();
} }
/**
* @brief
* @param x X坐标
* @param y Y坐标
* @param width
* @param height
*/
void GLRenderer::setViewport(int x, int y, int width, int height) { void GLRenderer::setViewport(int x, int y, int width, int height) {
glViewport(x, y, width, height); glViewport(x, y, width, height);
} }
/**
* @brief
* @param enabled true启用垂直同步false禁用
*/
void GLRenderer::setVSync(bool enabled) { void GLRenderer::setVSync(bool enabled) {
vsync_ = enabled; vsync_ = enabled;
// 使用 SDL2 设置交换间隔 // 使用 SDL2 设置交换间隔
SDL_GL_SetSwapInterval(enabled ? 1 : 0); SDL_GL_SetSwapInterval(enabled ? 1 : 0);
} }
/**
* @brief
* @param mode
*/
void GLRenderer::setBlendMode(BlendMode mode) { void GLRenderer::setBlendMode(BlendMode mode) {
// 状态缓存检查,避免冗余 GL 调用 // 状态缓存检查,避免冗余 GL 调用
if (cachedBlendMode_ == mode) { if (cachedBlendMode_ == mode) {
@ -182,10 +218,18 @@ void GLRenderer::setBlendMode(BlendMode mode) {
} }
} }
/**
* @brief
* @param matrix 4x4视图投影矩阵
*/
void GLRenderer::setViewProjection(const glm::mat4 &matrix) { void GLRenderer::setViewProjection(const glm::mat4 &matrix) {
viewProjection_ = matrix; viewProjection_ = matrix;
} }
/**
* @brief
* @param transform
*/
void GLRenderer::pushTransform(const glm::mat4 &transform) { void GLRenderer::pushTransform(const glm::mat4 &transform) {
if (transformStack_.empty()) { if (transformStack_.empty()) {
transformStack_.push_back(transform); transformStack_.push_back(transform);
@ -194,12 +238,19 @@ void GLRenderer::pushTransform(const glm::mat4 &transform) {
} }
} }
/**
* @brief
*/
void GLRenderer::popTransform() { void GLRenderer::popTransform() {
if (!transformStack_.empty()) { if (!transformStack_.empty()) {
transformStack_.pop_back(); transformStack_.pop_back();
} }
} }
/**
* @brief
* @return
*/
glm::mat4 GLRenderer::getCurrentTransform() const { glm::mat4 GLRenderer::getCurrentTransform() const {
if (transformStack_.empty()) { if (transformStack_.empty()) {
return glm::mat4(1.0f); return glm::mat4(1.0f);
@ -207,17 +258,42 @@ glm::mat4 GLRenderer::getCurrentTransform() const {
return transformStack_.back(); return transformStack_.back();
} }
/**
* @brief
* @param width
* @param height
* @param pixels
* @param channels
* @return
*/
Ptr<Texture> GLRenderer::createTexture(int width, int height, Ptr<Texture> GLRenderer::createTexture(int width, int height,
const uint8_t *pixels, int channels) { const uint8_t *pixels, int channels) {
return makePtr<GLTexture>(width, height, pixels, channels); return makePtr<GLTexture>(width, height, pixels, channels);
} }
/**
* @brief
* @param filepath
* @return
*/
Ptr<Texture> GLRenderer::loadTexture(const std::string &filepath) { Ptr<Texture> GLRenderer::loadTexture(const std::string &filepath) {
return makePtr<GLTexture>(filepath); return makePtr<GLTexture>(filepath);
} }
/**
* @brief
*/
void GLRenderer::beginSpriteBatch() { spriteBatch_.begin(viewProjection_); } 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, void GLRenderer::drawSprite(const Texture &texture, const Rect &destRect,
const Rect &srcRect, const Color &tint, const Rect &srcRect, const Color &tint,
float rotation, const Vec2 &anchor) { float rotation, const Vec2 &anchor) {
@ -246,6 +322,12 @@ void GLRenderer::drawSprite(const Texture &texture, const Rect &destRect,
spriteBatch_.draw(texture, data); spriteBatch_.draw(texture, data);
} }
/**
* @brief
* @param texture
* @param position
* @param tint
*/
void GLRenderer::drawSprite(const Texture &texture, const Vec2 &position, void GLRenderer::drawSprite(const Texture &texture, const Vec2 &position,
const Color &tint) { const Color &tint) {
Rect destRect(position.x, position.y, static_cast<float>(texture.getWidth()), Rect destRect(position.x, position.y, static_cast<float>(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)); drawSprite(texture, destRect, srcRect, tint, 0.0f, Vec2(0, 0));
} }
/**
* @brief
*/
void GLRenderer::endSpriteBatch() { void GLRenderer::endSpriteBatch() {
spriteBatch_.end(); spriteBatch_.end();
stats_.drawCalls += spriteBatch_.getDrawCallCount(); stats_.drawCalls += spriteBatch_.getDrawCallCount();
} }
/**
* @brief 线
* @param start
* @param end
* @param color 线
* @param width 线
*/
void GLRenderer::drawLine(const Vec2 &start, const Vec2 &end, void GLRenderer::drawLine(const Vec2 &start, const Vec2 &end,
const Color &color, float width) { const Color &color, float width) {
// 如果线宽改变,需要先刷新线条批次 // 如果线宽改变,需要先刷新线条批次
@ -300,6 +392,11 @@ void GLRenderer::drawRect(const Rect &rect, const Color &color, float width) {
addLineVertex(x1, y1, color); addLineVertex(x1, y1, color);
} }
/**
* @brief
* @param rect
* @param color
*/
void GLRenderer::fillRect(const Rect &rect, const Color &color) { void GLRenderer::fillRect(const Rect &rect, const Color &color) {
// 提交当前批次(如果模式不同) // 提交当前批次(如果模式不同)
submitShapeBatch(GL_TRIANGLES); submitShapeBatch(GL_TRIANGLES);
@ -321,6 +418,14 @@ void GLRenderer::fillRect(const Rect &rect, const Color &color) {
addShapeVertex(x1, y2, color); addShapeVertex(x1, y2, color);
} }
/**
* @brief
* @param center
* @param radius
* @param color
* @param segments
* @param width 线
*/
void GLRenderer::drawCircle(const Vec2 &center, float radius, void GLRenderer::drawCircle(const Vec2 &center, float radius,
const Color &color, int segments, float width) { const Color &color, int segments, float width) {
// 限制段数不超过缓存大小 // 限制段数不超过缓存大小
@ -348,6 +453,13 @@ void GLRenderer::drawCircle(const Vec2 &center, float radius,
} }
} }
/**
* @brief
* @param center
* @param radius
* @param color
* @param segments
*/
void GLRenderer::fillCircle(const Vec2 &center, float radius, void GLRenderer::fillCircle(const Vec2 &center, float radius,
const Color &color, int segments) { const Color &color, int segments) {
// 限制段数不超过缓存大小 // 限制段数不超过缓存大小
@ -375,6 +487,14 @@ void GLRenderer::fillCircle(const Vec2 &center, 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, void GLRenderer::drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
const Color &color, float width) { const Color &color, float width) {
drawLine(p1, p2, color, 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); 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, void GLRenderer::fillTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
const Color &color) { const Color &color) {
submitShapeBatch(GL_TRIANGLES); 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); addShapeVertex(p3.x, p3.y, color);
} }
/**
* @brief
* @param points
* @param color
* @param width 线
*/
void GLRenderer::drawPolygon(const std::vector<Vec2> &points, void GLRenderer::drawPolygon(const std::vector<Vec2> &points,
const Color &color, float width) { const Color &color, float width) {
if (points.size() < 2) if (points.size() < 2)
@ -411,6 +544,11 @@ void GLRenderer::drawPolygon(const std::vector<Vec2> &points,
} }
} }
/**
* @brief
* @param points
* @param color
*/
void GLRenderer::fillPolygon(const std::vector<Vec2> &points, void GLRenderer::fillPolygon(const std::vector<Vec2> &points,
const Color &color) { const Color &color) {
if (points.size() < 3) if (points.size() < 3)
@ -427,16 +565,38 @@ void GLRenderer::fillPolygon(const std::vector<Vec2> &points,
} }
} }
/**
* @brief
* @param filepath
* @param fontSize
* @param useSDF 使SDF渲染
* @return
*/
Ptr<FontAtlas> GLRenderer::createFontAtlas(const std::string &filepath, Ptr<FontAtlas> GLRenderer::createFontAtlas(const std::string &filepath,
int fontSize, bool useSDF) { int fontSize, bool useSDF) {
return makePtr<GLFontAtlas>(filepath, fontSize, useSDF); return makePtr<GLFontAtlas>(filepath, fontSize, useSDF);
} }
/**
* @brief 使Vec2位置
* @param font
* @param text
* @param position
* @param color
*/
void GLRenderer::drawText(const FontAtlas &font, const std::string &text, void GLRenderer::drawText(const FontAtlas &font, const std::string &text,
const Vec2 &position, const Color &color) { const Vec2 &position, const Color &color) {
drawText(font, text, position.x, position.y, 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, void GLRenderer::drawText(const FontAtlas &font, const std::string &text,
float x, float y, const Color &color) { float x, float y, const Color &color) {
float cursorX = x; float cursorX = x;
@ -488,8 +648,14 @@ void GLRenderer::drawText(const FontAtlas &font, const std::string &text,
} }
} }
/**
* @brief
*/
void GLRenderer::resetStats() { stats_ = Stats{}; } void GLRenderer::resetStats() { stats_ = Stats{}; }
/**
* @brief OpenGL资源VAOVBO
*/
void GLRenderer::initShapeRendering() { void GLRenderer::initShapeRendering() {
// 编译形状着色器 // 编译形状着色器
shapeShader_.compileFromSource(SHAPE_VERTEX_SHADER, SHAPE_FRAGMENT_SHADER); shapeShader_.compileFromSource(SHAPE_VERTEX_SHADER, SHAPE_FRAGMENT_SHADER);
@ -537,12 +703,18 @@ void GLRenderer::initShapeRendering() {
glBindVertexArray(0); glBindVertexArray(0);
// VRAM 跟踪 // VRAM 跟踪
VRAMManager::getInstance().allocBuffer(MAX_SHAPE_VERTICES * VRAMMgr::get().allocBuffer(MAX_SHAPE_VERTICES *
sizeof(ShapeVertex)); sizeof(ShapeVertex));
VRAMManager::getInstance().allocBuffer(MAX_LINE_VERTICES * VRAMMgr::get().allocBuffer(MAX_LINE_VERTICES *
sizeof(ShapeVertex)); sizeof(ShapeVertex));
} }
/**
* @brief
* @param x X坐标
* @param y Y坐标
* @param color
*/
void GLRenderer::addShapeVertex(float x, float y, const Color &color) { void GLRenderer::addShapeVertex(float x, float y, const Color &color) {
if (shapeVertexCount_ >= MAX_SHAPE_VERTICES) { if (shapeVertexCount_ >= MAX_SHAPE_VERTICES) {
flushShapeBatch(); flushShapeBatch();
@ -556,6 +728,12 @@ void GLRenderer::addShapeVertex(float x, float y, const Color &color) {
v.a = color.a; v.a = color.a;
} }
/**
* @brief 线
* @param x X坐标
* @param y Y坐标
* @param color
*/
void GLRenderer::addLineVertex(float x, float y, const Color &color) { void GLRenderer::addLineVertex(float x, float y, const Color &color) {
if (lineVertexCount_ >= MAX_LINE_VERTICES) { if (lineVertexCount_ >= MAX_LINE_VERTICES) {
flushLineBatch(); flushLineBatch();
@ -569,6 +747,10 @@ void GLRenderer::addLineVertex(float x, float y, const Color &color) {
v.a = color.a; v.a = color.a;
} }
/**
* @brief
* @param mode OpenGL绘制模式
*/
void GLRenderer::submitShapeBatch(GLenum mode) { void GLRenderer::submitShapeBatch(GLenum mode) {
if (shapeVertexCount_ == 0) if (shapeVertexCount_ == 0)
return; return;
@ -580,6 +762,9 @@ void GLRenderer::submitShapeBatch(GLenum mode) {
currentShapeMode_ = mode; currentShapeMode_ = mode;
} }
/**
* @brief OpenGL绘制调用
*/
void GLRenderer::flushShapeBatch() { void GLRenderer::flushShapeBatch() {
if (shapeVertexCount_ == 0) if (shapeVertexCount_ == 0)
return; return;
@ -600,6 +785,9 @@ void GLRenderer::flushShapeBatch() {
shapeVertexCount_ = 0; shapeVertexCount_ = 0;
} }
/**
* @brief 线OpenGL绘制调用
*/
void GLRenderer::flushLineBatch() { void GLRenderer::flushLineBatch() {
if (lineVertexCount_ == 0) if (lineVertexCount_ == 0)
return; return;

View File

@ -5,14 +5,26 @@
namespace extra2d { namespace extra2d {
/**
* @brief ID为0
*/
GLShader::GLShader() : programID_(0) {} GLShader::GLShader() : programID_(0) {}
/**
* @brief OpenGL着色器程序
*/
GLShader::~GLShader() { GLShader::~GLShader() {
if (programID_ != 0) { if (programID_ != 0) {
glDeleteProgram(programID_); glDeleteProgram(programID_);
} }
} }
/**
* @brief
* @param vertexSource
* @param fragmentSource
* @return truefalse
*/
bool GLShader::compileFromSource(const char *vertexSource, bool GLShader::compileFromSource(const char *vertexSource,
const char *fragmentSource) { const char *fragmentSource) {
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexSource); GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexSource);
@ -46,6 +58,12 @@ bool GLShader::compileFromSource(const char *vertexSource,
return success == GL_TRUE; return success == GL_TRUE;
} }
/**
* @brief
* @param vertexPath
* @param fragmentPath
* @return truefalse
*/
bool GLShader::compileFromFile(const std::string &vertexPath, bool GLShader::compileFromFile(const std::string &vertexPath,
const std::string &fragmentPath) { const std::string &fragmentPath) {
std::ifstream vShaderFile(vertexPath); std::ifstream vShaderFile(vertexPath);
@ -65,38 +83,85 @@ bool GLShader::compileFromFile(const std::string &vertexPath,
fShaderStream.str().c_str()); fShaderStream.str().c_str());
} }
/**
* @brief 使
*/
void GLShader::bind() const { glUseProgram(programID_); } void GLShader::bind() const { glUseProgram(programID_); }
/**
* @brief
*/
void GLShader::unbind() const { glUseProgram(0); } void GLShader::unbind() const { glUseProgram(0); }
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void GLShader::setBool(const std::string &name, bool value) { void GLShader::setBool(const std::string &name, bool value) {
glUniform1i(getUniformLocation(name), value ? 1 : 0); glUniform1i(getUniformLocation(name), value ? 1 : 0);
} }
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void GLShader::setInt(const std::string &name, int value) { void GLShader::setInt(const std::string &name, int value) {
glUniform1i(getUniformLocation(name), value); glUniform1i(getUniformLocation(name), value);
} }
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void GLShader::setFloat(const std::string &name, float value) { void GLShader::setFloat(const std::string &name, float value) {
glUniform1f(getUniformLocation(name), value); glUniform1f(getUniformLocation(name), value);
} }
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void GLShader::setVec2(const std::string &name, const glm::vec2 &value) { void GLShader::setVec2(const std::string &name, const glm::vec2 &value) {
glUniform2fv(getUniformLocation(name), 1, &value[0]); glUniform2fv(getUniformLocation(name), 1, &value[0]);
} }
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void GLShader::setVec3(const std::string &name, const glm::vec3 &value) { void GLShader::setVec3(const std::string &name, const glm::vec3 &value) {
glUniform3fv(getUniformLocation(name), 1, &value[0]); glUniform3fv(getUniformLocation(name), 1, &value[0]);
} }
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void GLShader::setVec4(const std::string &name, const glm::vec4 &value) { void GLShader::setVec4(const std::string &name, const glm::vec4 &value) {
glUniform4fv(getUniformLocation(name), 1, &value[0]); 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) { void GLShader::setMat4(const std::string &name, const glm::mat4 &value) {
glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, &value[0][0]); glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, &value[0][0]);
} }
/**
* @brief
* @param type GL_VERTEX_SHADER或GL_FRAGMENT_SHADER
* @param source
* @return ID0
*/
GLuint GLShader::compileShader(GLenum type, const char *source) { GLuint GLShader::compileShader(GLenum type, const char *source) {
GLuint shader = glCreateShader(type); GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, nullptr); glShaderSource(shader, 1, &source, nullptr);
@ -115,6 +180,11 @@ GLuint GLShader::compileShader(GLenum type, const char *source) {
return shader; return shader;
} }
/**
* @brief uniform变量位置使
* @param name uniform变量名
* @return uniform位置
*/
GLint GLShader::getUniformLocation(const std::string &name) { GLint GLShader::getUniformLocation(const std::string &name) {
auto it = uniformCache_.find(name); auto it = uniformCache_.find(name);
if (it != uniformCache_.end()) { if (it != uniformCache_.end()) {

View File

@ -8,16 +8,29 @@ namespace extra2d {
// ============================================================================ // ============================================================================
// 三角函数查表 - 避免每帧重复计算 sin/cos // 三角函数查表 - 避免每帧重复计算 sin/cos
// ============================================================================ // ============================================================================
/**
* @brief sin/cos
*/
class TrigLookup { class TrigLookup {
public: public:
static constexpr size_t TABLE_SIZE = 360 * 4; // 0.25度精度 static constexpr size_t TABLE_SIZE = 360 * 4; // 0.25度精度
static constexpr float INDEX_SCALE = 4.0f; // 每度4个采样点 static constexpr float INDEX_SCALE = 4.0f; // 每度4个采样点
static constexpr float RAD_TO_INDEX = INDEX_SCALE * 180.0f / 3.14159265359f; static constexpr float RAD_TO_INDEX = INDEX_SCALE * 180.0f / 3.14159265359f;
/**
* @brief sin值
* @param radians
* @return sin值
*/
static float sinRad(float radians) { static float sinRad(float radians) {
return table_.sinTable[normalizeIndexRad(radians)]; return table_.sinTable[normalizeIndexRad(radians)];
} }
/**
* @brief cos值
* @param radians
* @return cos值
*/
static float cosRad(float radians) { static float cosRad(float radians) {
return table_.cosTable[normalizeIndexRad(radians)]; return table_.cosTable[normalizeIndexRad(radians)];
} }
@ -50,6 +63,10 @@ private:
const TrigLookup::Tables TrigLookup::table_; const TrigLookup::Tables TrigLookup::table_;
// 静态索引生成函数 // 静态索引生成函数
/**
* @brief
* @return
*/
static const std::array<GLuint, GLSpriteBatch::MAX_INDICES>& getIndices() { static const std::array<GLuint, GLSpriteBatch::MAX_INDICES>& getIndices() {
static std::array<GLuint, GLSpriteBatch::MAX_INDICES> indices = []() { static std::array<GLuint, GLSpriteBatch::MAX_INDICES> indices = []() {
std::array<GLuint, GLSpriteBatch::MAX_INDICES> arr{}; std::array<GLuint, GLSpriteBatch::MAX_INDICES> arr{};
@ -114,13 +131,23 @@ void main() {
} }
)"; )";
/**
* @brief
*/
GLSpriteBatch::GLSpriteBatch() GLSpriteBatch::GLSpriteBatch()
: vao_(0), vbo_(0), ibo_(0), vertexCount_(0), currentTexture_(nullptr), : vao_(0), vbo_(0), ibo_(0), vertexCount_(0), currentTexture_(nullptr),
currentIsSDF_(false), drawCallCount_(0), spriteCount_(0), batchCount_(0) { currentIsSDF_(false), drawCallCount_(0), spriteCount_(0), batchCount_(0) {
} }
/**
* @brief shutdown释放资源
*/
GLSpriteBatch::~GLSpriteBatch() { shutdown(); } GLSpriteBatch::~GLSpriteBatch() { shutdown(); }
/**
* @brief VAOVBOIBO和编译着色器
* @return truefalse
*/
bool GLSpriteBatch::init() { bool GLSpriteBatch::init() {
// 创建并编译着色器 // 创建并编译着色器
if (!shader_.compileFromSource(SPRITE_VERTEX_SHADER, if (!shader_.compileFromSource(SPRITE_VERTEX_SHADER,
@ -167,6 +194,9 @@ bool GLSpriteBatch::init() {
return true; return true;
} }
/**
* @brief OpenGL资源
*/
void GLSpriteBatch::shutdown() { void GLSpriteBatch::shutdown() {
if (vao_ != 0) { if (vao_ != 0) {
glDeleteVertexArrays(1, &vao_); glDeleteVertexArrays(1, &vao_);
@ -182,6 +212,10 @@ void GLSpriteBatch::shutdown() {
} }
} }
/**
* @brief
* @param viewProjection
*/
void GLSpriteBatch::begin(const glm::mat4 &viewProjection) { void GLSpriteBatch::begin(const glm::mat4 &viewProjection) {
viewProjection_ = viewProjection; viewProjection_ = viewProjection;
vertexCount_ = 0; vertexCount_ = 0;
@ -192,6 +226,12 @@ void GLSpriteBatch::begin(const glm::mat4 &viewProjection) {
batchCount_ = 0; batchCount_ = 0;
} }
/**
* @brief
* @param texture
* @param isSDF SDF渲染
* @return truefalse
*/
bool GLSpriteBatch::needsFlush(const Texture &texture, bool isSDF) const { bool GLSpriteBatch::needsFlush(const Texture &texture, bool isSDF) const {
if (currentTexture_ == nullptr) { if (currentTexture_ == nullptr) {
return false; return false;
@ -202,6 +242,10 @@ bool GLSpriteBatch::needsFlush(const Texture &texture, bool isSDF) const {
(vertexCount_ + VERTICES_PER_SPRITE > MAX_VERTICES); (vertexCount_ + VERTICES_PER_SPRITE > MAX_VERTICES);
} }
/**
* @brief
* @param data
*/
void GLSpriteBatch::addVertices(const SpriteData &data) { void GLSpriteBatch::addVertices(const SpriteData &data) {
// 计算锚点偏移 // 计算锚点偏移
float anchorOffsetX = data.size.x * data.anchor.x; 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) { void GLSpriteBatch::draw(const Texture &texture, const SpriteData &data) {
// 如果需要刷新,先提交当前批次 // 如果需要刷新,先提交当前批次
if (needsFlush(texture, data.isSDF)) { if (needsFlush(texture, data.isSDF)) {
@ -267,6 +316,11 @@ void GLSpriteBatch::draw(const Texture &texture, const SpriteData &data) {
spriteCount_++; spriteCount_++;
} }
/**
* @brief
* @param texture
* @param sprites
*/
void GLSpriteBatch::drawBatch(const Texture &texture, void GLSpriteBatch::drawBatch(const Texture &texture,
const std::vector<SpriteData> &sprites) { const std::vector<SpriteData> &sprites) {
if (sprites.empty()) { if (sprites.empty()) {
@ -303,6 +357,11 @@ void GLSpriteBatch::drawBatch(const Texture &texture,
batchCount_++; batchCount_++;
} }
/**
* @brief
* @param texture
* @param data
*/
void GLSpriteBatch::drawImmediate(const Texture &texture, void GLSpriteBatch::drawImmediate(const Texture &texture,
const SpriteData &data) { const SpriteData &data) {
// 立即绘制,不缓存 - 用于需要立即显示的情况 // 立即绘制,不缓存 - 用于需要立即显示的情况
@ -316,12 +375,18 @@ void GLSpriteBatch::drawImmediate(const Texture &texture,
flush(); // 立即提交 flush(); // 立即提交
} }
/**
* @brief
*/
void GLSpriteBatch::end() { void GLSpriteBatch::end() {
if (vertexCount_ > 0) { if (vertexCount_ > 0) {
flush(); flush();
} }
} }
/**
* @brief OpenGL绘制调用
*/
void GLSpriteBatch::flush() { void GLSpriteBatch::flush() {
if (vertexCount_ == 0 || currentTexture_ == nullptr) { if (vertexCount_ == 0 || currentTexture_ == nullptr) {
return; return;

View File

@ -80,6 +80,14 @@ struct DDSHeaderDXT10 {
static constexpr uint32_t DDS_MAGIC = 0x20534444; // "DDS " static constexpr uint32_t DDS_MAGIC = 0x20534444; // "DDS "
static constexpr uint32_t DDPF_FOURCC = 0x04; 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) { static uint32_t makeFourCC(char a, char b, char c, char d) {
return static_cast<uint32_t>(a) | (static_cast<uint32_t>(b) << 8) | return static_cast<uint32_t>(a) | (static_cast<uint32_t>(b) << 8) |
(static_cast<uint32_t>(c) << 16) | (static_cast<uint32_t>(d) << 24); (static_cast<uint32_t>(c) << 16) | (static_cast<uint32_t>(d) << 24);
@ -89,6 +97,13 @@ static uint32_t makeFourCC(char a, char b, char c, char d) {
// GLTexture 实现 // 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) GLTexture::GLTexture(int width, int height, const uint8_t *pixels, int channels)
: textureID_(0), width_(width), height_(height), channels_(channels), : textureID_(0), width_(width), height_(height), channels_(channels),
format_(PixelFormat::RGBA8), dataSize_(0) { format_(PixelFormat::RGBA8), dataSize_(0) {
@ -100,6 +115,10 @@ GLTexture::GLTexture(int width, int height, const uint8_t *pixels, int channels)
createTexture(pixels); createTexture(pixels);
} }
/**
* @brief
* @param filepath KTX/DDS
*/
GLTexture::GLTexture(const std::string &filepath) GLTexture::GLTexture(const std::string &filepath)
: textureID_(0), width_(0), height_(0), channels_(0), : textureID_(0), width_(0), height_(0), channels_(0),
format_(PixelFormat::RGBA8), dataSize_(0) { format_(PixelFormat::RGBA8), dataSize_(0) {
@ -133,12 +152,12 @@ GLTexture::~GLTexture() {
if (textureID_ != 0) { if (textureID_ != 0) {
// 检查 GPU 上下文是否仍然有效 // 检查 GPU 上下文是否仍然有效
// 如果 OpenGL 上下文已销毁,则跳过 glDeleteTextures 调用 // 如果 OpenGL 上下文已销毁,则跳过 glDeleteTextures 调用
if (GPUContext::getInstance().isValid()) { if (GPUContext::get().isValid()) {
glDeleteTextures(1, &textureID_); glDeleteTextures(1, &textureID_);
} }
// VRAM 跟踪: 释放纹理显存(无论上下文是否有效都需要更新统计) // VRAM 跟踪: 释放纹理显存(无论上下文是否有效都需要更新统计)
if (dataSize_ > 0) { 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_); glBindTexture(GL_TEXTURE_2D, textureID_);
} }
/**
* @brief
*/
void GLTexture::unbind() const { glBindTexture(GL_TEXTURE_2D, 0); } void GLTexture::unbind() const { glBindTexture(GL_TEXTURE_2D, 0); }
/**
* @brief OpenGL纹理对象并上传像素数据
* @param pixels
*/
void GLTexture::createTexture(const uint8_t *pixels) { void GLTexture::createTexture(const uint8_t *pixels) {
GLenum format = GL_RGBA; GLenum format = GL_RGBA;
GLenum internalFormat = GL_RGBA8; GLenum internalFormat = GL_RGBA8;
@ -208,7 +234,7 @@ void GLTexture::createTexture(const uint8_t *pixels) {
// VRAM 跟踪 // VRAM 跟踪
dataSize_ = static_cast<size_t>(width_ * height_ * channels_); dataSize_ = static_cast<size_t>(width_ * height_ * channels_);
VRAMManager::getInstance().allocTexture(dataSize_); VRAMMgr::get().allocTexture(dataSize_);
} }
// ============================================================================ // ============================================================================
@ -227,6 +253,11 @@ bool GLTexture::loadCompressed(const std::string &filepath) {
return false; return false;
} }
/**
* @brief KTX格式压缩纹理
* @param filepath KTX文件路径
* @return truefalse
*/
bool GLTexture::loadKTX(const std::string &filepath) { bool GLTexture::loadKTX(const std::string &filepath) {
std::ifstream file(filepath, std::ios::binary); std::ifstream file(filepath, std::ios::binary);
if (!file.is_open()) { if (!file.is_open()) {
@ -316,13 +347,18 @@ bool GLTexture::loadKTX(const std::string &filepath) {
// VRAM 跟踪 // VRAM 跟踪
dataSize_ = imageSize; dataSize_ = imageSize;
VRAMManager::getInstance().allocTexture(dataSize_); VRAMMgr::get().allocTexture(dataSize_);
E2D_LOG_INFO("Loaded compressed KTX texture: {} ({}x{}, format={:#06x})", E2D_LOG_INFO("Loaded compressed KTX texture: {} ({}x{}, format={:#06x})",
filepath, width_, height_, glInternalFormat); filepath, width_, height_, glInternalFormat);
return true; return true;
} }
/**
* @brief DDS格式压缩纹理
* @param filepath DDS文件路径
* @return truefalse
*/
bool GLTexture::loadDDS(const std::string &filepath) { bool GLTexture::loadDDS(const std::string &filepath) {
std::ifstream file(filepath, std::ios::binary); std::ifstream file(filepath, std::ios::binary);
if (!file.is_open()) { if (!file.is_open()) {
@ -415,7 +451,7 @@ bool GLTexture::loadDDS(const std::string &filepath) {
// VRAM 跟踪 // VRAM 跟踪
dataSize_ = imageSize; dataSize_ = imageSize;
VRAMManager::getInstance().allocTexture(dataSize_); VRAMMgr::get().allocTexture(dataSize_);
E2D_LOG_INFO("Loaded compressed DDS texture: {} ({}x{})", filepath, width_, E2D_LOG_INFO("Loaded compressed DDS texture: {} ({}x{})", filepath, width_,
height_); height_);
@ -436,6 +472,13 @@ void GLTexture::generateAlphaMask() {
PixelFormat GLTexture::getFormat() const { return format_; } PixelFormat GLTexture::getFormat() const { return format_; }
/**
* @brief
* @param width
* @param height
* @param format
* @return
*/
Ptr<Texture> GLTexture::create(int width, int height, PixelFormat format) { Ptr<Texture> GLTexture::create(int width, int height, PixelFormat format) {
int channels = 4; int channels = 4;
switch (format) { switch (format) {

View File

@ -3,6 +3,15 @@
namespace extra2d { namespace extra2d {
/**
* @brief
*
*
* OpenGL后端
*
* @param type OpenGL
* @return nullptr
*/
UniquePtr<RenderBackend> RenderBackend::create(BackendType type) { UniquePtr<RenderBackend> RenderBackend::create(BackendType type) {
switch (type) { switch (type) {
case BackendType::OpenGL: case BackendType::OpenGL:

View File

@ -7,6 +7,21 @@ namespace extra2d {
// RenderCommand 便捷构造函数 // 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, RenderCommand RenderCommand::makeSprite(const Texture* tex, const Rect& dest,
const Rect& src, const Color& tint, const Rect& src, const Color& tint,
float rot, const Vec2& anc, float rot, const Vec2& anc,
@ -31,6 +46,18 @@ RenderCommand RenderCommand::makeSprite(const Texture* tex, const Rect& dest,
return cmd; 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, RenderCommand RenderCommand::makeLine(const Vec2& s, const Vec2& e, const Color& c,
float w, uint32_t lyr) { float w, uint32_t lyr) {
RenderCommand cmd; RenderCommand cmd;
@ -48,6 +75,18 @@ RenderCommand RenderCommand::makeLine(const Vec2& s, const Vec2& e, const Color&
return cmd; 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, RenderCommand RenderCommand::makeRect(const Rect& r, const Color& c,
float w, bool fill, uint32_t lyr) { float w, bool fill, uint32_t lyr) {
RenderCommand cmd; RenderCommand cmd;
@ -69,12 +108,29 @@ RenderCommand RenderCommand::makeRect(const Rect& r, const Color& c,
// RenderCommandBuffer 实现 // RenderCommandBuffer 实现
// ============================================================================ // ============================================================================
/**
* @brief
*
*
*/
RenderCommandBuffer::RenderCommandBuffer() : nextOrder_(0) { RenderCommandBuffer::RenderCommandBuffer() : nextOrder_(0) {
commands_.reserve(INITIAL_CAPACITY); commands_.reserve(INITIAL_CAPACITY);
} }
/**
* @brief
*
*
*/
RenderCommandBuffer::~RenderCommandBuffer() = default; RenderCommandBuffer::~RenderCommandBuffer() = default;
/**
* @brief
*
*
*
* @param cmd
*/
void RenderCommandBuffer::addCommand(const RenderCommand& cmd) { void RenderCommandBuffer::addCommand(const RenderCommand& cmd) {
if (commands_.size() >= MAX_CAPACITY) { if (commands_.size() >= MAX_CAPACITY) {
// 缓冲区已满,可能需要立即刷新 // 缓冲区已满,可能需要立即刷新
@ -86,6 +142,13 @@ void RenderCommandBuffer::addCommand(const RenderCommand& cmd) {
commands_.push_back(std::move(copy)); commands_.push_back(std::move(copy));
} }
/**
* @brief
*
*
*
* @param cmd
*/
void RenderCommandBuffer::addCommand(RenderCommand&& cmd) { void RenderCommandBuffer::addCommand(RenderCommand&& cmd) {
if (commands_.size() >= MAX_CAPACITY) { if (commands_.size() >= MAX_CAPACITY) {
return; return;
@ -95,6 +158,13 @@ void RenderCommandBuffer::addCommand(RenderCommand&& cmd) {
commands_.push_back(std::move(cmd)); commands_.push_back(std::move(cmd));
} }
/**
* @brief
*
*
*
* @return
*/
RenderCommand& RenderCommandBuffer::emplaceCommand() { RenderCommand& RenderCommandBuffer::emplaceCommand() {
if (commands_.size() >= MAX_CAPACITY) { if (commands_.size() >= MAX_CAPACITY) {
// 如果已满,返回一个虚拟命令(不应该发生) // 如果已满,返回一个虚拟命令(不应该发生)
@ -107,6 +177,12 @@ RenderCommand& RenderCommandBuffer::emplaceCommand() {
return commands_.back(); return commands_.back();
} }
/**
* @brief
*
* /
*
*/
void RenderCommandBuffer::sortCommands() { void RenderCommandBuffer::sortCommands() {
// 按以下优先级排序: // 按以下优先级排序:
// 1. 层级 (layer) - 低层级先渲染 // 1. 层级 (layer) - 低层级先渲染
@ -117,17 +193,38 @@ void RenderCommandBuffer::sortCommands() {
std::sort(commands_.begin(), commands_.end(), compareCommands); std::sort(commands_.begin(), commands_.end(), compareCommands);
} }
/**
* @brief
*
*
*/
void RenderCommandBuffer::clear() { void RenderCommandBuffer::clear() {
commands_.clear(); commands_.clear();
nextOrder_ = 0; nextOrder_ = 0;
} }
/**
* @brief
*
*
*
* @param capacity
*/
void RenderCommandBuffer::reserve(size_t capacity) { void RenderCommandBuffer::reserve(size_t capacity) {
if (capacity <= MAX_CAPACITY) { if (capacity <= MAX_CAPACITY) {
commands_.reserve(capacity); commands_.reserve(capacity);
} }
} }
/**
* @brief
*
*
*
* @param a
* @param b
* @return a应排在b前面返回truefalse
*/
bool RenderCommandBuffer::compareCommands(const RenderCommand& a, const RenderCommand& b) { bool RenderCommandBuffer::compareCommands(const RenderCommand& a, const RenderCommand& b) {
// 首先按层级排序 // 首先按层级排序
if (a.layer != b.layer) { if (a.layer != b.layer) {

View File

@ -12,10 +12,26 @@ namespace extra2d {
// RenderTarget实现 // RenderTarget实现
// ============================================================================ // ============================================================================
/**
* @brief
*
*
*/
RenderTarget::RenderTarget() = default; RenderTarget::RenderTarget() = default;
/**
* @brief
*
*
*/
RenderTarget::~RenderTarget() { destroy(); } RenderTarget::~RenderTarget() { destroy(); }
/**
* @brief
* @param other
*
*
*/
RenderTarget::RenderTarget(RenderTarget &&other) noexcept RenderTarget::RenderTarget(RenderTarget &&other) noexcept
: fbo_(other.fbo_), rbo_(other.rbo_), : fbo_(other.fbo_), rbo_(other.rbo_),
colorTexture_(std::move(other.colorTexture_)), colorTexture_(std::move(other.colorTexture_)),
@ -29,6 +45,13 @@ RenderTarget::RenderTarget(RenderTarget &&other) noexcept
other.height_ = 0; other.height_ = 0;
} }
/**
* @brief
* @param other
* @return
*
*
*/
RenderTarget &RenderTarget::operator=(RenderTarget &&other) noexcept { RenderTarget &RenderTarget::operator=(RenderTarget &&other) noexcept {
if (this != &other) { if (this != &other) {
destroy(); destroy();
@ -52,6 +75,13 @@ RenderTarget &RenderTarget::operator=(RenderTarget &&other) noexcept {
return *this; return *this;
} }
/**
* @brief
* @param config
* @return truefalse
*
*
*/
bool RenderTarget::create(const RenderTargetConfig &config) { bool RenderTarget::create(const RenderTargetConfig &config) {
destroy(); destroy();
@ -73,6 +103,14 @@ bool RenderTarget::create(const RenderTargetConfig &config) {
return true; return true;
} }
/**
* @brief
* @param texture
* @param hasDepth
* @return truefalse
*
* 使
*/
bool RenderTarget::createFromTexture(Ptr<Texture> texture, bool hasDepth) { bool RenderTarget::createFromTexture(Ptr<Texture> texture, bool hasDepth) {
if (!texture || !texture->isValid()) { if (!texture || !texture->isValid()) {
E2D_ERROR("无效的颜色纹理"); E2D_ERROR("无效的颜色纹理");
@ -125,6 +163,11 @@ bool RenderTarget::createFromTexture(Ptr<Texture> texture, bool hasDepth) {
return true; return true;
} }
/**
* @brief
*
*
*/
void RenderTarget::destroy() { void RenderTarget::destroy() {
deleteFBO(); deleteFBO();
@ -135,6 +178,11 @@ void RenderTarget::destroy() {
height_ = 0; height_ = 0;
} }
/**
* @brief
*
*
*/
void RenderTarget::bind() { void RenderTarget::bind() {
if (!isValid()) { if (!isValid()) {
return; return;
@ -144,8 +192,19 @@ void RenderTarget::bind() {
glViewport(0, 0, width_, height_); glViewport(0, 0, width_, height_);
} }
/**
* @brief
*
*
*/
void RenderTarget::unbind() { bindDefault(); } void RenderTarget::unbind() { bindDefault(); }
/**
* @brief
* @param color
*
* 使/
*/
void RenderTarget::clear(const Color &color) { void RenderTarget::clear(const Color &color) {
if (!isValid()) { if (!isValid()) {
return; return;
@ -167,6 +226,15 @@ void RenderTarget::clear(const Color &color) {
glClear(mask); glClear(mask);
} }
/**
* @brief
* @param x X坐标
* @param y Y坐标
* @param width
* @param height
*
*
*/
void RenderTarget::setViewport(int x, int y, int width, int height) { void RenderTarget::setViewport(int x, int y, int width, int height) {
if (!isValid()) { if (!isValid()) {
return; return;
@ -176,6 +244,15 @@ void RenderTarget::setViewport(int x, int y, int width, int height) {
glViewport(x, y, width, 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, void RenderTarget::getFullViewport(int &x, int &y, int &width,
int &height) const { int &height) const {
x = 0; x = 0;
@ -184,6 +261,14 @@ void RenderTarget::getFullViewport(int &x, int &y, int &width,
height = height_; height = height_;
} }
/**
* @brief
* @param width
* @param height
* @return truefalse
*
*
*/
bool RenderTarget::resize(int width, int height) { bool RenderTarget::resize(int width, int height) {
if (!isValid()) { if (!isValid()) {
return false; return false;
@ -200,6 +285,12 @@ bool RenderTarget::resize(int width, int height) {
return create(config); return create(config);
} }
/**
* @brief
* @param target
*
* 使glBlitFramebuffer将内容复制到目标渲染目标
*/
void RenderTarget::copyTo(RenderTarget &target) { void RenderTarget::copyTo(RenderTarget &target) {
if (!isValid() || !target.isValid()) { if (!isValid() || !target.isValid()) {
return; return;
@ -220,6 +311,14 @@ void RenderTarget::copyTo(RenderTarget &target) {
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
} }
/**
* @brief
* @param target
* @param color
* @param depth
*
* 使glBlitFramebuffer进行选择性复制
*/
void RenderTarget::blitTo(RenderTarget &target, bool color, bool depth) { void RenderTarget::blitTo(RenderTarget &target, bool color, bool depth) {
if (!isValid() || !target.isValid()) { if (!isValid() || !target.isValid()) {
return; return;
@ -245,6 +344,13 @@ void RenderTarget::blitTo(RenderTarget &target, bool color, bool depth) {
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
} }
/**
* @brief
* @param screenWidth
* @param screenHeight
*
*
*/
void RenderTarget::copyToScreen(int screenWidth, int screenHeight) { void RenderTarget::copyToScreen(int screenWidth, int screenHeight) {
if (!isValid()) { if (!isValid()) {
return; return;
@ -259,6 +365,13 @@ void RenderTarget::copyToScreen(int screenWidth, int screenHeight) {
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
} }
/**
* @brief
* @param filepath
* @return truefalse
*
* PNG图片文件
*/
bool RenderTarget::saveToFile(const std::string &filepath) { bool RenderTarget::saveToFile(const std::string &filepath) {
if (!isValid() || !colorTexture_) { if (!isValid() || !colorTexture_) {
return false; return false;
@ -296,6 +409,13 @@ bool RenderTarget::saveToFile(const std::string &filepath) {
return true; return true;
} }
/**
* @brief
* @param config
* @return nullptr
*
*
*/
Ptr<RenderTarget> Ptr<RenderTarget>
RenderTarget::createFromConfig(const RenderTargetConfig &config) { RenderTarget::createFromConfig(const RenderTargetConfig &config) {
auto rt = std::make_shared<RenderTarget>(); auto rt = std::make_shared<RenderTarget>();
@ -305,18 +425,35 @@ RenderTarget::createFromConfig(const RenderTargetConfig &config) {
return nullptr; return nullptr;
} }
/**
* @brief ID
* @return FBO ID
*
* OpenGL当前绑定的帧缓冲对象
*/
GLuint RenderTarget::getCurrentFBO() { GLuint RenderTarget::getCurrentFBO() {
GLint fbo = 0; GLint fbo = 0;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo); glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
return static_cast<GLuint>(fbo); return static_cast<GLuint>(fbo);
} }
/**
* @brief
*
*
*/
void RenderTarget::bindDefault() { glBindFramebuffer(GL_FRAMEBUFFER, 0); } void RenderTarget::bindDefault() { glBindFramebuffer(GL_FRAMEBUFFER, 0); }
// ============================================================================ // ============================================================================
// 内部方法 // 内部方法
// ============================================================================ // ============================================================================
/**
* @brief
* @return truefalse
*
* FBO及相关附件
*/
bool RenderTarget::createFBO() { bool RenderTarget::createFBO() {
// 创建颜色纹理 // 创建颜色纹理
colorTexture_ = GLTexture::create(width_, height_, colorFormat_); colorTexture_ = GLTexture::create(width_, height_, colorFormat_);
@ -370,6 +507,11 @@ bool RenderTarget::createFBO() {
return true; return true;
} }
/**
* @brief
*
* FBO和渲染缓冲对象
*/
void RenderTarget::deleteFBO() { void RenderTarget::deleteFBO() {
if (rbo_ != 0) { if (rbo_ != 0) {
glDeleteRenderbuffers(1, &rbo_); glDeleteRenderbuffers(1, &rbo_);
@ -386,6 +528,15 @@ void RenderTarget::deleteFBO() {
// MultisampleRenderTarget实现 // MultisampleRenderTarget实现
// ============================================================================ // ============================================================================
/**
* @brief
* @param width
* @param height
* @param samples
* @return truefalse
*
* 齿
*/
bool MultisampleRenderTarget::create(int width, int height, int samples) { bool MultisampleRenderTarget::create(int width, int height, int samples) {
// 先销毁现有的 // 先销毁现有的
destroy(); destroy();
@ -433,6 +584,11 @@ bool MultisampleRenderTarget::create(int width, int height, int samples) {
return true; return true;
} }
/**
* @brief
*
*
*/
void MultisampleRenderTarget::destroy() { void MultisampleRenderTarget::destroy() {
// 删除颜色渲染缓冲 // 删除颜色渲染缓冲
if (colorRBO_ != 0) { if (colorRBO_ != 0) {
@ -444,6 +600,12 @@ void MultisampleRenderTarget::destroy() {
RenderTarget::destroy(); RenderTarget::destroy();
} }
/**
* @brief
* @param target
*
*
*/
void MultisampleRenderTarget::resolveTo(RenderTarget &target) { void MultisampleRenderTarget::resolveTo(RenderTarget &target) {
if (!isValid() || !target.isValid()) { if (!isValid() || !target.isValid()) {
return; return;
@ -463,11 +625,23 @@ void MultisampleRenderTarget::resolveTo(RenderTarget &target) {
// RenderTargetStack实现 // RenderTargetStack实现
// ============================================================================ // ============================================================================
RenderTargetStack &RenderTargetStack::getInstance() { /**
* @brief RenderTargetStack单例实例
* @return RenderTargetStack单例的引用
*
* 使线
*/
RenderTargetStack &RenderTargetStack::get() {
static RenderTargetStack instance; static RenderTargetStack instance;
return instance; return instance;
} }
/**
* @brief
* @param target
*
*
*/
void RenderTargetStack::push(RenderTarget *target) { void RenderTargetStack::push(RenderTarget *target) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
@ -477,6 +651,11 @@ void RenderTargetStack::push(RenderTarget *target) {
} }
} }
/**
* @brief
*
*
*/
void RenderTargetStack::pop() { void RenderTargetStack::pop() {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
@ -492,6 +671,10 @@ void RenderTargetStack::pop() {
} }
} }
/**
* @brief
* @return nullptr
*/
RenderTarget *RenderTargetStack::getCurrent() const { RenderTarget *RenderTargetStack::getCurrent() const {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
@ -501,11 +684,20 @@ RenderTarget *RenderTargetStack::getCurrent() const {
return stack_.back(); return stack_.back();
} }
/**
* @brief
* @return
*/
size_t RenderTargetStack::size() const { size_t RenderTargetStack::size() const {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
return stack_.size(); return stack_.size();
} }
/**
* @brief
*
*
*/
void RenderTargetStack::clear() { void RenderTargetStack::clear() {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
stack_.clear(); 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; return instance;
} }
bool RenderTargetManager::init(int width, int height) { /**
* @brief
* @param width
* @param height
* @return truefalse
*
*
*/
bool RenderTargetMgr::init(int width, int height) {
if (initialized_) { if (initialized_) {
return true; return true;
} }
@ -544,7 +750,12 @@ bool RenderTargetManager::init(int width, int height) {
return true; return true;
} }
void RenderTargetManager::shutdown() { /**
* @brief
*
*
*/
void RenderTargetMgr::shutdown() {
if (!initialized_) { if (!initialized_) {
return; return;
} }
@ -556,8 +767,15 @@ void RenderTargetManager::shutdown() {
E2D_INFO("渲染目标管理器已关闭"); E2D_INFO("渲染目标管理器已关闭");
} }
/**
* @brief
* @param config
* @return nullptr
*
*
*/
Ptr<RenderTarget> Ptr<RenderTarget>
RenderTargetManager::createRenderTarget(const RenderTargetConfig &config) { RenderTargetMgr::createRenderTarget(const RenderTargetConfig &config) {
if (!initialized_) { if (!initialized_) {
E2D_ERROR("渲染目标管理器未初始化"); E2D_ERROR("渲染目标管理器未初始化");
return nullptr; return nullptr;
@ -570,7 +788,14 @@ RenderTargetManager::createRenderTarget(const RenderTargetConfig &config) {
return rt; return rt;
} }
void RenderTargetManager::resize(int width, int height) { /**
* @brief
* @param width
* @param height
*
*
*/
void RenderTargetMgr::resize(int width, int height) {
if (!initialized_) { if (!initialized_) {
return; return;
} }

View File

@ -7,6 +7,14 @@ namespace extra2d {
// ShaderPreset实现 // ShaderPreset实现
// ============================================================================ // ============================================================================
/**
* @brief
*
* GLShader对象
*
* @param params waveSpeedwaveAmplitude和waveFrequency
* @return nullptr
*/
Ptr<GLShader> ShaderPreset::Water(const WaterParams &params) { Ptr<GLShader> ShaderPreset::Water(const WaterParams &params) {
auto shader = std::make_shared<GLShader>(); auto shader = std::make_shared<GLShader>();
@ -25,6 +33,14 @@ Ptr<GLShader> ShaderPreset::Water(const WaterParams &params) {
return shader; return shader;
} }
/**
* @brief
*
* GLShader对象
*
* @param params color和thickness
* @return nullptr
*/
Ptr<GLShader> ShaderPreset::Outline(const OutlineParams &params) { Ptr<GLShader> ShaderPreset::Outline(const OutlineParams &params) {
auto shader = std::make_shared<GLShader>(); auto shader = std::make_shared<GLShader>();
@ -43,6 +59,14 @@ Ptr<GLShader> ShaderPreset::Outline(const OutlineParams &params) {
return shader; return shader;
} }
/**
* @brief
*
* GLShader对象
*
* @param params distortionAmount和timeScale
* @return nullptr
*/
Ptr<GLShader> ShaderPreset::Distortion(const DistortionParams &params) { Ptr<GLShader> ShaderPreset::Distortion(const DistortionParams &params) {
auto shader = std::make_shared<GLShader>(); auto shader = std::make_shared<GLShader>();
@ -60,6 +84,14 @@ Ptr<GLShader> ShaderPreset::Distortion(const DistortionParams &params) {
return shader; return shader;
} }
/**
* @brief
*
* GLShader对象
*
* @param params pixelSize
* @return nullptr
*/
Ptr<GLShader> ShaderPreset::Pixelate(const PixelateParams &params) { Ptr<GLShader> ShaderPreset::Pixelate(const PixelateParams &params) {
auto shader = std::make_shared<GLShader>(); auto shader = std::make_shared<GLShader>();
@ -76,6 +108,14 @@ Ptr<GLShader> ShaderPreset::Pixelate(const PixelateParams &params) {
return shader; return shader;
} }
/**
* @brief
*
* GLShader对象
*
* @param params strength
* @return nullptr
*/
Ptr<GLShader> ShaderPreset::Invert(const InvertParams &params) { Ptr<GLShader> ShaderPreset::Invert(const InvertParams &params) {
auto shader = std::make_shared<GLShader>(); auto shader = std::make_shared<GLShader>();
@ -92,6 +132,14 @@ Ptr<GLShader> ShaderPreset::Invert(const InvertParams &params) {
return shader; return shader;
} }
/**
* @brief
*
* GLShader对象
*
* @param params intensity
* @return nullptr
*/
Ptr<GLShader> ShaderPreset::Grayscale(const GrayscaleParams &params) { Ptr<GLShader> ShaderPreset::Grayscale(const GrayscaleParams &params) {
auto shader = std::make_shared<GLShader>(); auto shader = std::make_shared<GLShader>();
@ -108,6 +156,14 @@ Ptr<GLShader> ShaderPreset::Grayscale(const GrayscaleParams &params) {
return shader; return shader;
} }
/**
* @brief
*
* GLShader对象
*
* @param params radius
* @return nullptr
*/
Ptr<GLShader> ShaderPreset::Blur(const BlurParams &params) { Ptr<GLShader> ShaderPreset::Blur(const BlurParams &params) {
auto shader = std::make_shared<GLShader>(); auto shader = std::make_shared<GLShader>();
@ -124,6 +180,15 @@ Ptr<GLShader> ShaderPreset::Blur(const BlurParams &params) {
return shader; return shader;
} }
/**
* @brief +
*
* GLShader对象
*
* @param grayParams intensity
* @param outlineParams color和thickness
* @return nullptr
*/
Ptr<GLShader> Ptr<GLShader>
ShaderPreset::GrayscaleOutline(const GrayscaleParams &grayParams, ShaderPreset::GrayscaleOutline(const GrayscaleParams &grayParams,
const OutlineParams &outlineParams) { const OutlineParams &outlineParams) {
@ -183,6 +248,15 @@ void main() {
return shader; return shader;
} }
/**
* @brief +
*
* GLShader对象
*
* @param pixParams pixelSize
* @param invParams strength
* @return nullptr
*/
Ptr<GLShader> ShaderPreset::PixelateInvert(const PixelateParams &pixParams, Ptr<GLShader> ShaderPreset::PixelateInvert(const PixelateParams &pixParams,
const InvertParams &invParams) { const InvertParams &invParams) {
// 创建组合效果的片段着色器 (GLES 3.2) // 创建组合效果的片段着色器 (GLES 3.2)

View File

@ -182,11 +182,23 @@ void main() {
// ShaderSystem实现 // ShaderSystem实现
// ============================================================================ // ============================================================================
ShaderSystem &ShaderSystem::getInstance() { /**
* @brief ShaderSystem单例实例
* @return ShaderSystem单例的引用
*
* 使线
*/
ShaderSystem &ShaderSystem::get() {
static ShaderSystem instance; static ShaderSystem instance;
return instance; return instance;
} }
/**
* @brief Shader系统
* @return truefalse
*
*
*/
bool ShaderSystem::init() { bool ShaderSystem::init() {
E2D_INFO("初始化Shader系统..."); E2D_INFO("初始化Shader系统...");
@ -199,6 +211,11 @@ bool ShaderSystem::init() {
return true; return true;
} }
/**
* @brief Shader系统
*
*
*/
void ShaderSystem::shutdown() { void ShaderSystem::shutdown() {
E2D_INFO("关闭Shader系统..."); E2D_INFO("关闭Shader系统...");
clear(); clear();
@ -209,6 +226,12 @@ void ShaderSystem::shutdown() {
builtinShapeShader_.reset(); builtinShapeShader_.reset();
} }
/**
* @brief
* @return truefalse
*
*
*/
bool ShaderSystem::loadBuiltinShaders() { bool ShaderSystem::loadBuiltinShaders() {
// 加载精灵Shader // 加载精灵Shader
builtinSpriteShader_ = std::make_shared<GLShader>(); builtinSpriteShader_ = std::make_shared<GLShader>();
@ -246,6 +269,15 @@ bool ShaderSystem::loadBuiltinShaders() {
return true; return true;
} }
/**
* @brief
* @param name
* @param vertPath
* @param fragPath
* @return nullptr
*
*
*/
Ptr<GLShader> ShaderSystem::loadFromFile(const std::string &name, Ptr<GLShader> ShaderSystem::loadFromFile(const std::string &name,
const std::string &vertPath, const std::string &vertPath,
const std::string &fragPath) { const std::string &fragPath) {
@ -285,6 +317,15 @@ Ptr<GLShader> ShaderSystem::loadFromFile(const std::string &name,
return shader; return shader;
} }
/**
* @brief
* @param name
* @param vertSource
* @param fragSource
* @return nullptr
*
*
*/
Ptr<GLShader> ShaderSystem::loadFromSource(const std::string &name, Ptr<GLShader> ShaderSystem::loadFromSource(const std::string &name,
const std::string &vertSource, const std::string &vertSource,
const std::string &fragSource) { const std::string &fragSource) {
@ -306,6 +347,11 @@ Ptr<GLShader> ShaderSystem::loadFromSource(const std::string &name,
return shader; return shader;
} }
/**
* @brief
* @param name
* @return nullptr
*/
Ptr<GLShader> ShaderSystem::get(const std::string &name) { Ptr<GLShader> ShaderSystem::get(const std::string &name) {
auto it = shaders_.find(name); auto it = shaders_.find(name);
if (it != shaders_.end()) { if (it != shaders_.end()) {
@ -314,14 +360,36 @@ Ptr<GLShader> ShaderSystem::get(const std::string &name) {
return nullptr; return nullptr;
} }
/**
* @brief
* @param name
* @return truefalse
*/
bool ShaderSystem::has(const std::string &name) const { bool ShaderSystem::has(const std::string &name) const {
return shaders_.find(name) != shaders_.end(); return shaders_.find(name) != shaders_.end();
} }
/**
* @brief
* @param name
*
*
*/
void ShaderSystem::remove(const std::string &name) { shaders_.erase(name); } void ShaderSystem::remove(const std::string &name) { shaders_.erase(name); }
/**
* @brief
*
*
*/
void ShaderSystem::clear() { shaders_.clear(); } void ShaderSystem::clear() { shaders_.clear(); }
/**
* @brief
* @param enable
*
*
*/
void ShaderSystem::setFileWatching(bool enable) { void ShaderSystem::setFileWatching(bool enable) {
fileWatching_ = enable; fileWatching_ = enable;
if (enable) { if (enable) {
@ -331,6 +399,11 @@ void ShaderSystem::setFileWatching(bool enable) {
} }
} }
/**
* @brief
*
*
*/
void ShaderSystem::updateFileWatching() { void ShaderSystem::updateFileWatching() {
if (!fileWatching_) if (!fileWatching_)
return; return;
@ -342,6 +415,11 @@ void ShaderSystem::updateFileWatching() {
} }
} }
/**
* @brief
*
*
*/
void ShaderSystem::checkAndReload() { void ShaderSystem::checkAndReload() {
for (auto &[name, info] : shaders_) { for (auto &[name, info] : shaders_) {
if (info.isBuiltin) if (info.isBuiltin)
@ -359,6 +437,13 @@ void ShaderSystem::checkAndReload() {
} }
} }
/**
* @brief
* @param name
* @return truefalse
*
*
*/
bool ShaderSystem::reload(const std::string &name) { bool ShaderSystem::reload(const std::string &name) {
auto it = shaders_.find(name); auto it = shaders_.find(name);
if (it == shaders_.end()) { if (it == shaders_.end()) {
@ -387,6 +472,11 @@ bool ShaderSystem::reload(const std::string &name) {
return false; return false;
} }
/**
* @brief
*
*
*/
void ShaderSystem::reloadAll() { void ShaderSystem::reloadAll() {
for (const auto &[name, info] : shaders_) { for (const auto &[name, info] : shaders_) {
if (!info.isBuiltin) { if (!info.isBuiltin) {
@ -395,22 +485,45 @@ void ShaderSystem::reloadAll() {
} }
} }
/**
* @brief
* @return
*/
Ptr<GLShader> ShaderSystem::getBuiltinSpriteShader() { Ptr<GLShader> ShaderSystem::getBuiltinSpriteShader() {
return builtinSpriteShader_; return builtinSpriteShader_;
} }
/**
* @brief
* @return
*/
Ptr<GLShader> ShaderSystem::getBuiltinParticleShader() { Ptr<GLShader> ShaderSystem::getBuiltinParticleShader() {
return builtinParticleShader_; return builtinParticleShader_;
} }
/**
* @brief
* @return
*/
Ptr<GLShader> ShaderSystem::getBuiltinPostProcessShader() { Ptr<GLShader> ShaderSystem::getBuiltinPostProcessShader() {
return builtinPostProcessShader_; return builtinPostProcessShader_;
} }
/**
* @brief
* @return
*/
Ptr<GLShader> ShaderSystem::getBuiltinShapeShader() { Ptr<GLShader> ShaderSystem::getBuiltinShapeShader() {
return builtinShapeShader_; return builtinShapeShader_;
} }
/**
* @brief
* @param filepath
* @return
*
*
*/
std::string ShaderSystem::readFile(const std::string &filepath) { std::string ShaderSystem::readFile(const std::string &filepath) {
std::ifstream file(filepath, std::ios::in | std::ios::binary); std::ifstream file(filepath, std::ios::in | std::ios::binary);
if (!file.is_open()) { if (!file.is_open()) {
@ -422,6 +535,13 @@ std::string ShaderSystem::readFile(const std::string &filepath) {
return buffer.str(); return buffer.str();
} }
/**
* @brief
* @param filepath
* @return 0
*
*
*/
uint64_t ShaderSystem::getFileModifiedTime(const std::string &filepath) { uint64_t ShaderSystem::getFileModifiedTime(const std::string &filepath) {
#ifdef _WIN32 #ifdef _WIN32
struct _stat64 statBuf; struct _stat64 statBuf;
@ -441,47 +561,103 @@ uint64_t ShaderSystem::getFileModifiedTime(const std::string &filepath) {
// ShaderParams实现 // ShaderParams实现
// ============================================================================ // ============================================================================
/**
* @brief
* @param shader
*
*
*/
ShaderParams::ShaderParams(GLShader &shader) : shader_(shader) {} ShaderParams::ShaderParams(GLShader &shader) : shader_(shader) {}
/**
* @brief uniform变量
* @param name
* @param value
* @return
*/
ShaderParams &ShaderParams::setBool(const std::string &name, bool value) { ShaderParams &ShaderParams::setBool(const std::string &name, bool value) {
shader_.setBool(name, value); shader_.setBool(name, value);
return *this; return *this;
} }
/**
* @brief uniform变量
* @param name
* @param value
* @return
*/
ShaderParams &ShaderParams::setInt(const std::string &name, int value) { ShaderParams &ShaderParams::setInt(const std::string &name, int value) {
shader_.setInt(name, value); shader_.setInt(name, value);
return *this; return *this;
} }
/**
* @brief uniform变量
* @param name
* @param value
* @return
*/
ShaderParams &ShaderParams::setFloat(const std::string &name, float value) { ShaderParams &ShaderParams::setFloat(const std::string &name, float value) {
shader_.setFloat(name, value); shader_.setFloat(name, value);
return *this; return *this;
} }
/**
* @brief uniform变量
* @param name
* @param value
* @return
*/
ShaderParams &ShaderParams::setVec2(const std::string &name, ShaderParams &ShaderParams::setVec2(const std::string &name,
const glm::vec2 &value) { const glm::vec2 &value) {
shader_.setVec2(name, value); shader_.setVec2(name, value);
return *this; return *this;
} }
/**
* @brief uniform变量
* @param name
* @param value
* @return
*/
ShaderParams &ShaderParams::setVec3(const std::string &name, ShaderParams &ShaderParams::setVec3(const std::string &name,
const glm::vec3 &value) { const glm::vec3 &value) {
shader_.setVec3(name, value); shader_.setVec3(name, value);
return *this; return *this;
} }
/**
* @brief uniform变量
* @param name
* @param value
* @return
*/
ShaderParams &ShaderParams::setVec4(const std::string &name, ShaderParams &ShaderParams::setVec4(const std::string &name,
const glm::vec4 &value) { const glm::vec4 &value) {
shader_.setVec4(name, value); shader_.setVec4(name, value);
return *this; return *this;
} }
/**
* @brief 4x4矩阵类型uniform变量
* @param name
* @param value 4x4矩阵值
* @return
*/
ShaderParams &ShaderParams::setMat4(const std::string &name, ShaderParams &ShaderParams::setMat4(const std::string &name,
const glm::mat4 &value) { const glm::mat4 &value) {
shader_.setMat4(name, value); shader_.setMat4(name, value);
return *this; return *this;
} }
/**
* @brief uniform变量
* @param name
* @param color
* @return
*
*
*/
ShaderParams &ShaderParams::setColor(const std::string &name, ShaderParams &ShaderParams::setColor(const std::string &name,
const Color &color) { const Color &color) {
shader_.setVec4(name, glm::vec4(color.r, color.g, color.b, color.a)); shader_.setVec4(name, glm::vec4(color.r, color.g, color.b, color.a));

View File

@ -9,6 +9,13 @@ namespace extra2d {
// TextureAtlasPage 实现 // TextureAtlasPage 实现
// ============================================================================ // ============================================================================
/**
* @brief
* @param width
* @param height
*
*
*/
TextureAtlasPage::TextureAtlasPage(int width, int height) TextureAtlasPage::TextureAtlasPage(int width, int height)
: width_(width), height_(height), isFull_(false), usedArea_(0) { : 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); E2D_LOG_INFO("Created texture atlas page: {}x{}", width, height);
} }
/**
* @brief
*
*
*/
TextureAtlasPage::~TextureAtlasPage() = default; TextureAtlasPage::~TextureAtlasPage() = default;
/**
* @brief
* @param name
* @param texWidth
* @param texHeight
* @param pixels
* @param[out] outUvRect UV坐标矩形
* @return truefalse
*
* 使
*/
bool TextureAtlasPage::tryAddTexture(const std::string& name, int texWidth, int texHeight, bool TextureAtlasPage::tryAddTexture(const std::string& name, int texWidth, int texHeight,
const uint8_t* pixels, Rect& outUvRect) { const uint8_t* pixels, Rect& outUvRect) {
if (isFull_) { if (isFull_) {
@ -73,6 +96,15 @@ bool TextureAtlasPage::tryAddTexture(const std::string& name, int texWidth, int
return true; return true;
} }
/**
* @brief
* @param node
* @param width
* @param height
* @return nullptr
*
* 使
*/
TextureAtlasPage::PackNode* TextureAtlasPage::insert(PackNode* node, int width, int height) { TextureAtlasPage::PackNode* TextureAtlasPage::insert(PackNode* node, int width, int height) {
if (node == nullptr) { if (node == nullptr) {
return nullptr; return nullptr;
@ -116,6 +148,16 @@ TextureAtlasPage::PackNode* TextureAtlasPage::insert(PackNode* node, int width,
return insert(node->left.get(), width, height); 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) { void TextureAtlasPage::writePixels(int x, int y, int w, int h, const uint8_t* pixels) {
if (texture_ == nullptr || pixels == nullptr) { if (texture_ == nullptr || pixels == nullptr) {
return; 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); glBindTexture(GL_TEXTURE_2D, 0);
} }
/**
* @brief
* @param name
* @return nullptr
*/
const AtlasEntry* TextureAtlasPage::getEntry(const std::string& name) const { const AtlasEntry* TextureAtlasPage::getEntry(const std::string& name) const {
auto it = entries_.find(name); auto it = entries_.find(name);
if (it != entries_.end()) { if (it != entries_.end()) {
@ -138,6 +185,12 @@ const AtlasEntry* TextureAtlasPage::getEntry(const std::string& name) const {
return nullptr; return nullptr;
} }
/**
* @brief 使
* @return 使0.01.0
*
* 使
*/
float TextureAtlasPage::getUsageRatio() const { float TextureAtlasPage::getUsageRatio() const {
return static_cast<float>(usedArea_) / (width_ * height_); return static_cast<float>(usedArea_) / (width_ * height_);
} }
@ -146,6 +199,11 @@ float TextureAtlasPage::getUsageRatio() const {
// TextureAtlas 实现 // TextureAtlas 实现
// ============================================================================ // ============================================================================
/**
* @brief
*
* 使
*/
TextureAtlas::TextureAtlas() TextureAtlas::TextureAtlas()
: pageSize_(TextureAtlasPage::DEFAULT_SIZE), : pageSize_(TextureAtlasPage::DEFAULT_SIZE),
sizeThreshold_(256), sizeThreshold_(256),
@ -153,14 +211,35 @@ TextureAtlas::TextureAtlas()
initialized_(false) { initialized_(false) {
} }
/**
* @brief
*
*
*/
TextureAtlas::~TextureAtlas() = default; TextureAtlas::~TextureAtlas() = default;
/**
* @brief
* @param pageSize
*
*
*/
void TextureAtlas::init(int pageSize) { void TextureAtlas::init(int pageSize) {
pageSize_ = pageSize; pageSize_ = pageSize;
initialized_ = true; initialized_ = true;
E2D_LOG_INFO("TextureAtlas initialized with page size: {}", pageSize); E2D_LOG_INFO("TextureAtlas initialized with page size: {}", pageSize);
} }
/**
* @brief
* @param name
* @param width
* @param height
* @param pixels
* @return truefalse
*
*
*/
bool TextureAtlas::addTexture(const std::string& name, int width, int height, bool TextureAtlas::addTexture(const std::string& name, int width, int height,
const uint8_t* pixels) { const uint8_t* pixels) {
if (!enabled_ || !initialized_) { if (!enabled_ || !initialized_) {
@ -200,10 +279,20 @@ bool TextureAtlas::addTexture(const std::string& name, int width, int height,
return false; return false;
} }
/**
* @brief
* @param name
* @return truefalse
*/
bool TextureAtlas::contains(const std::string& name) const { bool TextureAtlas::contains(const std::string& name) const {
return entryToPage_.find(name) != entryToPage_.end(); return entryToPage_.find(name) != entryToPage_.end();
} }
/**
* @brief
* @param name
* @return nullptr
*/
const Texture* TextureAtlas::getAtlasTexture(const std::string& name) const { const Texture* TextureAtlas::getAtlasTexture(const std::string& name) const {
auto it = entryToPage_.find(name); auto it = entryToPage_.find(name);
if (it != entryToPage_.end()) { if (it != entryToPage_.end()) {
@ -212,6 +301,11 @@ const Texture* TextureAtlas::getAtlasTexture(const std::string& name) const {
return nullptr; return nullptr;
} }
/**
* @brief UV坐标矩形
* @param name
* @return UV坐标矩形
*/
Rect TextureAtlas::getUVRect(const std::string& name) const { Rect TextureAtlas::getUVRect(const std::string& name) const {
auto it = entryToPage_.find(name); auto it = entryToPage_.find(name);
if (it != entryToPage_.end()) { if (it != entryToPage_.end()) {
@ -223,6 +317,11 @@ Rect TextureAtlas::getUVRect(const std::string& name) const {
return Rect(0, 0, 1, 1); // 默认 UV return Rect(0, 0, 1, 1); // 默认 UV
} }
/**
* @brief
* @param name
* @return
*/
Vec2 TextureAtlas::getOriginalSize(const std::string& name) const { Vec2 TextureAtlas::getOriginalSize(const std::string& name) const {
auto it = entryToPage_.find(name); auto it = entryToPage_.find(name);
if (it != entryToPage_.end()) { if (it != entryToPage_.end()) {
@ -234,6 +333,12 @@ Vec2 TextureAtlas::getOriginalSize(const std::string& name) const {
return Vec2(0, 0); return Vec2(0, 0);
} }
/**
* @brief 使
* @return 使
*
* 使
*/
float TextureAtlas::getTotalUsageRatio() const { float TextureAtlas::getTotalUsageRatio() const {
if (pages_.empty()) { if (pages_.empty()) {
return 0.0f; return 0.0f;
@ -246,6 +351,11 @@ float TextureAtlas::getTotalUsageRatio() const {
return total / pages_.size(); return total / pages_.size();
} }
/**
* @brief
*
*
*/
void TextureAtlas::clear() { void TextureAtlas::clear() {
pages_.clear(); pages_.clear();
entryToPage_.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; return instance;
} }

View File

@ -13,6 +13,8 @@ namespace extra2d {
/** /**
* @brief * @brief
*
*
*/ */
TexturePool::TexturePool() TexturePool::TexturePool()
: scene_(nullptr) : scene_(nullptr)
@ -27,6 +29,8 @@ TexturePool::TexturePool()
* @brief * @brief
* @param scene * @param scene
* @param maxMemoryUsage 使0 * @param maxMemoryUsage 使0
*
*
*/ */
TexturePool::TexturePool(Scene* scene, size_t maxMemoryUsage) TexturePool::TexturePool(Scene* scene, size_t maxMemoryUsage)
: scene_(scene) : scene_(scene)
@ -42,6 +46,8 @@ TexturePool::TexturePool(Scene* scene, size_t maxMemoryUsage)
* @brief * @brief
* @param scene * @param scene
* @param maxMemoryUsage 使0 * @param maxMemoryUsage 使0
*
*
*/ */
void TexturePool::init(Scene* scene, size_t maxMemoryUsage) { void TexturePool::init(Scene* scene, size_t maxMemoryUsage) {
scene_ = scene; scene_ = scene;
@ -51,6 +57,8 @@ void TexturePool::init(Scene* scene, size_t maxMemoryUsage) {
/** /**
* @brief * @brief
*
*
*/ */
TexturePool::~TexturePool() { TexturePool::~TexturePool() {
clear(); clear();
@ -66,6 +74,8 @@ TexturePool::~TexturePool() {
* @param path * @param path
* @param options * @param options
* @return * @return
*
*
*/ */
TextureRef TexturePool::load(const std::string& path, const TextureLoadOptions& options) { TextureRef TexturePool::load(const std::string& path, const TextureLoadOptions& options) {
return load(path, Rect::Zero(), options); return load(path, Rect::Zero(), options);
@ -77,6 +87,8 @@ TextureRef TexturePool::load(const std::string& path, const TextureLoadOptions&
* @param region * @param region
* @param options * @param options
* @return * @return
*
*
*/ */
TextureRef TexturePool::load(const std::string& path, const Rect& region, TextureRef TexturePool::load(const std::string& path, const Rect& region,
const TextureLoadOptions& options) { const TextureLoadOptions& options) {
@ -157,6 +169,8 @@ TextureRef TexturePool::load(const std::string& path, const Rect& region,
* @param channels * @param channels
* @param key * @param key
* @return * @return
*
*
*/ */
TextureRef TexturePool::loadFromMemory(const uint8_t* data, int width, int height, TextureRef TexturePool::loadFromMemory(const uint8_t* data, int width, int height,
int channels, const std::string& key) { int channels, const std::string& key) {
@ -226,6 +240,8 @@ TextureRef TexturePool::loadFromMemory(const uint8_t* data, int width, int heigh
* @param path * @param path
* @param options * @param options
* @return * @return
*
*
*/ */
TextureRef TexturePool::getOrLoad(const std::string& path, const TextureLoadOptions& options) { TextureRef TexturePool::getOrLoad(const std::string& path, const TextureLoadOptions& options) {
return getOrLoad(path, Rect::Zero(), options); return getOrLoad(path, Rect::Zero(), options);
@ -237,6 +253,8 @@ TextureRef TexturePool::getOrLoad(const std::string& path, const TextureLoadOpti
* @param region * @param region
* @param options * @param options
* @return * @return
*
*
*/ */
TextureRef TexturePool::getOrLoad(const std::string& path, const Rect& region, TextureRef TexturePool::getOrLoad(const std::string& path, const Rect& region,
const TextureLoadOptions& options) { const TextureLoadOptions& options) {
@ -307,6 +325,8 @@ TextureRef TexturePool::getOrLoad(const std::string& path, const Rect& region,
* @brief * @brief
* @param key * @param key
* @return * @return
*
*
*/ */
bool TexturePool::addRef(const TextureKey& key) { bool TexturePool::addRef(const TextureKey& key) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
@ -324,6 +344,8 @@ bool TexturePool::addRef(const TextureKey& key) {
* @brief * @brief
* @param key * @param key
* @return * @return
*
*
*/ */
uint32_t TexturePool::release(const TextureKey& key) { uint32_t TexturePool::release(const TextureKey& key) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
@ -340,6 +362,8 @@ uint32_t TexturePool::release(const TextureKey& key) {
* @brief * @brief
* @param key * @param key
* @return * @return
*
*
*/ */
uint32_t TexturePool::getRefCount(const TextureKey& key) const { uint32_t TexturePool::getRefCount(const TextureKey& key) const {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
@ -359,6 +383,8 @@ uint32_t TexturePool::getRefCount(const TextureKey& key) const {
* @brief * @brief
* @param key * @param key
* @return * @return
*
*
*/ */
bool TexturePool::isCached(const TextureKey& key) const { bool TexturePool::isCached(const TextureKey& key) const {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
@ -369,6 +395,8 @@ bool TexturePool::isCached(const TextureKey& key) const {
* @brief * @brief
* @param key * @param key
* @return * @return
*
*
*/ */
bool TexturePool::removeFromCache(const TextureKey& key) { bool TexturePool::removeFromCache(const TextureKey& key) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
@ -386,6 +414,8 @@ bool TexturePool::removeFromCache(const TextureKey& key) {
/** /**
* @brief 0 * @brief 0
* @return * @return
*
* 0
*/ */
size_t TexturePool::collectGarbage() { size_t TexturePool::collectGarbage() {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
@ -410,6 +440,8 @@ size_t TexturePool::collectGarbage() {
/** /**
* @brief * @brief
*
*
*/ */
void TexturePool::clear() { void TexturePool::clear() {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
@ -427,6 +459,8 @@ void TexturePool::clear() {
/** /**
* @brief 使 * @brief 使
* @return 使 * @return 使
*
* 使
*/ */
size_t TexturePool::getMemoryUsage() const { size_t TexturePool::getMemoryUsage() const {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
@ -436,6 +470,8 @@ size_t TexturePool::getMemoryUsage() const {
/** /**
* @brief 使 * @brief 使
* @param maxMemory 使0 * @param maxMemory 使0
*
* 使
*/ */
void TexturePool::setMaxMemoryUsage(size_t maxMemory) { void TexturePool::setMaxMemoryUsage(size_t maxMemory) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
@ -453,6 +489,8 @@ void TexturePool::setMaxMemoryUsage(size_t maxMemory) {
* @brief LRU * @brief LRU
* @param targetMemory 使 * @param targetMemory 使
* @return * @return
*
* LRU算法淘汰最少使用的纹理以达到目标内存使用量
*/ */
size_t TexturePool::evictLRU(size_t targetMemory) { size_t TexturePool::evictLRU(size_t targetMemory) {
// 注意:调用者应该已持有锁 // 注意:调用者应该已持有锁
@ -506,7 +544,9 @@ size_t TexturePool::evictLRU(size_t targetMemory) {
/** /**
* @brief * @brief
* @return * @return
*
* 使
*/ */
TexturePool::Stats TexturePool::getStats() const { TexturePool::Stats TexturePool::getStats() const {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
@ -524,6 +564,8 @@ TexturePool::Stats TexturePool::getStats() const {
/** /**
* @brief * @brief
*
*
*/ */
void TexturePool::resetStats() { void TexturePool::resetStats() {
cacheHits_.store(0, std::memory_order_relaxed); cacheHits_.store(0, std::memory_order_relaxed);
@ -539,6 +581,8 @@ void TexturePool::resetStats() {
* @brief * @brief
* @param texture * @param texture
* @return * @return
*
*
*/ */
size_t TexturePool::calculateTextureMemory(const Texture* texture) { size_t TexturePool::calculateTextureMemory(const Texture* texture) {
if (!texture) { if (!texture) {
@ -587,6 +631,8 @@ size_t TexturePool::calculateTextureMemory(const Texture* texture) {
/** /**
* @brief * @brief
* @return * @return
*
* 使
*/ */
bool TexturePool::needsEviction() const { bool TexturePool::needsEviction() const {
return maxMemoryUsage_ > 0 && currentMemoryUsage_ > maxMemoryUsage_; return maxMemoryUsage_ > 0 && currentMemoryUsage_ > maxMemoryUsage_;
@ -594,6 +640,8 @@ bool TexturePool::needsEviction() const {
/** /**
* @brief * @brief
*
* 使LRU淘汰
*/ */
void TexturePool::tryAutoEvict() { void TexturePool::tryAutoEvict() {
if (needsEviction()) { if (needsEviction()) {

View File

@ -4,38 +4,88 @@
namespace extra2d { namespace extra2d {
/**
* @brief
*
*
*/
ViewportAdapter::ViewportAdapter() = default; ViewportAdapter::ViewportAdapter() = default;
/**
* @brief
* @param logicWidth
* @param logicHeight
*
*
*/
ViewportAdapter::ViewportAdapter(float logicWidth, float logicHeight) { ViewportAdapter::ViewportAdapter(float logicWidth, float logicHeight) {
config_.logicWidth = logicWidth; config_.logicWidth = logicWidth;
config_.logicHeight = logicHeight; config_.logicHeight = logicHeight;
} }
/**
* @brief
* @param config
*
*
*/
void ViewportAdapter::setConfig(const ViewportConfig &config) { void ViewportAdapter::setConfig(const ViewportConfig &config) {
config_ = config; config_ = config;
matrixDirty_ = true; matrixDirty_ = true;
} }
/**
* @brief
* @param width
* @param height
*
*
*/
void ViewportAdapter::setLogicSize(float width, float height) { void ViewportAdapter::setLogicSize(float width, float height) {
config_.logicWidth = width; config_.logicWidth = width;
config_.logicHeight = height; config_.logicHeight = height;
matrixDirty_ = true; matrixDirty_ = true;
} }
/**
* @brief
* @param mode
*
*
*/
void ViewportAdapter::setMode(ViewportMode mode) { void ViewportAdapter::setMode(ViewportMode mode) {
config_.mode = mode; config_.mode = mode;
matrixDirty_ = true; matrixDirty_ = true;
} }
/**
* @brief
* @param position
*
*
*/
void ViewportAdapter::setLetterboxPosition(LetterboxPosition position) { void ViewportAdapter::setLetterboxPosition(LetterboxPosition position) {
config_.letterboxPosition = position; config_.letterboxPosition = position;
matrixDirty_ = true; matrixDirty_ = true;
} }
/**
* @brief
* @param color
*
*
*/
void ViewportAdapter::setLetterboxColor(const Color &color) { void ViewportAdapter::setLetterboxColor(const Color &color) {
config_.letterboxColor = color; config_.letterboxColor = color;
} }
/**
* @brief
* @param screenWidth
* @param screenHeight
*
*
*/
void ViewportAdapter::update(int screenWidth, int screenHeight) { void ViewportAdapter::update(int screenWidth, int screenHeight) {
if (screenWidth_ == screenWidth && screenHeight_ == screenHeight && if (screenWidth_ == screenWidth && screenHeight_ == screenHeight &&
!matrixDirty_) { !matrixDirty_) {
@ -68,6 +118,11 @@ void ViewportAdapter::update(int screenWidth, int screenHeight) {
} }
} }
/**
* @brief
*
*
*/
void ViewportAdapter::calculateAspectRatio() { void ViewportAdapter::calculateAspectRatio() {
if (config_.logicHeight <= 0.0f || screenHeight_ <= 0) { if (config_.logicHeight <= 0.0f || screenHeight_ <= 0) {
result_ = ViewportResult(); result_ = ViewportResult();
@ -104,6 +159,11 @@ void ViewportAdapter::calculateAspectRatio() {
calculateLetterbox(); calculateLetterbox();
} }
/**
* @brief
*
*
*/
void ViewportAdapter::calculateStretch() { void ViewportAdapter::calculateStretch() {
result_.scaleX = static_cast<float>(screenWidth_) / config_.logicWidth; result_.scaleX = static_cast<float>(screenWidth_) / config_.logicWidth;
result_.scaleY = static_cast<float>(screenHeight_) / config_.logicHeight; result_.scaleY = static_cast<float>(screenHeight_) / config_.logicHeight;
@ -117,6 +177,11 @@ void ViewportAdapter::calculateStretch() {
result_.hasLetterbox = false; result_.hasLetterbox = false;
} }
/**
* @brief
*
*
*/
void ViewportAdapter::calculateCenter() { void ViewportAdapter::calculateCenter() {
float displayWidth = config_.logicWidth; float displayWidth = config_.logicWidth;
float displayHeight = config_.logicHeight; float displayHeight = config_.logicHeight;
@ -155,6 +220,11 @@ void ViewportAdapter::calculateCenter() {
calculateLetterbox(); calculateLetterbox();
} }
/**
* @brief
*
* 使
*/
void ViewportAdapter::calculateCustom() { void ViewportAdapter::calculateCustom() {
result_.scaleX = config_.customScale; result_.scaleX = config_.customScale;
result_.scaleY = config_.customScale; result_.scaleY = config_.customScale;
@ -176,6 +246,11 @@ void ViewportAdapter::calculateCustom() {
calculateLetterbox(); calculateLetterbox();
} }
/**
* @brief
*
*
*/
void ViewportAdapter::calculateLetterbox() { void ViewportAdapter::calculateLetterbox() {
result_.hasLetterbox = false; result_.hasLetterbox = false;
@ -201,6 +276,13 @@ void ViewportAdapter::calculateLetterbox() {
} }
} }
/**
* @brief
* @param extraWidth
* @param extraHeight
*
*
*/
void ViewportAdapter::applyLetterboxPosition(float extraWidth, void ViewportAdapter::applyLetterboxPosition(float extraWidth,
float extraHeight) { float extraHeight) {
if (extraWidth <= 0.0f && extraHeight <= 0.0f) { if (extraWidth <= 0.0f && extraHeight <= 0.0f) {
@ -251,25 +333,57 @@ void ViewportAdapter::applyLetterboxPosition(float extraWidth,
result_.viewport.origin = result_.offset; result_.viewport.origin = result_.offset;
} }
/**
* @brief
* @param screenPos
* @return
*
*
*/
Vec2 ViewportAdapter::screenToLogic(const Vec2 &screenPos) const { Vec2 ViewportAdapter::screenToLogic(const Vec2 &screenPos) const {
return Vec2((screenPos.x - result_.offset.x) / result_.scaleX, return Vec2((screenPos.x - result_.offset.x) / result_.scaleX,
(screenPos.y - result_.offset.y) / result_.scaleY); (screenPos.y - result_.offset.y) / result_.scaleY);
} }
/**
* @brief
* @param logicPos
* @return
*
*
*/
Vec2 ViewportAdapter::logicToScreen(const Vec2 &logicPos) const { Vec2 ViewportAdapter::logicToScreen(const Vec2 &logicPos) const {
return Vec2(logicPos.x * result_.scaleX + result_.offset.x, return Vec2(logicPos.x * result_.scaleX + result_.offset.x,
logicPos.y * result_.scaleY + result_.offset.y); logicPos.y * result_.scaleY + result_.offset.y);
} }
/**
* @brief
* @param x X坐标
* @param y Y坐标
* @return
*/
Vec2 ViewportAdapter::screenToLogic(float x, float y) const { Vec2 ViewportAdapter::screenToLogic(float x, float y) const {
return screenToLogic(Vec2(x, y)); return screenToLogic(Vec2(x, y));
} }
/**
* @brief
* @param x X坐标
* @param y Y坐标
* @return
*/
Vec2 ViewportAdapter::logicToScreen(float x, float y) const { Vec2 ViewportAdapter::logicToScreen(float x, float y) const {
return logicToScreen(Vec2(x, y)); return logicToScreen(Vec2(x, y));
} }
glm::mat4 ViewportAdapter::getViewportMatrix() const { /**
* @brief
* @return 4x4变换矩阵
*
*
*/
glm::mat4 ViewportAdapter::getMatrix() const {
if (matrixDirty_) { if (matrixDirty_) {
viewportMatrix_ = glm::mat4(1.0f); viewportMatrix_ = glm::mat4(1.0f);
viewportMatrix_ = glm::translate(viewportMatrix_, viewportMatrix_ = glm::translate(viewportMatrix_,
@ -281,18 +395,34 @@ glm::mat4 ViewportAdapter::getViewportMatrix() const {
return viewportMatrix_; return viewportMatrix_;
} }
glm::mat4 ViewportAdapter::getInverseViewportMatrix() const { /**
* @brief
* @return 4x4逆变换矩阵
*
*
*/
glm::mat4 ViewportAdapter::getInvMatrix() const {
if (matrixDirty_) { if (matrixDirty_) {
getViewportMatrix(); getMatrix();
} }
inverseViewportMatrix_ = glm::inverse(viewportMatrix_); inverseViewportMatrix_ = glm::inverse(viewportMatrix_);
return inverseViewportMatrix_; return inverseViewportMatrix_;
} }
/**
* @brief
* @param screenPos
* @return truefalse
*/
bool ViewportAdapter::isInViewport(const Vec2 &screenPos) const { bool ViewportAdapter::isInViewport(const Vec2 &screenPos) const {
return result_.viewport.containsPoint(screenPos); return result_.viewport.containsPoint(screenPos);
} }
/**
* @brief
* @param screenPos
* @return truefalse
*/
bool ViewportAdapter::isInLetterbox(const Vec2 &screenPos) const { bool ViewportAdapter::isInLetterbox(const Vec2 &screenPos) const {
if (!result_.hasLetterbox) { if (!result_.hasLetterbox) {
return false; return false;

View File

@ -7,17 +7,34 @@ namespace extra2d {
// Switch 推荐 VRAM 预算 ~400MB // Switch 推荐 VRAM 预算 ~400MB
static constexpr size_t DEFAULT_VRAM_BUDGET = 400 * 1024 * 1024; 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), : textureVRAM_(0), bufferVRAM_(0), vramBudget_(DEFAULT_VRAM_BUDGET),
textureAllocCount_(0), textureFreeCount_(0), bufferAllocCount_(0), textureAllocCount_(0), textureFreeCount_(0), bufferAllocCount_(0),
bufferFreeCount_(0), peakTextureVRAM_(0), peakBufferVRAM_(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; return instance;
} }
void VRAMManager::allocTexture(size_t size) { /**
* @brief VRAM
* @param size
*
* VRAM使用量并更新峰值
*/
void VRAMMgr::allocTexture(size_t size) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
textureVRAM_ += size; textureVRAM_ += size;
textureAllocCount_++; 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<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
if (size <= textureVRAM_) { if (size <= textureVRAM_) {
textureVRAM_ -= size; textureVRAM_ -= size;
@ -39,7 +62,13 @@ void VRAMManager::freeTexture(size_t size) {
textureFreeCount_++; textureFreeCount_++;
} }
void VRAMManager::allocBuffer(size_t size) { /**
* @brief VRAM
* @param size
*
* VRAM使用量并更新峰值
*/
void VRAMMgr::allocBuffer(size_t size) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
bufferVRAM_ += size; bufferVRAM_ += size;
bufferAllocCount_++; 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<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
if (size <= bufferVRAM_) { if (size <= bufferVRAM_) {
bufferVRAM_ -= size; bufferVRAM_ -= size;
@ -61,28 +96,67 @@ void VRAMManager::freeBuffer(size_t size) {
bufferFreeCount_++; 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(); size_t used = getUsedVRAM();
return (used < vramBudget_) ? (vramBudget_ - used) : 0; 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<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
vramBudget_ = budget; vramBudget_ = budget;
E2D_LOG_INFO("VRAM budget set to {} MB", budget / (1024 * 1024)); 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 truefalse
*/
bool VRAMMgr::isOverBudget() const { return getUsedVRAM() > vramBudget_; }
void VRAMManager::printStats() const { /**
* @brief VRAM统计信息
*
* VRAM使用情况/
*/
void VRAMMgr::printStats() const {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
E2D_LOG_INFO("=== VRAM Stats ==="); E2D_LOG_INFO("=== VRAM Stats ===");
E2D_LOG_INFO(" Texture VRAM: {} MB (peak: {} MB)", E2D_LOG_INFO(" Texture VRAM: {} MB (peak: {} MB)",
@ -98,7 +172,12 @@ void VRAMManager::printStats() const {
bufferFreeCount_); bufferFreeCount_);
} }
void VRAMManager::reset() { /**
* @brief
*
* VRAM计数器和峰值记录
*/
void VRAMMgr::reset() {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
textureVRAM_ = 0; textureVRAM_ = 0;
bufferVRAM_ = 0; bufferVRAM_ = 0;

View File

@ -5,6 +5,12 @@
namespace extra2d { namespace extra2d {
/**
* @brief
*
*
* false
*/
Input::Input() Input::Input()
: controller_(nullptr), : controller_(nullptr),
leftStickX_(0.0f), leftStickY_(0.0f), leftStickX_(0.0f), leftStickY_(0.0f),
@ -13,7 +19,6 @@ Input::Input()
touching_(false), prevTouching_(false), touchCount_(0), touching_(false), prevTouching_(false), touchCount_(0),
viewportAdapter_(nullptr) { viewportAdapter_(nullptr) {
// 初始化所有状态数组
keysDown_.fill(false); keysDown_.fill(false);
prevKeysDown_.fill(false); prevKeysDown_.fill(false);
buttonsDown_.fill(false); buttonsDown_.fill(false);
@ -22,10 +27,19 @@ Input::Input()
prevMouseButtonsDown_.fill(false); prevMouseButtonsDown_.fill(false);
} }
/**
* @brief
*
* shutdown()
*/
Input::~Input() { shutdown(); } Input::~Input() { shutdown(); }
/**
* @brief
*
* PC端获取初始鼠标位置
*/
void Input::init() { void Input::init() {
// 打开第一个可用的游戏控制器
for (int i = 0; i < SDL_NumJoysticks(); ++i) { for (int i = 0; i < SDL_NumJoysticks(); ++i) {
if (SDL_IsGameController(i)) { if (SDL_IsGameController(i)) {
controller_ = SDL_GameControllerOpen(i); controller_ = SDL_GameControllerOpen(i);
@ -41,7 +55,6 @@ void Input::init() {
E2D_LOG_WARN("No game controller found"); E2D_LOG_WARN("No game controller found");
} }
// PC 端获取初始鼠标状态
#ifndef PLATFORM_SWITCH #ifndef PLATFORM_SWITCH
int mouseX, mouseY; int mouseX, mouseY;
SDL_GetMouseState(&mouseX, &mouseY); SDL_GetMouseState(&mouseX, &mouseY);
@ -50,6 +63,11 @@ void Input::init() {
#endif #endif
} }
/**
* @brief
*
*
*/
void Input::shutdown() { void Input::shutdown() {
if (controller_) { if (controller_) {
SDL_GameControllerClose(controller_); SDL_GameControllerClose(controller_);
@ -57,8 +75,12 @@ void Input::shutdown() {
} }
} }
/**
* @brief
*
*
*/
void Input::update() { void Input::update() {
// 保存上一帧状态
prevKeysDown_ = keysDown_; prevKeysDown_ = keysDown_;
prevButtonsDown_ = buttonsDown_; prevButtonsDown_ = buttonsDown_;
prevMouseButtonsDown_ = mouseButtonsDown_; prevMouseButtonsDown_ = mouseButtonsDown_;
@ -67,50 +89,56 @@ void Input::update() {
prevTouching_ = touching_; prevTouching_ = touching_;
prevTouchPosition_ = touchPosition_; prevTouchPosition_ = touchPosition_;
// 更新各输入设备状态
updateKeyboard(); updateKeyboard();
updateMouse(); updateMouse();
updateGamepad(); updateGamepad();
updateTouch(); updateTouch();
} }
/**
* @brief
*
* SDL获取当前键盘状态并更新按键数组
*/
void Input::updateKeyboard() { void Input::updateKeyboard() {
// 获取当前键盘状态
const Uint8* state = SDL_GetKeyboardState(nullptr); const Uint8* state = SDL_GetKeyboardState(nullptr);
for (int i = 0; i < MAX_KEYS; ++i) { for (int i = 0; i < MAX_KEYS; ++i) {
keysDown_[i] = state[i] != 0; keysDown_[i] = state[i] != 0;
} }
} }
/**
* @brief
*
* Switch平台执行
*/
void Input::updateMouse() { void Input::updateMouse() {
#ifndef PLATFORM_SWITCH #ifndef PLATFORM_SWITCH
// 更新鼠标位置
int mouseX, mouseY; int mouseX, mouseY;
Uint32 buttonState = SDL_GetMouseState(&mouseX, &mouseY); Uint32 buttonState = SDL_GetMouseState(&mouseX, &mouseY);
mousePosition_ = Vec2(static_cast<float>(mouseX), static_cast<float>(mouseY)); mousePosition_ = Vec2(static_cast<float>(mouseX), static_cast<float>(mouseY));
// 更新鼠标按钮状态
mouseButtonsDown_[0] = (buttonState & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; mouseButtonsDown_[0] = (buttonState & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0;
mouseButtonsDown_[1] = (buttonState & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0; mouseButtonsDown_[1] = (buttonState & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
mouseButtonsDown_[2] = (buttonState & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0; mouseButtonsDown_[2] = (buttonState & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
mouseButtonsDown_[3] = (buttonState & SDL_BUTTON(SDL_BUTTON_X1)) != 0; mouseButtonsDown_[3] = (buttonState & SDL_BUTTON(SDL_BUTTON_X1)) != 0;
mouseButtonsDown_[4] = (buttonState & SDL_BUTTON(SDL_BUTTON_X2)) != 0; mouseButtonsDown_[4] = (buttonState & SDL_BUTTON(SDL_BUTTON_X2)) != 0;
// 处理鼠标滚轮事件(需要在事件循环中处理,这里简化处理)
// 实际滚轮值通过 SDL_MOUSEWHEEL 事件更新
#endif #endif
} }
/**
* @brief
*
* -1.0~1.0
*/
void Input::updateGamepad() { void Input::updateGamepad() {
if (controller_) { if (controller_) {
// 更新按钮状态
for (int i = 0; i < MAX_BUTTONS; ++i) { for (int i = 0; i < MAX_BUTTONS; ++i) {
buttonsDown_[i] = buttonsDown_[i] =
SDL_GameControllerGetButton( SDL_GameControllerGetButton(
controller_, static_cast<SDL_GameControllerButton>(i)) != 0; controller_, static_cast<SDL_GameControllerButton>(i)) != 0;
} }
// 读取摇杆(归一化到 -1.0 ~ 1.0
leftStickX_ = static_cast<float>(SDL_GameControllerGetAxis( leftStickX_ = static_cast<float>(SDL_GameControllerGetAxis(
controller_, SDL_CONTROLLER_AXIS_LEFTX)) / 32767.0f; controller_, SDL_CONTROLLER_AXIS_LEFTX)) / 32767.0f;
leftStickY_ = static_cast<float>(SDL_GameControllerGetAxis( leftStickY_ = static_cast<float>(SDL_GameControllerGetAxis(
@ -125,9 +153,14 @@ void Input::updateGamepad() {
} }
} }
/**
* @brief
*
*
* Switch平台使用原生触摸屏支持PC端支持可选触摸设备
*/
void Input::updateTouch() { void Input::updateTouch() {
#ifdef PLATFORM_SWITCH #ifdef PLATFORM_SWITCH
// Switch 原生触摸屏支持
SDL_TouchID touchId = SDL_GetTouchDevice(0); SDL_TouchID touchId = SDL_GetTouchDevice(0);
if (touchId != 0) { if (touchId != 0) {
touchCount_ = SDL_GetNumTouchFingers(touchId); touchCount_ = SDL_GetNumTouchFingers(touchId);
@ -135,7 +168,6 @@ void Input::updateTouch() {
SDL_Finger *finger = SDL_GetTouchFinger(touchId, 0); SDL_Finger *finger = SDL_GetTouchFinger(touchId, 0);
if (finger) { if (finger) {
touching_ = true; touching_ = true;
// SDL 触摸坐标是归一化 0.0~1.0,转换为像素坐标
touchPosition_ = Vec2(finger->x * 1280.0f, finger->y * 720.0f); touchPosition_ = Vec2(finger->x * 1280.0f, finger->y * 720.0f);
} else { } else {
touching_ = false; touching_ = false;
@ -148,7 +180,6 @@ void Input::updateTouch() {
touching_ = false; touching_ = false;
} }
#else #else
// PC 端:触摸屏可选支持(如果有触摸设备)
SDL_TouchID touchId = SDL_GetTouchDevice(0); SDL_TouchID touchId = SDL_GetTouchDevice(0);
if (touchId != 0) { if (touchId != 0) {
touchCount_ = SDL_GetNumTouchFingers(touchId); touchCount_ = SDL_GetNumTouchFingers(touchId);
@ -156,7 +187,6 @@ void Input::updateTouch() {
SDL_Finger *finger = SDL_GetTouchFinger(touchId, 0); SDL_Finger *finger = SDL_GetTouchFinger(touchId, 0);
if (finger) { if (finger) {
touching_ = true; touching_ = true;
// PC 端需要根据窗口大小转换坐标
int windowWidth, windowHeight; int windowWidth, windowHeight;
SDL_Window* window = SDL_GL_GetCurrentWindow(); SDL_Window* window = SDL_GL_GetCurrentWindow();
if (window) { if (window) {
@ -182,9 +212,16 @@ void Input::updateTouch() {
// 键盘输入 // 键盘输入
// ============================================================================ // ============================================================================
/**
* @brief
*
* Switch平台模拟键盘输入
*
* @param keyCode
* @return SDL手柄按钮枚举值
*/
SDL_GameControllerButton Input::mapKeyToButton(int keyCode) const { SDL_GameControllerButton Input::mapKeyToButton(int keyCode) const {
switch (keyCode) { switch (keyCode) {
// 方向键 → DPad
case Key::Up: case Key::Up:
return SDL_CONTROLLER_BUTTON_DPAD_UP; return SDL_CONTROLLER_BUTTON_DPAD_UP;
case Key::Down: case Key::Down:
@ -194,7 +231,6 @@ SDL_GameControllerButton Input::mapKeyToButton(int keyCode) const {
case Key::Right: case Key::Right:
return SDL_CONTROLLER_BUTTON_DPAD_RIGHT; return SDL_CONTROLLER_BUTTON_DPAD_RIGHT;
// WASD → 也映射到 DPad
case Key::W: case Key::W:
return SDL_CONTROLLER_BUTTON_DPAD_UP; return SDL_CONTROLLER_BUTTON_DPAD_UP;
case Key::S: case Key::S:
@ -204,7 +240,6 @@ SDL_GameControllerButton Input::mapKeyToButton(int keyCode) const {
case Key::D: case Key::D:
return SDL_CONTROLLER_BUTTON_DPAD_RIGHT; return SDL_CONTROLLER_BUTTON_DPAD_RIGHT;
// 常用键 → 手柄按钮
case Key::Z: case Key::Z:
return SDL_CONTROLLER_BUTTON_B; return SDL_CONTROLLER_BUTTON_B;
case Key::X: case Key::X:
@ -220,13 +255,11 @@ SDL_GameControllerButton Input::mapKeyToButton(int keyCode) const {
case Key::Escape: case Key::Escape:
return SDL_CONTROLLER_BUTTON_START; return SDL_CONTROLLER_BUTTON_START;
// 肩键
case Key::Q: case Key::Q:
return SDL_CONTROLLER_BUTTON_LEFTSHOULDER; return SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
case Key::E: case Key::E:
return SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; return SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
// Start/Select
case Key::Tab: case Key::Tab:
return SDL_CONTROLLER_BUTTON_BACK; return SDL_CONTROLLER_BUTTON_BACK;
case Key::Backspace: case Key::Backspace:
@ -237,15 +270,22 @@ SDL_GameControllerButton Input::mapKeyToButton(int keyCode) const {
} }
} }
/**
* @brief
*
*
* Switch平台映射到手柄按钮PC端直接读取键盘状态
*
* @param keyCode
* @return truefalse
*/
bool Input::isKeyDown(int keyCode) const { bool Input::isKeyDown(int keyCode) const {
#ifdef PLATFORM_SWITCH #ifdef PLATFORM_SWITCH
// Switch: 映射到手柄按钮
SDL_GameControllerButton button = mapKeyToButton(keyCode); SDL_GameControllerButton button = mapKeyToButton(keyCode);
if (button == SDL_CONTROLLER_BUTTON_INVALID) if (button == SDL_CONTROLLER_BUTTON_INVALID)
return false; return false;
return buttonsDown_[button]; return buttonsDown_[button];
#else #else
// PC: 直接使用键盘扫描码
SDL_Scancode scancode = SDL_GetScancodeFromKey(keyCode); SDL_Scancode scancode = SDL_GetScancodeFromKey(keyCode);
if (scancode >= 0 && scancode < MAX_KEYS) { if (scancode >= 0 && scancode < MAX_KEYS) {
return keysDown_[scancode]; return keysDown_[scancode];
@ -254,6 +294,14 @@ bool Input::isKeyDown(int keyCode) const {
#endif #endif
} }
/**
* @brief
*
*
*
* @param keyCode
* @return truefalse
*/
bool Input::isKeyPressed(int keyCode) const { bool Input::isKeyPressed(int keyCode) const {
#ifdef PLATFORM_SWITCH #ifdef PLATFORM_SWITCH
SDL_GameControllerButton button = mapKeyToButton(keyCode); SDL_GameControllerButton button = mapKeyToButton(keyCode);
@ -269,6 +317,14 @@ bool Input::isKeyPressed(int keyCode) const {
#endif #endif
} }
/**
* @brief
*
*
*
* @param keyCode
* @return truefalse
*/
bool Input::isKeyReleased(int keyCode) const { bool Input::isKeyReleased(int keyCode) const {
#ifdef PLATFORM_SWITCH #ifdef PLATFORM_SWITCH
SDL_GameControllerButton button = mapKeyToButton(keyCode); SDL_GameControllerButton button = mapKeyToButton(keyCode);
@ -288,39 +344,74 @@ bool Input::isKeyReleased(int keyCode) const {
// 手柄按钮 // 手柄按钮
// ============================================================================ // ============================================================================
/**
* @brief
*
* @param button
* @return truefalse
*/
bool Input::isButtonDown(int button) const { bool Input::isButtonDown(int button) const {
if (button < 0 || button >= MAX_BUTTONS) if (button < 0 || button >= MAX_BUTTONS)
return false; return false;
return buttonsDown_[button]; return buttonsDown_[button];
} }
/**
* @brief
*
* @param button
* @return truefalse
*/
bool Input::isButtonPressed(int button) const { bool Input::isButtonPressed(int button) const {
if (button < 0 || button >= MAX_BUTTONS) if (button < 0 || button >= MAX_BUTTONS)
return false; return false;
return buttonsDown_[button] && !prevButtonsDown_[button]; return buttonsDown_[button] && !prevButtonsDown_[button];
} }
/**
* @brief
*
* @param button
* @return truefalse
*/
bool Input::isButtonReleased(int button) const { bool Input::isButtonReleased(int button) const {
if (button < 0 || button >= MAX_BUTTONS) if (button < 0 || button >= MAX_BUTTONS)
return false; return false;
return !buttonsDown_[button] && prevButtonsDown_[button]; return !buttonsDown_[button] && prevButtonsDown_[button];
} }
/**
* @brief
*
* @return X和Y轴值的二维向量-1.0~1.0
*/
Vec2 Input::getLeftStick() const { return Vec2(leftStickX_, leftStickY_); } Vec2 Input::getLeftStick() const { return Vec2(leftStickX_, leftStickY_); }
/**
* @brief
*
* @return X和Y轴值的二维向量-1.0~1.0
*/
Vec2 Input::getRightStick() const { return Vec2(rightStickX_, rightStickY_); } Vec2 Input::getRightStick() const { return Vec2(rightStickX_, rightStickY_); }
// ============================================================================ // ============================================================================
// 鼠标输入 // 鼠标输入
// ============================================================================ // ============================================================================
/**
* @brief
*
* Switch平台左键映射到触摸A键
*
* @param button
* @return truefalse
*/
bool Input::isMouseDown(MouseButton button) const { bool Input::isMouseDown(MouseButton button) const {
int index = static_cast<int>(button); int index = static_cast<int>(button);
if (index < 0 || index >= 8) if (index < 0 || index >= 8)
return false; return false;
#ifdef PLATFORM_SWITCH #ifdef PLATFORM_SWITCH
// Switch: 左键映射到触摸,右键映射到 A 键
if (button == MouseButton::Left) { if (button == MouseButton::Left) {
return touching_; return touching_;
} }
@ -329,11 +420,16 @@ bool Input::isMouseDown(MouseButton button) const {
} }
return false; return false;
#else #else
// PC: 直接使用鼠标按钮
return mouseButtonsDown_[index]; return mouseButtonsDown_[index];
#endif #endif
} }
/**
* @brief
*
* @param button
* @return truefalse
*/
bool Input::isMousePressed(MouseButton button) const { bool Input::isMousePressed(MouseButton button) const {
int index = static_cast<int>(button); int index = static_cast<int>(button);
if (index < 0 || index >= 8) if (index < 0 || index >= 8)
@ -353,6 +449,12 @@ bool Input::isMousePressed(MouseButton button) const {
#endif #endif
} }
/**
* @brief
*
* @param button
* @return truefalse
*/
bool Input::isMouseReleased(MouseButton button) const { bool Input::isMouseReleased(MouseButton button) const {
int index = static_cast<int>(button); int index = static_cast<int>(button);
if (index < 0 || index >= 8) if (index < 0 || index >= 8)
@ -372,6 +474,13 @@ bool Input::isMouseReleased(MouseButton button) const {
#endif #endif
} }
/**
* @brief
*
* Switch平台返回触摸位置PC端返回鼠标位置
*
* @return X和Y坐标的二维向量
*/
Vec2 Input::getMousePosition() const { Vec2 Input::getMousePosition() const {
#ifdef PLATFORM_SWITCH #ifdef PLATFORM_SWITCH
return touchPosition_; return touchPosition_;
@ -380,6 +489,13 @@ Vec2 Input::getMousePosition() const {
#endif #endif
} }
/**
* @brief
*
*
*
* @return X和Y移动量的二维向量
*/
Vec2 Input::getMouseDelta() const { Vec2 Input::getMouseDelta() const {
#ifdef PLATFORM_SWITCH #ifdef PLATFORM_SWITCH
if (touching_ && prevTouching_) { if (touching_ && prevTouching_) {
@ -391,6 +507,13 @@ Vec2 Input::getMouseDelta() const {
#endif #endif
} }
/**
* @brief
*
* PC端有效
*
* @param position
*/
void Input::setMousePosition(const Vec2 &position) { void Input::setMousePosition(const Vec2 &position) {
#ifndef PLATFORM_SWITCH #ifndef PLATFORM_SWITCH
SDL_WarpMouseInWindow(SDL_GL_GetCurrentWindow(), SDL_WarpMouseInWindow(SDL_GL_GetCurrentWindow(),
@ -401,6 +524,13 @@ void Input::setMousePosition(const Vec2 &position) {
#endif #endif
} }
/**
* @brief
*
* PC端有效
*
* @param visible true显示光标false隐藏光标
*/
void Input::setMouseVisible(bool visible) { void Input::setMouseVisible(bool visible) {
#ifndef PLATFORM_SWITCH #ifndef PLATFORM_SWITCH
SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE); SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE);
@ -409,6 +539,13 @@ void Input::setMouseVisible(bool visible) {
#endif #endif
} }
/**
* @brief
*
*
*
* @param locked true锁定鼠标到窗口中心false解锁
*/
void Input::setMouseLocked(bool locked) { void Input::setMouseLocked(bool locked) {
#ifndef PLATFORM_SWITCH #ifndef PLATFORM_SWITCH
SDL_SetRelativeMouseMode(locked ? SDL_TRUE : SDL_FALSE); SDL_SetRelativeMouseMode(locked ? SDL_TRUE : SDL_FALSE);
@ -421,6 +558,13 @@ void Input::setMouseLocked(bool locked) {
// 便捷方法 // 便捷方法
// ============================================================================ // ============================================================================
/**
* @brief
*
* Switch平台检查手柄按钮PC端检查键盘按键
*
* @return truefalse
*/
bool Input::isAnyKeyDown() const { bool Input::isAnyKeyDown() const {
#ifdef PLATFORM_SWITCH #ifdef PLATFORM_SWITCH
for (int i = 0; i < MAX_BUTTONS; ++i) { for (int i = 0; i < MAX_BUTTONS; ++i) {
@ -436,6 +580,13 @@ bool Input::isAnyKeyDown() const {
return false; return false;
} }
/**
* @brief
*
* Switch平台检查触摸状态PC端检查鼠标按钮
*
* @return truefalse
*/
bool Input::isAnyMouseDown() const { bool Input::isAnyMouseDown() const {
#ifdef PLATFORM_SWITCH #ifdef PLATFORM_SWITCH
return touching_; return touching_;
@ -452,11 +603,25 @@ bool Input::isAnyMouseDown() const {
// 视口适配器 // 视口适配器
// ============================================================================ // ============================================================================
/**
* @brief
*
*
*
* @param adapter
*/
void Input::setViewportAdapter(ViewportAdapter* adapter) { void Input::setViewportAdapter(ViewportAdapter* adapter) {
viewportAdapter_ = adapter; viewportAdapter_ = adapter;
} }
Vec2 Input::getMousePositionLogic() const { /**
* @brief
*
*
*
* @return
*/
Vec2 Input::getMousePosLogic() const {
Vec2 screenPos = getMousePosition(); Vec2 screenPos = getMousePosition();
if (viewportAdapter_) { if (viewportAdapter_) {
return viewportAdapter_->screenToLogic(screenPos); return viewportAdapter_->screenToLogic(screenPos);
@ -464,7 +629,14 @@ Vec2 Input::getMousePositionLogic() const {
return screenPos; return screenPos;
} }
Vec2 Input::getTouchPositionLogic() const { /**
* @brief
*
*
*
* @return
*/
Vec2 Input::getTouchPosLogic() const {
Vec2 screenPos = getTouchPosition(); Vec2 screenPos = getTouchPosition();
if (viewportAdapter_) { if (viewportAdapter_) {
return viewportAdapter_->screenToLogic(screenPos); return viewportAdapter_->screenToLogic(screenPos);
@ -472,6 +644,13 @@ Vec2 Input::getTouchPositionLogic() const {
return screenPos; return screenPos;
} }
/**
* @brief
*
*
*
* @return
*/
Vec2 Input::getMouseDeltaLogic() const { Vec2 Input::getMouseDeltaLogic() const {
Vec2 delta = getMouseDelta(); Vec2 delta = getMouseDelta();
if (viewportAdapter_) { if (viewportAdapter_) {

View File

@ -9,19 +9,38 @@
namespace extra2d { namespace extra2d {
/**
* @brief
*
* SDL窗口指针OpenGL上下文
* VSync状态等
*/
Window::Window() Window::Window()
: sdlWindow_(nullptr), glContext_(nullptr), currentCursor_(nullptr), : sdlWindow_(nullptr), glContext_(nullptr), currentCursor_(nullptr),
width_(1280), height_(720), vsync_(true), shouldClose_(false), width_(1280), height_(720), vsync_(true), shouldClose_(false),
fullscreen_(true), focused_(true), contentScaleX_(1.0f), contentScaleY_(1.0f), fullscreen_(true), focused_(true), contentScaleX_(1.0f),
enableDpiScale_(true), userData_(nullptr), eventQueue_(nullptr) { contentScaleY_(1.0f), enableDpiScale_(true), userData_(nullptr),
// 初始化光标数组 eventQueue_(nullptr) {
for (int i = 0; i < 9; ++i) { for (int i = 0; i < 9; ++i) {
sdlCursors_[i] = nullptr; sdlCursors_[i] = nullptr;
} }
} }
/**
* @brief
*
* destroy()
*/
Window::~Window() { destroy(); } Window::~Window() { destroy(); }
/**
* @brief
*
* SDL窗口和OpenGL ES上下文
*
* @param config
* @return truefalse
*/
bool Window::create(const WindowConfig &config) { bool Window::create(const WindowConfig &config) {
if (sdlWindow_ != nullptr) { if (sdlWindow_ != nullptr) {
E2D_LOG_WARN("Window already created"); E2D_LOG_WARN("Window already created");
@ -34,17 +53,14 @@ bool Window::create(const WindowConfig &config) {
fullscreen_ = config.fullscreen; fullscreen_ = config.fullscreen;
enableDpiScale_ = config.enableDpiScale; enableDpiScale_ = config.enableDpiScale;
// 初始化 SDL2 + 创建窗口 + GL 上下文
if (!initSDL(config)) { if (!initSDL(config)) {
E2D_LOG_ERROR("Failed to initialize SDL2"); E2D_LOG_ERROR("Failed to initialize SDL2");
return false; return false;
} }
// 创建输入管理器
input_ = makeUnique<Input>(); input_ = makeUnique<Input>();
input_->init(); input_->init();
// 初始化光标
if (config.enableCursors) { if (config.enableCursors) {
initCursors(); initCursors();
} }
@ -53,19 +69,26 @@ bool Window::create(const WindowConfig &config) {
return true; return true;
} }
/**
* @brief SDL库和OpenGL上下文
*
* SDL2全局初始化OpenGL ES 3.2
* OpenGL上下文并加载GLES函数指针
*
* @param config
* @return truefalse
*/
bool Window::initSDL(const WindowConfig &config) { bool Window::initSDL(const WindowConfig &config) {
// SDL2 全局初始化(视频 + 游戏控制器 + 音频) if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER | SDL_INIT_AUDIO) !=
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER | SDL_INIT_AUDIO) != 0) { 0) {
E2D_LOG_ERROR("SDL_Init failed: {}", SDL_GetError()); E2D_LOG_ERROR("SDL_Init failed: {}", SDL_GetError());
return false; 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_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
// 颜色/深度/模板缓冲配置
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_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_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
// 双缓冲
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
// 创建 SDL2 窗口
Uint32 windowFlags = SDL_WINDOW_OPENGL; Uint32 windowFlags = SDL_WINDOW_OPENGL;
// 根据配置设置窗口模式
if (config.fullscreen) { if (config.fullscreen) {
// Switch 平台使用 SDL_WINDOW_FULLSCREEN固定分辨率
// PC 平台使用 SDL_WINDOW_FULLSCREEN_DESKTOP桌面全屏
if (config.fullscreenDesktop) { if (config.fullscreenDesktop) {
windowFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP; windowFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
} else { } else {
@ -92,8 +110,6 @@ bool Window::initSDL(const WindowConfig &config) {
if (config.resizable) { if (config.resizable) {
windowFlags |= SDL_WINDOW_RESIZABLE; windowFlags |= SDL_WINDOW_RESIZABLE;
} }
// 注意SDL_WINDOWPOS_CENTERED 是位置参数,不是窗口标志
// 窗口居中在 SDL_CreateWindow 的位置参数中处理
} }
sdlWindow_ = 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,
config.centerWindow ? SDL_WINDOWPOS_CENTERED : SDL_WINDOWPOS_UNDEFINED, config.centerWindow ? SDL_WINDOWPOS_CENTERED : SDL_WINDOWPOS_UNDEFINED,
width_, height_, windowFlags); width_, height_, windowFlags);
if (!sdlWindow_) { if (!sdlWindow_) {
E2D_LOG_ERROR("SDL_CreateWindow failed: {}", SDL_GetError()); E2D_LOG_ERROR("SDL_CreateWindow failed: {}", SDL_GetError());
SDL_Quit(); SDL_Quit();
return false; return false;
} }
// 创建 OpenGL ES 上下文
glContext_ = SDL_GL_CreateContext(sdlWindow_); glContext_ = SDL_GL_CreateContext(sdlWindow_);
if (!glContext_) { if (!glContext_) {
E2D_LOG_ERROR("SDL_GL_CreateContext failed: {}", SDL_GetError()); E2D_LOG_ERROR("SDL_GL_CreateContext failed: {}", SDL_GetError());
@ -128,8 +143,8 @@ bool Window::initSDL(const WindowConfig &config) {
return false; return false;
} }
// 加载 OpenGL ES 函数指针 if (gladLoadGLES2Loader(
if (gladLoadGLES2Loader(reinterpret_cast<GLADloadproc>(SDL_GL_GetProcAddress)) == 0) { reinterpret_cast<GLADloadproc>(SDL_GL_GetProcAddress)) == 0) {
E2D_LOG_ERROR("gladLoadGLES2Loader failed"); E2D_LOG_ERROR("gladLoadGLES2Loader failed");
SDL_GL_DeleteContext(glContext_); SDL_GL_DeleteContext(glContext_);
glContext_ = nullptr; glContext_ = nullptr;
@ -139,10 +154,8 @@ bool Window::initSDL(const WindowConfig &config) {
return false; return false;
} }
// 设置 VSync
SDL_GL_SetSwapInterval(vsync_ ? 1 : 0); SDL_GL_SetSwapInterval(vsync_ ? 1 : 0);
// 更新 DPI 缩放
if (config.enableDpiScale) { if (config.enableDpiScale) {
updateContentScale(); updateContentScale();
} }
@ -156,9 +169,14 @@ bool Window::initSDL(const WindowConfig &config) {
return true; return true;
} }
/**
* @brief SDL资源
*
* OpenGL上下文SDL窗口并退出SDL库
*/
void Window::deinitSDL() { void Window::deinitSDL() {
deinitCursors(); deinitCursors();
if (glContext_) { if (glContext_) {
SDL_GL_DeleteContext(glContext_); SDL_GL_DeleteContext(glContext_);
glContext_ = nullptr; glContext_ = nullptr;
@ -172,6 +190,11 @@ void Window::deinitSDL() {
SDL_Quit(); SDL_Quit();
} }
/**
* @brief
*
* deinitSDL()SDL相关资源
*/
void Window::destroy() { void Window::destroy() {
if (sdlWindow_ != nullptr) { if (sdlWindow_ != nullptr) {
input_.reset(); input_.reset();
@ -180,8 +203,13 @@ void Window::destroy() {
} }
} }
/**
* @brief
*
* SDL事件队列中的所有事件
*
*/
void Window::pollEvents() { void Window::pollEvents() {
// SDL2 事件循环
SDL_Event event; SDL_Event event;
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
switch (event.type) { switch (event.type) {
@ -220,28 +248,53 @@ void Window::pollEvents() {
} }
} }
// 输入更新
if (input_) { if (input_) {
input_->update(); input_->update();
} }
} }
/**
* @brief
*
*
*/
void Window::swapBuffers() { void Window::swapBuffers() {
if (sdlWindow_) { if (sdlWindow_) {
SDL_GL_SwapWindow(sdlWindow_); SDL_GL_SwapWindow(sdlWindow_);
} }
} }
/**
* @brief
*
* @return truefalse
*/
bool Window::shouldClose() const { return shouldClose_; } bool Window::shouldClose() const { return shouldClose_; }
/**
* @brief
*
* @param close
*/
void Window::setShouldClose(bool close) { shouldClose_ = close; } void Window::setShouldClose(bool close) { shouldClose_ = close; }
/**
* @brief
*
* @param title
*/
void Window::setTitle(const std::string &title) { void Window::setTitle(const std::string &title) {
if (sdlWindow_) { if (sdlWindow_) {
SDL_SetWindowTitle(sdlWindow_, title.c_str()); SDL_SetWindowTitle(sdlWindow_, title.c_str());
} }
} }
/**
* @brief
*
* @param width
* @param height
*/
void Window::setSize(int width, int height) { void Window::setSize(int width, int height) {
if (sdlWindow_) { if (sdlWindow_) {
SDL_SetWindowSize(sdlWindow_, width, height); 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_) { if (sdlWindow_) {
SDL_SetWindowPosition(sdlWindow_, x, y); SDL_SetWindowPosition(sdlWindow_, x, y);
} }
} }
/**
* @brief
*
* @param fullscreen true为全屏模式false为窗口模式
*/
void Window::setFullscreen(bool fullscreen) { void Window::setFullscreen(bool fullscreen) {
if (sdlWindow_) { if (sdlWindow_) {
// 默认使用桌面全屏模式PC 平台)
Uint32 flags = fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0; Uint32 flags = fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0;
SDL_SetWindowFullscreen(sdlWindow_, flags); SDL_SetWindowFullscreen(sdlWindow_, flags);
fullscreen_ = fullscreen; fullscreen_ = fullscreen;
} }
} }
/**
* @brief
*
* @param enabled true启用VSyncfalse禁用VSync
*/
void Window::setVSync(bool enabled) { void Window::setVSync(bool enabled) {
vsync_ = enabled; vsync_ = enabled;
SDL_GL_SetSwapInterval(enabled ? 1 : 0); SDL_GL_SetSwapInterval(enabled ? 1 : 0);
} }
/**
* @brief
*
* @param resizable true允许用户调整窗口大小false禁止调整
*/
void Window::setResizable(bool resizable) { void Window::setResizable(bool resizable) {
if (sdlWindow_) { if (sdlWindow_) {
SDL_SetWindowResizable(sdlWindow_, resizable ? SDL_TRUE : SDL_FALSE); SDL_SetWindowResizable(sdlWindow_, resizable ? SDL_TRUE : SDL_FALSE);
} }
} }
/**
* @brief
*
* @return X和Y坐标的二维向量
*/
Vec2 Window::getPosition() const { Vec2 Window::getPosition() const {
if (sdlWindow_) { if (sdlWindow_) {
int x, y; int x, y;
@ -285,18 +363,42 @@ Vec2 Window::getPosition() const {
return Vec2::Zero(); return Vec2::Zero();
} }
/**
* @brief X轴内容缩放比例
*
* DPI设置返回X轴的内容缩放比例DPI显示适配
*
* @return X轴缩放比例DPI缩放被禁用则返回1.0
*/
float Window::getContentScaleX() const { float Window::getContentScaleX() const {
return enableDpiScale_ ? contentScaleX_ : 1.0f; return enableDpiScale_ ? contentScaleX_ : 1.0f;
} }
/**
* @brief Y轴内容缩放比例
*
* DPI设置返回Y轴的内容缩放比例DPI显示适配
*
* @return Y轴缩放比例DPI缩放被禁用则返回1.0
*/
float Window::getContentScaleY() const { float Window::getContentScaleY() const {
return enableDpiScale_ ? contentScaleY_ : 1.0f; return enableDpiScale_ ? contentScaleY_ : 1.0f;
} }
/**
* @brief
*
* @return X和Y轴缩放比例的二维向量
*/
Vec2 Window::getContentScale() const { Vec2 Window::getContentScale() const {
return Vec2(getContentScaleX(), getContentScaleY()); return Vec2(getContentScaleX(), getContentScaleY());
} }
/**
* @brief
*
* @return truefalse
*/
bool Window::isMinimized() const { bool Window::isMinimized() const {
if (sdlWindow_) { if (sdlWindow_) {
Uint32 flags = SDL_GetWindowFlags(sdlWindow_); Uint32 flags = SDL_GetWindowFlags(sdlWindow_);
@ -305,6 +407,11 @@ bool Window::isMinimized() const {
return false; return false;
} }
/**
* @brief
*
* @return truefalse
*/
bool Window::isMaximized() const { bool Window::isMaximized() const {
if (sdlWindow_) { if (sdlWindow_) {
Uint32 flags = SDL_GetWindowFlags(sdlWindow_); Uint32 flags = SDL_GetWindowFlags(sdlWindow_);
@ -313,6 +420,12 @@ bool Window::isMaximized() const {
return true; return true;
} }
/**
* @brief
*
* 9
* 线
*/
void Window::initCursors() { void Window::initCursors() {
sdlCursors_[0] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); sdlCursors_[0] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
sdlCursors_[1] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); sdlCursors_[1] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
@ -325,6 +438,11 @@ void Window::initCursors() {
sdlCursors_[8] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW); sdlCursors_[8] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
} }
/**
* @brief
*
*
*/
void Window::deinitCursors() { void Window::deinitCursors() {
for (int i = 0; i < 9; ++i) { for (int i = 0; i < 9; ++i) {
if (sdlCursors_[i]) { if (sdlCursors_[i]) {
@ -335,6 +453,13 @@ void Window::deinitCursors() {
currentCursor_ = nullptr; currentCursor_ = nullptr;
} }
/**
* @brief
*
*
*
* @param shape
*/
void Window::setCursor(CursorShape shape) { void Window::setCursor(CursorShape shape) {
int index = static_cast<int>(shape); int index = static_cast<int>(shape);
if (index >= 0 && index < 9 && sdlCursors_[index]) { if (index >= 0 && index < 9 && sdlCursors_[index]) {
@ -343,23 +468,37 @@ void Window::setCursor(CursorShape shape) {
} }
} }
/**
* @brief
*
*
*/
void Window::resetCursor() { void Window::resetCursor() {
SDL_SetCursor(SDL_GetDefaultCursor()); SDL_SetCursor(SDL_GetDefaultCursor());
currentCursor_ = nullptr; currentCursor_ = nullptr;
} }
/**
* @brief
*
* @param visible true显示鼠标光标false隐藏鼠标光标
*/
void Window::setMouseVisible(bool visible) { void Window::setMouseVisible(bool visible) {
SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE); SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE);
} }
/**
* @brief
*
* DPI值更新内容缩放比例
* 96 DPI为基准计算缩放因子
*/
void Window::updateContentScale() { void Window::updateContentScale() {
if (sdlWindow_) { if (sdlWindow_) {
// 使用 DPI 计算内容缩放比例
int displayIndex = SDL_GetWindowDisplayIndex(sdlWindow_); int displayIndex = SDL_GetWindowDisplayIndex(sdlWindow_);
if (displayIndex >= 0) { if (displayIndex >= 0) {
float ddpi, hdpi, vdpi; float ddpi, hdpi, vdpi;
if (SDL_GetDisplayDPI(displayIndex, &ddpi, &hdpi, &vdpi) == 0) { if (SDL_GetDisplayDPI(displayIndex, &ddpi, &hdpi, &vdpi) == 0) {
// 假设标准 DPI 为 96
contentScaleX_ = hdpi / 96.0f; contentScaleX_ = hdpi / 96.0f;
contentScaleY_ = vdpi / 96.0f; contentScaleY_ = vdpi / 96.0f;
} }

View File

@ -7,18 +7,32 @@
namespace extra2d { namespace extra2d {
/**
* @brief
*
*
*/
Node::Node() = default; Node::Node() = default;
Node::~Node() { /**
removeAllChildren(); * @brief
} *
*
*/
Node::~Node() { clearChildren(); }
/**
* @brief
* @param child
*
*
*/
void Node::addChild(Ptr<Node> child) { void Node::addChild(Ptr<Node> child) {
if (!child || child.get() == this) { if (!child || child.get() == this) {
return; return;
} }
child->removeFromParent(); child->detach();
child->parent_ = weak_from_this(); child->parent_ = weak_from_this();
children_.push_back(child); children_.push_back(child);
childrenOrderDirty_ = true; childrenOrderDirty_ = true;
@ -39,6 +53,12 @@ void Node::addChild(Ptr<Node> child) {
} }
} }
/**
* @brief
* @param children
*
*
*/
void Node::addChildren(std::vector<Ptr<Node>> &&children) { void Node::addChildren(std::vector<Ptr<Node>> &&children) {
// 预留空间,避免多次扩容 // 预留空间,避免多次扩容
size_t newSize = children_.size() + children.size(); size_t newSize = children_.size() + children.size();
@ -51,7 +71,7 @@ void Node::addChildren(std::vector<Ptr<Node>> &&children) {
continue; continue;
} }
child->removeFromParent(); child->detach();
child->parent_ = weak_from_this(); child->parent_ = weak_from_this();
children_.push_back(child); children_.push_back(child);
@ -76,6 +96,12 @@ void Node::addChildren(std::vector<Ptr<Node>> &&children) {
} }
} }
/**
* @brief
* @param child
*
* 退
*/
void Node::removeChild(Ptr<Node> child) { void Node::removeChild(Ptr<Node> child) {
if (!child) if (!child)
return; return;
@ -98,14 +124,25 @@ void Node::removeChild(Ptr<Node> child) {
} }
} }
/**
* @brief
* @param name
*
*
*/
void Node::removeChildByName(const std::string &name) { void Node::removeChildByName(const std::string &name) {
auto child = getChildByName(name); auto child = findChild(name);
if (child) { if (child) {
removeChild(child); removeChild(child);
} }
} }
void Node::removeFromParent() { /**
* @brief
*
*
*/
void Node::detach() {
auto p = parent_.lock(); auto p = parent_.lock();
if (p) { if (p) {
// 安全获取 shared_ptr避免在对象未由 shared_ptr 管理时崩溃 // 安全获取 shared_ptr避免在对象未由 shared_ptr 管理时崩溃
@ -121,7 +158,12 @@ void Node::removeFromParent() {
} }
} }
void Node::removeAllChildren() { /**
* @brief
*
* 退
*/
void Node::clearChildren() {
for (auto &child : children_) { for (auto &child : children_) {
if (running_) { if (running_) {
child->onDetachFromScene(); child->onDetachFromScene();
@ -134,7 +176,14 @@ void Node::removeAllChildren() {
tagIndex_.clear(); tagIndex_.clear();
} }
Ptr<Node> Node::getChildByName(const std::string &name) const { /**
* @brief
* @param name
* @return nullptr
*
* 使O(1)
*/
Ptr<Node> Node::findChild(const std::string &name) const {
// 使用哈希索引O(1) 查找 // 使用哈希索引O(1) 查找
auto it = nameIndex_.find(name); auto it = nameIndex_.find(name);
if (it != nameIndex_.end()) { if (it != nameIndex_.end()) {
@ -143,7 +192,14 @@ Ptr<Node> Node::getChildByName(const std::string &name) const {
return nullptr; return nullptr;
} }
Ptr<Node> Node::getChildByTag(int tag) const { /**
* @brief
* @param tag
* @return nullptr
*
* 使O(1)
*/
Ptr<Node> Node::findChildByTag(int tag) const {
// 使用哈希索引O(1) 查找 // 使用哈希索引O(1) 查找
auto it = tagIndex_.find(tag); auto it = tagIndex_.find(tag);
if (it != tagIndex_.end()) { if (it != tagIndex_.end()) {
@ -152,53 +208,123 @@ Ptr<Node> Node::getChildByTag(int tag) const {
return nullptr; return nullptr;
} }
void Node::setPosition(const Vec2 &pos) { /**
* @brief
* @param pos
*/
void Node::setPos(const Vec2 &pos) {
position_ = pos; position_ = pos;
markTransformDirty(); 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) { void Node::setRotation(float degrees) {
rotation_ = degrees; rotation_ = degrees;
markTransformDirty(); markTransformDirty();
} }
/**
* @brief
* @param scale
*/
void Node::setScale(const Vec2 &scale) { void Node::setScale(const Vec2 &scale) {
scale_ = scale; scale_ = scale;
markTransformDirty(); markTransformDirty();
} }
/**
* @brief
* @param scale
*/
void Node::setScale(float scale) { setScale(Vec2(scale, 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)); } void Node::setScale(float x, float y) { setScale(Vec2(x, y)); }
/**
* @brief
* @param anchor 0-1
*/
void Node::setAnchor(const Vec2 &anchor) { void Node::setAnchor(const Vec2 &anchor) {
anchor_ = anchor; anchor_ = anchor;
markTransformDirty(); markTransformDirty();
} }
/**
* @brief
* @param x X坐标0-1
* @param y Y坐标0-1
*/
void Node::setAnchor(float x, float y) { setAnchor(Vec2(x, y)); } void Node::setAnchor(float x, float y) { setAnchor(Vec2(x, y)); }
/**
* @brief
* @param skew
*/
void Node::setSkew(const Vec2 &skew) { void Node::setSkew(const Vec2 &skew) {
skew_ = skew; skew_ = skew;
markTransformDirty(); markTransformDirty();
} }
/**
* @brief
* @param x X轴斜切角度
* @param y Y轴斜切角度
*/
void Node::setSkew(float x, float y) { setSkew(Vec2(x, y)); } void Node::setSkew(float x, float y) { setSkew(Vec2(x, y)); }
/**
* @brief
* @param opacity 0.0-1.0
*/
void Node::setOpacity(float opacity) { void Node::setOpacity(float opacity) {
opacity_ = std::clamp(opacity, 0.0f, 1.0f); opacity_ = std::clamp(opacity, 0.0f, 1.0f);
} }
/**
* @brief
* @param visible
*/
void Node::setVisible(bool visible) { visible_ = 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; } void Node::setFlipX(bool flipX) { flipX_ = flipX; }
/**
* @brief
* @param flipY
*/
void Node::setFlipY(bool flipY) { flipY_ = flipY; } void Node::setFlipY(bool flipY) { flipY_ = flipY; }
/**
* @brief Z序
* @param zOrder
*
* Z序值会在上层渲染
*/
void Node::setZOrder(int zOrder) { void Node::setZOrder(int zOrder) {
if (zOrder_ != zOrder) { if (zOrder_ != zOrder) {
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 = glm::vec4 worldPos =
getWorldTransform() * glm::vec4(localPos.x, localPos.y, 0.0f, 1.0f); getWorldTransform() * glm::vec4(localPos.x, localPos.y, 0.0f, 1.0f);
return Vec2(worldPos.x, worldPos.y); 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::mat4 invWorld = glm::inverse(getWorldTransform());
glm::vec4 localPos = invWorld * glm::vec4(worldPos.x, worldPos.y, 0.0f, 1.0f); glm::vec4 localPos = invWorld * glm::vec4(worldPos.x, worldPos.y, 0.0f, 1.0f);
return Vec2(localPos.x, localPos.y); return Vec2(localPos.x, localPos.y);
} }
/**
* @brief
* @return
*
*
*/
glm::mat4 Node::getLocalTransform() const { glm::mat4 Node::getLocalTransform() const {
if (transformDirty_) { if (transformDirty_) {
localTransform_ = glm::mat4(1.0f); localTransform_ = glm::mat4(1.0f);
@ -249,13 +391,19 @@ glm::mat4 Node::getLocalTransform() const {
return localTransform_; return localTransform_;
} }
/**
* @brief
* @return
*
*
*/
glm::mat4 Node::getWorldTransform() const { glm::mat4 Node::getWorldTransform() const {
if (worldTransformDirty_) { if (worldTransformDirty_) {
// 使用线程局部存储的固定数组,避免每帧内存分配 // 使用线程局部存储的固定数组,避免每帧内存分配
// 限制最大深度为 256 层,足以覆盖绝大多数场景 // 限制最大深度为 256 层,足以覆盖绝大多数场景
thread_local std::array<const Node*, 256> nodeChainCache; thread_local std::array<const Node *, 256> nodeChainCache;
thread_local size_t chainCount = 0; thread_local size_t chainCount = 0;
chainCount = 0; chainCount = 0;
const Node *current = this; const Node *current = this;
while (current && chainCount < nodeChainCache.size()) { while (current && chainCount < nodeChainCache.size()) {
@ -275,6 +423,11 @@ glm::mat4 Node::getWorldTransform() const {
return worldTransform_; return worldTransform_;
} }
/**
* @brief
*
*
*/
void Node::markTransformDirty() { void Node::markTransformDirty() {
// 避免重复标记,提高性能 // 避免重复标记,提高性能
if (!transformDirty_ || !worldTransformDirty_) { if (!transformDirty_ || !worldTransformDirty_) {
@ -288,12 +441,17 @@ void Node::markTransformDirty() {
} }
} }
void Node::batchUpdateTransforms() { /**
* @brief
*
*
*/
void Node::batchTransforms() {
// 如果本地变换脏了,先计算本地变换 // 如果本地变换脏了,先计算本地变换
if (transformDirty_) { if (transformDirty_) {
(void)getLocalTransform(); // 这会计算并缓存本地变换 (void)getLocalTransform(); // 这会计算并缓存本地变换
} }
// 如果世界变换脏了,需要重新计算 // 如果世界变换脏了,需要重新计算
if (worldTransformDirty_) { if (worldTransformDirty_) {
auto parent = parent_.lock(); auto parent = parent_.lock();
@ -306,13 +464,18 @@ void Node::batchUpdateTransforms() {
} }
worldTransformDirty_ = false; worldTransformDirty_ = false;
} }
// 递归更新子节点 // 递归更新子节点
for (auto &child : children_) { for (auto &child : children_) {
child->batchUpdateTransforms(); child->batchTransforms();
} }
} }
/**
* @brief
*
* onEnter
*/
void Node::onEnter() { void Node::onEnter() {
running_ = true; running_ = true;
for (auto &child : children_) { for (auto &child : children_) {
@ -320,6 +483,11 @@ void Node::onEnter() {
} }
} }
/**
* @brief 退
*
* onExit
*/
void Node::onExit() { void Node::onExit() {
running_ = false; running_ = false;
for (auto &child : children_) { for (auto &child : children_) {
@ -327,6 +495,12 @@ void Node::onExit() {
} }
} }
/**
* @brief
* @param dt
*
*
*/
void Node::onUpdate(float dt) { void Node::onUpdate(float dt) {
onUpdateNode(dt); onUpdateNode(dt);
@ -336,6 +510,12 @@ void Node::onUpdate(float dt) {
} }
} }
/**
* @brief
* @param renderer
*
*
*/
void Node::onRender(RenderBackend &renderer) { void Node::onRender(RenderBackend &renderer) {
if (!visible_) if (!visible_)
return; return;
@ -347,6 +527,12 @@ void Node::onRender(RenderBackend &renderer) {
} }
} }
/**
* @brief
* @param scene
*
*
*/
void Node::onAttachToScene(Scene *scene) { void Node::onAttachToScene(Scene *scene) {
scene_ = scene; scene_ = scene;
@ -355,6 +541,11 @@ void Node::onAttachToScene(Scene *scene) {
} }
} }
/**
* @brief
*
*
*/
void Node::onDetachFromScene() { void Node::onDetachFromScene() {
scene_ = nullptr; scene_ = nullptr;
for (auto &child : children_) { 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); } void Node::update(float dt) { onUpdate(dt); }
/**
* @brief
* @param renderer
*
* onRender进行渲染
*/
void Node::render(RenderBackend &renderer) { void Node::render(RenderBackend &renderer) {
if (childrenOrderDirty_) { if (childrenOrderDirty_) {
sortChildren(); sortChildren();
@ -375,6 +582,11 @@ void Node::render(RenderBackend &renderer) {
onRender(renderer); onRender(renderer);
} }
/**
* @brief Z序排序
*
* 使使
*/
void Node::sortChildren() { void Node::sortChildren() {
// 使用插入排序优化小范围更新场景 // 使用插入排序优化小范围更新场景
// 插入排序在大部分已有序的情况下性能接近O(n) // 插入排序在大部分已有序的情况下性能接近O(n)
@ -409,6 +621,13 @@ void Node::sortChildren() {
childrenOrderDirty_ = false; childrenOrderDirty_ = false;
} }
/**
* @brief
* @param commands
* @param parentZOrder Z序
*
*
*/
void Node::collectRenderCommands(std::vector<RenderCommand> &commands, void Node::collectRenderCommands(std::vector<RenderCommand> &commands,
int parentZOrder) { int parentZOrder) {
if (!visible_) if (!visible_)

View File

@ -5,10 +5,26 @@
namespace extra2d { namespace extra2d {
/**
* @brief
*
*
*/
Scene::Scene() { defaultCamera_ = makePtr<Camera>(); } Scene::Scene() { defaultCamera_ = makePtr<Camera>(); }
/**
* @brief
* @param camera
*/
void Scene::setCamera(Ptr<Camera> camera) { camera_ = camera; } void Scene::setCamera(Ptr<Camera> camera) { camera_ = camera; }
/**
* @brief
* @param width
* @param height
*
*
*/
void Scene::setViewportSize(float width, float height) { void Scene::setViewportSize(float width, float height) {
viewportSize_ = Size(width, height); viewportSize_ = Size(width, height);
if (defaultCamera_) { if (defaultCamera_) {
@ -18,10 +34,20 @@ void Scene::setViewportSize(float width, float height) {
} }
} }
/**
* @brief
* @param size
*/
void Scene::setViewportSize(const Size &size) { void Scene::setViewportSize(const Size &size) {
setViewportSize(size.width, size.height); setViewportSize(size.width, size.height);
} }
/**
* @brief
* @param renderer
*
*
*/
void Scene::renderScene(RenderBackend &renderer) { void Scene::renderScene(RenderBackend &renderer) {
if (!isVisible()) if (!isVisible())
return; return;
@ -32,12 +58,18 @@ void Scene::renderScene(RenderBackend &renderer) {
renderer.endFrame(); renderer.endFrame();
} }
/**
* @brief
* @param renderer
*
*
*/
void Scene::renderContent(RenderBackend &renderer) { void Scene::renderContent(RenderBackend &renderer) {
if (!isVisible()) if (!isVisible())
return; return;
// 在渲染前批量更新所有节点的世界变换 // 在渲染前批量更新所有节点的世界变换
batchUpdateTransforms(); batchTransforms();
Camera *activeCam = getActiveCamera(); Camera *activeCam = getActiveCamera();
if (activeCam) { if (activeCam) {
@ -49,20 +81,39 @@ void Scene::renderContent(RenderBackend &renderer) {
renderer.endSpriteBatch(); renderer.endSpriteBatch();
} }
/**
* @brief
* @param dt
*
* update方法
*/
void Scene::updateScene(float dt) { void Scene::updateScene(float dt) {
if (!paused_) { if (!paused_) {
update(dt); 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<RenderCommand> &commands, void Scene::collectRenderCommands(std::vector<RenderCommand> &commands,
int parentZOrder) { int parentZOrder) {
if (!isVisible()) if (!isVisible())
@ -72,6 +123,10 @@ void Scene::collectRenderCommands(std::vector<RenderCommand> &commands,
Node::collectRenderCommands(commands, parentZOrder); Node::collectRenderCommands(commands, parentZOrder);
} }
/**
* @brief
* @return
*/
Ptr<Scene> Scene::create() { return makePtr<Scene>(); } Ptr<Scene> Scene::create() { return makePtr<Scene>(); }
} // namespace extra2d } // namespace extra2d

View File

@ -12,6 +12,9 @@ namespace {
/** /**
* @brief - * @brief -
* @param node
* @param worldPos
* @return nullptr
*/ */
Node *hitTestTopmost(const Ptr<Node> &node, const Vec2 &worldPos) { Node *hitTestTopmost(const Ptr<Node> &node, const Vec2 &worldPos) {
if (!node || !node->isVisible()) { if (!node || !node->isVisible()) {
@ -34,7 +37,7 @@ Node *hitTestTopmost(const Ptr<Node> &node, const Vec2 &worldPos) {
return nullptr; return nullptr;
} }
Rect bounds = node->getBoundingBox(); Rect bounds = node->getBounds();
if (!bounds.empty() && bounds.containsPoint(worldPos)) { if (!bounds.empty() && bounds.containsPoint(worldPos)) {
return node.get(); return node.get();
} }
@ -44,6 +47,8 @@ Node *hitTestTopmost(const Ptr<Node> &node, const Vec2 &worldPos) {
/** /**
* @brief * @brief
* @param node
* @param event
*/ */
void dispatchToNode(Node *node, Event &event) { void dispatchToNode(Node *node, Event &event) {
if (!node) { if (!node) {
@ -54,11 +59,21 @@ void dispatchToNode(Node *node, Event &event) {
} // namespace } // namespace
SceneManager &SceneManager::getInstance() { /**
* @brief
* @return
*/
SceneManager &SceneManager::get() {
static SceneManager instance; static SceneManager instance;
return instance; return instance;
} }
/**
* @brief
* @param scene
*
*
*/
void SceneManager::runWithScene(Ptr<Scene> scene) { void SceneManager::runWithScene(Ptr<Scene> scene) {
if (!scene) { if (!scene) {
return; return;
@ -74,6 +89,12 @@ void SceneManager::runWithScene(Ptr<Scene> scene) {
sceneStack_.push(scene); sceneStack_.push(scene);
} }
/**
* @brief
* @param scene
*
*
*/
void SceneManager::replaceScene(Ptr<Scene> scene) { void SceneManager::replaceScene(Ptr<Scene> scene) {
if (!scene || isTransitioning_) { if (!scene || isTransitioning_) {
return; return;
@ -94,6 +115,12 @@ void SceneManager::replaceScene(Ptr<Scene> scene) {
sceneStack_.push(scene); sceneStack_.push(scene);
} }
/**
* @brief
* @param scene
*
*
*/
void SceneManager::enterScene(Ptr<Scene> scene) { void SceneManager::enterScene(Ptr<Scene> scene) {
if (!scene || isTransitioning_) { if (!scene || isTransitioning_) {
return; return;
@ -106,6 +133,12 @@ void SceneManager::enterScene(Ptr<Scene> scene) {
} }
} }
/**
* @brief
* @param scene
*
*
*/
void SceneManager::pushScene(Ptr<Scene> scene) { void SceneManager::pushScene(Ptr<Scene> scene) {
if (!scene || isTransitioning_) { if (!scene || isTransitioning_) {
return; return;
@ -120,6 +153,11 @@ void SceneManager::pushScene(Ptr<Scene> scene) {
sceneStack_.push(scene); sceneStack_.push(scene);
} }
/**
* @brief
*
*
*/
void SceneManager::popScene() { void SceneManager::popScene() {
if (sceneStack_.size() <= 1 || isTransitioning_) { if (sceneStack_.size() <= 1 || isTransitioning_) {
return; return;
@ -135,6 +173,11 @@ void SceneManager::popScene() {
} }
} }
/**
* @brief
*
*
*/
void SceneManager::popToRootScene() { void SceneManager::popToRootScene() {
if (sceneStack_.size() <= 1 || isTransitioning_) { if (sceneStack_.size() <= 1 || isTransitioning_) {
return; return;
@ -150,6 +193,12 @@ void SceneManager::popToRootScene() {
sceneStack_.top()->resume(); sceneStack_.top()->resume();
} }
/**
* @brief
* @param name
*
*
*/
void SceneManager::popToScene(const std::string &name) { void SceneManager::popToScene(const std::string &name) {
if (isTransitioning_) { if (isTransitioning_) {
return; return;
@ -174,6 +223,10 @@ void SceneManager::popToScene(const std::string &name) {
} }
} }
/**
* @brief
* @return nullptr
*/
Ptr<Scene> SceneManager::getCurrentScene() const { Ptr<Scene> SceneManager::getCurrentScene() const {
if (sceneStack_.empty()) { if (sceneStack_.empty()) {
return nullptr; return nullptr;
@ -181,6 +234,10 @@ Ptr<Scene> SceneManager::getCurrentScene() const {
return sceneStack_.top(); return sceneStack_.top();
} }
/**
* @brief
* @return nullptr
*/
Ptr<Scene> SceneManager::getPreviousScene() const { Ptr<Scene> SceneManager::getPreviousScene() const {
if (sceneStack_.size() < 2) { if (sceneStack_.size() < 2) {
return nullptr; return nullptr;
@ -191,6 +248,10 @@ Ptr<Scene> SceneManager::getPreviousScene() const {
return tempStack.top(); return tempStack.top();
} }
/**
* @brief
* @return nullptr
*/
Ptr<Scene> SceneManager::getRootScene() const { Ptr<Scene> SceneManager::getRootScene() const {
if (sceneStack_.empty()) { if (sceneStack_.empty()) {
return nullptr; return nullptr;
@ -205,6 +266,11 @@ Ptr<Scene> SceneManager::getRootScene() const {
return root; return root;
} }
/**
* @brief
* @param name
* @return nullptr
*/
Ptr<Scene> SceneManager::getSceneByName(const std::string &name) const { Ptr<Scene> SceneManager::getSceneByName(const std::string &name) const {
auto it = namedScenes_.find(name); auto it = namedScenes_.find(name);
if (it != namedScenes_.end()) { if (it != namedScenes_.end()) {
@ -223,10 +289,21 @@ Ptr<Scene> SceneManager::getSceneByName(const std::string &name) const {
return nullptr; return nullptr;
} }
/**
* @brief
* @param name
* @return truefalse
*/
bool SceneManager::hasScene(const std::string &name) const { bool SceneManager::hasScene(const std::string &name) const {
return getSceneByName(name) != nullptr; return getSceneByName(name) != nullptr;
} }
/**
* @brief
* @param dt
*
*
*/
void SceneManager::update(float dt) { void SceneManager::update(float dt) {
if (isTransitioning_) { if (isTransitioning_) {
hoverTarget_ = nullptr; hoverTarget_ = nullptr;
@ -243,6 +320,12 @@ void SceneManager::update(float dt) {
} }
} }
/**
* @brief
* @param renderer
*
* 使
*/
void SceneManager::render(RenderBackend &renderer) { void SceneManager::render(RenderBackend &renderer) {
Color clearColor = Colors::Black; Color clearColor = Colors::Black;
if (!sceneStack_.empty()) { if (!sceneStack_.empty()) {
@ -264,12 +347,23 @@ void SceneManager::render(RenderBackend &renderer) {
E2D_LOG_TRACE("SceneManager::render - endFrame"); E2D_LOG_TRACE("SceneManager::render - endFrame");
} }
/**
* @brief
* @param commands
*
*
*/
void SceneManager::collectRenderCommands(std::vector<RenderCommand> &commands) { void SceneManager::collectRenderCommands(std::vector<RenderCommand> &commands) {
if (!sceneStack_.empty()) { if (!sceneStack_.empty()) {
sceneStack_.top()->collectRenderCommands(commands, 0); sceneStack_.top()->collectRenderCommands(commands, 0);
} }
} }
/**
* @brief
*
* 退
*/
void SceneManager::end() { void SceneManager::end() {
while (!sceneStack_.empty()) { while (!sceneStack_.empty()) {
auto scene = sceneStack_.top(); auto scene = sceneStack_.top();
@ -280,10 +374,21 @@ void SceneManager::end() {
namedScenes_.clear(); namedScenes_.clear();
} }
/**
* @brief
*
*
*/
void SceneManager::purgeCachedScenes() { namedScenes_.clear(); } void SceneManager::purgeCachedScenes() { namedScenes_.clear(); }
/**
* @brief
* @param scene
*
*
*/
void SceneManager::dispatchPointerEvents(Scene &scene) { void SceneManager::dispatchPointerEvents(Scene &scene) {
auto &input = Application::instance().input(); auto &input = Application::get().input();
Vec2 screenPos = input.getMousePosition(); Vec2 screenPos = input.getMousePosition();
Vec2 worldPos = screenPos; Vec2 worldPos = screenPos;

View File

@ -7,10 +7,25 @@
namespace extra2d { namespace extra2d {
/**
* @brief
*
*
*/
ShapeNode::ShapeNode() = default; ShapeNode::ShapeNode() = default;
/**
* @brief
* @return
*/
Ptr<ShapeNode> ShapeNode::create() { return makePtr<ShapeNode>(); } Ptr<ShapeNode> ShapeNode::create() { return makePtr<ShapeNode>(); }
/**
* @brief
* @param pos
* @param color
* @return
*/
Ptr<ShapeNode> ShapeNode::createPoint(const Vec2 &pos, const Color &color) { Ptr<ShapeNode> ShapeNode::createPoint(const Vec2 &pos, const Color &color) {
auto node = makePtr<ShapeNode>(); auto node = makePtr<ShapeNode>();
node->shapeType_ = ShapeType::Point; node->shapeType_ = ShapeType::Point;
@ -19,6 +34,14 @@ Ptr<ShapeNode> ShapeNode::createPoint(const Vec2 &pos, const Color &color) {
return node; return node;
} }
/**
* @brief 线
* @param start 线
* @param end 线
* @param color 线
* @param width 线
* @return 线
*/
Ptr<ShapeNode> ShapeNode::createLine(const Vec2 &start, const Vec2 &end, Ptr<ShapeNode> ShapeNode::createLine(const Vec2 &start, const Vec2 &end,
const Color &color, float width) { const Color &color, float width) {
auto node = makePtr<ShapeNode>(); auto node = makePtr<ShapeNode>();
@ -29,6 +52,13 @@ Ptr<ShapeNode> ShapeNode::createLine(const Vec2 &start, const Vec2 &end,
return node; return node;
} }
/**
* @brief
* @param rect
* @param color
* @param width 线
* @return
*/
Ptr<ShapeNode> ShapeNode::createRect(const Rect &rect, const Color &color, Ptr<ShapeNode> ShapeNode::createRect(const Rect &rect, const Color &color,
float width) { float width) {
auto node = makePtr<ShapeNode>(); auto node = makePtr<ShapeNode>();
@ -42,6 +72,12 @@ Ptr<ShapeNode> ShapeNode::createRect(const Rect &rect, const Color &color,
return node; return node;
} }
/**
* @brief
* @param rect
* @param color
* @return
*/
Ptr<ShapeNode> ShapeNode::createFilledRect(const Rect &rect, Ptr<ShapeNode> ShapeNode::createFilledRect(const Rect &rect,
const Color &color) { const Color &color) {
auto node = createRect(rect, color, 0); auto node = createRect(rect, color, 0);
@ -49,6 +85,15 @@ Ptr<ShapeNode> ShapeNode::createFilledRect(const Rect &rect,
return node; return node;
} }
/**
* @brief
* @param center
* @param radius
* @param color
* @param segments
* @param width 线
* @return
*/
Ptr<ShapeNode> ShapeNode::createCircle(const Vec2 &center, float radius, Ptr<ShapeNode> ShapeNode::createCircle(const Vec2 &center, float radius,
const Color &color, int segments, const Color &color, int segments,
float width) { float width) {
@ -64,6 +109,14 @@ Ptr<ShapeNode> ShapeNode::createCircle(const Vec2 &center, float radius,
return node; return node;
} }
/**
* @brief
* @param center
* @param radius
* @param color
* @param segments
* @return
*/
Ptr<ShapeNode> ShapeNode::createFilledCircle(const Vec2 &center, float radius, Ptr<ShapeNode> ShapeNode::createFilledCircle(const Vec2 &center, float radius,
const Color &color, int segments) { const Color &color, int segments) {
auto node = createCircle(center, radius, color, segments, 0); auto node = createCircle(center, radius, color, segments, 0);
@ -71,6 +124,15 @@ Ptr<ShapeNode> ShapeNode::createFilledCircle(const Vec2 &center, float radius,
return node; return node;
} }
/**
* @brief
* @param p1
* @param p2
* @param p3
* @param color
* @param width 线
* @return
*/
Ptr<ShapeNode> ShapeNode::createTriangle(const Vec2 &p1, const Vec2 &p2, Ptr<ShapeNode> ShapeNode::createTriangle(const Vec2 &p1, const Vec2 &p2,
const Vec2 &p3, const Color &color, const Vec2 &p3, const Color &color,
float width) { float width) {
@ -83,6 +145,14 @@ Ptr<ShapeNode> ShapeNode::createTriangle(const Vec2 &p1, const Vec2 &p2,
return node; return node;
} }
/**
* @brief
* @param p1
* @param p2
* @param p3
* @param color
* @return
*/
Ptr<ShapeNode> ShapeNode::createFilledTriangle(const Vec2 &p1, const Vec2 &p2, Ptr<ShapeNode> ShapeNode::createFilledTriangle(const Vec2 &p1, const Vec2 &p2,
const Vec2 &p3, const Vec2 &p3,
const Color &color) { const Color &color) {
@ -91,6 +161,13 @@ Ptr<ShapeNode> ShapeNode::createFilledTriangle(const Vec2 &p1, const Vec2 &p2,
return node; return node;
} }
/**
* @brief
* @param points
* @param color
* @param width 线
* @return
*/
Ptr<ShapeNode> ShapeNode::createPolygon(const std::vector<Vec2> &points, Ptr<ShapeNode> ShapeNode::createPolygon(const std::vector<Vec2> &points,
const Color &color, float width) { const Color &color, float width) {
auto node = makePtr<ShapeNode>(); auto node = makePtr<ShapeNode>();
@ -102,6 +179,12 @@ Ptr<ShapeNode> ShapeNode::createPolygon(const std::vector<Vec2> &points,
return node; return node;
} }
/**
* @brief
* @param points
* @param color
* @return
*/
Ptr<ShapeNode> ShapeNode::createFilledPolygon(const std::vector<Vec2> &points, Ptr<ShapeNode> ShapeNode::createFilledPolygon(const std::vector<Vec2> &points,
const Color &color) { const Color &color) {
auto node = createPolygon(points, color, 0); auto node = createPolygon(points, color, 0);
@ -109,19 +192,36 @@ Ptr<ShapeNode> ShapeNode::createFilledPolygon(const std::vector<Vec2> &points,
return node; return node;
} }
/**
* @brief
* @param points
*/
void ShapeNode::setPoints(const std::vector<Vec2> &points) { void ShapeNode::setPoints(const std::vector<Vec2> &points) {
points_ = points; points_ = points;
} }
/**
* @brief
* @param point
*/
void ShapeNode::addPoint(const Vec2 &point) { void ShapeNode::addPoint(const Vec2 &point) {
points_.push_back(point); points_.push_back(point);
} }
/**
* @brief
*/
void ShapeNode::clearPoints() { void ShapeNode::clearPoints() {
points_.clear(); points_.clear();
} }
Rect ShapeNode::getBoundingBox() const { /**
* @brief
* @return
*
* 线
*/
Rect ShapeNode::getBounds() const {
if (points_.empty()) { if (points_.empty()) {
return Rect(); return Rect();
} }
@ -163,6 +263,12 @@ Rect ShapeNode::getBoundingBox() const {
(maxY - minY) + inflate * 2.0f); (maxY - minY) + inflate * 2.0f);
} }
/**
* @brief
* @param renderer
*
*
*/
void ShapeNode::onDraw(RenderBackend &renderer) { void ShapeNode::onDraw(RenderBackend &renderer) {
if (points_.empty()) { if (points_.empty()) {
return; return;
@ -245,6 +351,13 @@ void ShapeNode::onDraw(RenderBackend &renderer) {
} }
} }
/**
* @brief
* @param commands
* @param zOrder
*
*
*/
void ShapeNode::generateRenderCommand(std::vector<RenderCommand> &commands, void ShapeNode::generateRenderCommand(std::vector<RenderCommand> &commands,
int zOrder) { int zOrder) {
if (points_.empty()) { if (points_.empty()) {

View File

@ -7,10 +7,27 @@
namespace extra2d { namespace extra2d {
/**
* @brief
*
*
*/
Sprite::Sprite() = default; Sprite::Sprite() = default;
/**
* @brief
* @param texture 使
*
*
*/
Sprite::Sprite(Ptr<Texture> texture) { setTexture(texture); } Sprite::Sprite(Ptr<Texture> texture) { setTexture(texture); }
/**
* @brief
* @param texture
*
*
*/
void Sprite::setTexture(Ptr<Texture> texture) { void Sprite::setTexture(Ptr<Texture> texture) {
texture_ = texture; texture_ = texture;
if (texture_) { if (texture_) {
@ -19,27 +36,68 @@ void Sprite::setTexture(Ptr<Texture> texture) {
} }
} }
/**
* @brief
* @param rect
*
*
*/
void Sprite::setTextureRect(const Rect &rect) { textureRect_ = rect; } void Sprite::setTextureRect(const Rect &rect) { textureRect_ = rect; }
/**
* @brief
* @param color
*
*
*/
void Sprite::setColor(const Color &color) { color_ = color; } void Sprite::setColor(const Color &color) { color_ = color; }
/**
* @brief
* @param flip
*/
void Sprite::setFlipX(bool flip) { flipX_ = flip; } void Sprite::setFlipX(bool flip) { flipX_ = flip; }
/**
* @brief
* @param flip
*/
void Sprite::setFlipY(bool flip) { flipY_ = flip; } void Sprite::setFlipY(bool flip) { flipY_ = flip; }
/**
* @brief
* @return
*/
Ptr<Sprite> Sprite::create() { return makePtr<Sprite>(); } Ptr<Sprite> Sprite::create() { return makePtr<Sprite>(); }
/**
* @brief
* @param texture 使
* @return
*/
Ptr<Sprite> Sprite::create(Ptr<Texture> texture) { Ptr<Sprite> Sprite::create(Ptr<Texture> texture) {
return makePtr<Sprite>(texture); return makePtr<Sprite>(texture);
} }
/**
* @brief
* @param texture 使
* @param rect
* @return
*/
Ptr<Sprite> Sprite::create(Ptr<Texture> texture, const Rect &rect) { Ptr<Sprite> Sprite::create(Ptr<Texture> texture, const Rect &rect) {
auto sprite = makePtr<Sprite>(texture); auto sprite = makePtr<Sprite>(texture);
sprite->setTextureRect(rect); sprite->setTextureRect(rect);
return sprite; return sprite;
} }
Rect Sprite::getBoundingBox() const { /**
* @brief
* @return
*
*
*/
Rect Sprite::getBounds() const {
if (!texture_ || !texture_->isValid()) { if (!texture_ || !texture_->isValid()) {
return Rect(); return Rect();
} }
@ -63,6 +121,12 @@ Rect Sprite::getBoundingBox() const {
return Rect(l, t, std::abs(w), std::abs(h)); return Rect(l, t, std::abs(w), std::abs(h));
} }
/**
* @brief
* @param renderer
*
* 使
*/
void Sprite::onDraw(RenderBackend &renderer) { void Sprite::onDraw(RenderBackend &renderer) {
if (!texture_ || !texture_->isValid()) { if (!texture_ || !texture_->isValid()) {
return; return;
@ -108,6 +172,13 @@ void Sprite::onDraw(RenderBackend &renderer) {
anchor); anchor);
} }
/**
* @brief
* @param commands
* @param zOrder
*
*
*/
void Sprite::generateRenderCommand(std::vector<RenderCommand> &commands, void Sprite::generateRenderCommand(std::vector<RenderCommand> &commands,
int zOrder) { int zOrder) {
if (!texture_ || !texture_->isValid()) { if (!texture_ || !texture_->isValid()) {

View File

@ -12,7 +12,7 @@ std::string Logger::logFile_;
/** /**
* @brief * @brief
* @param level * @param level
* @return * @return
*/ */
const char *Logger::getLevelString(LogLevel level) { const char *Logger::getLevelString(LogLevel level) {
switch (level) { switch (level) {
@ -35,6 +35,8 @@ const char *Logger::getLevelString(LogLevel level) {
/** /**
* @brief * @brief
*
* SDL日志级别为详细模式
*/ */
void Logger::init() { void Logger::init() {
if (initialized_) { if (initialized_) {
@ -50,6 +52,8 @@ void Logger::init() {
/** /**
* @brief * @brief
*
*
*/ */
void Logger::shutdown() { void Logger::shutdown() {
if (initialized_) { if (initialized_) {
@ -60,7 +64,9 @@ void Logger::shutdown() {
/** /**
* @brief * @brief
* @param level * @param level
*
*
*/ */
void Logger::setLevel(LogLevel level) { void Logger::setLevel(LogLevel level) {
level_ = level; level_ = level;
@ -73,7 +79,9 @@ void Logger::setLevel(LogLevel level) {
/** /**
* @brief * @brief
* @param enable * @param enable true启用控制台输出false禁用
*
* SDL日志优先级实现
*/ */
void Logger::setConsoleOutput(bool enable) { void Logger::setConsoleOutput(bool enable) {
consoleOutput_ = enable; consoleOutput_ = enable;
@ -88,7 +96,9 @@ void Logger::setConsoleOutput(bool enable) {
/** /**
* @brief * @brief
* @param filename * @param filename
*
*
*/ */
void Logger::setFileOutput(const std::string &filename) { void Logger::setFileOutput(const std::string &filename) {
logFile_ = filename; logFile_ = filename;

View File

@ -3,26 +3,54 @@
namespace extra2d { namespace extra2d {
/**
* @brief
*
* 使
*/
Random::Random() : floatDist_(0.0f, 1.0f) { Random::Random() : floatDist_(0.0f, 1.0f) {
// 使用当前时间作为默认种子 // 使用当前时间作为默认种子
randomize(); randomize();
} }
Random &Random::getInstance() { /**
* @brief Random单例实例
* @return Random单例的引用
*/
Random &Random::get() {
static Random instance; static Random instance;
return instance; return instance;
} }
/**
* @brief
* @param seed
*/
void Random::setSeed(uint32 seed) { generator_.seed(seed); } void Random::setSeed(uint32 seed) { generator_.seed(seed); }
/**
* @brief 使
*
* 使
*/
void Random::randomize() { void Random::randomize() {
auto now = std::chrono::high_resolution_clock::now(); auto now = std::chrono::high_resolution_clock::now();
auto time = now.time_since_epoch().count(); auto time = now.time_since_epoch().count();
generator_.seed(static_cast<uint32>(time)); generator_.seed(static_cast<uint32>(time));
} }
/**
* @brief [0.0, 1.0]
* @return [0.0, 1.0]
*/
float Random::getFloat() { return floatDist_(generator_); } float Random::getFloat() { return floatDist_(generator_); }
/**
* @brief
* @param min
* @param max
* @return [min, max]
*/
float Random::getFloat(float min, float max) { float Random::getFloat(float min, float max) {
if (min >= max) { if (min >= max) {
return min; return min;
@ -30,6 +58,11 @@ float Random::getFloat(float min, float max) {
return min + floatDist_(generator_) * (max - min); return min + floatDist_(generator_) * (max - min);
} }
/**
* @brief [0, max]
* @param max
* @return [0, max]
*/
int Random::getInt(int max) { int Random::getInt(int max) {
if (max <= 0) { if (max <= 0) {
return 0; return 0;
@ -38,6 +71,12 @@ int Random::getInt(int max) {
return dist(generator_); return dist(generator_);
} }
/**
* @brief
* @param min
* @param max
* @return [min, max]
*/
int Random::getInt(int min, int max) { int Random::getInt(int min, int max) {
if (min >= max) { if (min >= max) {
return min; return min;
@ -46,8 +85,17 @@ int Random::getInt(int min, int max) {
return dist(generator_); return dist(generator_);
} }
/**
* @brief 50%
* @return
*/
bool Random::getBool() { return floatDist_(generator_) >= 0.5f; } bool Random::getBool() { return floatDist_(generator_) >= 0.5f; }
/**
* @brief
* @param probability true的概率[0.0, 1.0]
* @return
*/
bool Random::getBool(float probability) { bool Random::getBool(float probability) {
if (probability <= 0.0f) { if (probability <= 0.0f) {
return false; return false;
@ -58,11 +106,19 @@ bool Random::getBool(float probability) {
return floatDist_(generator_) < probability; return floatDist_(generator_) < probability;
} }
/**
* @brief
* @return [0, 2π]
*/
float Random::getAngle() { float Random::getAngle() {
static const float TWO_PI = 6.28318530718f; static const float TWO_PI = 6.28318530718f;
return floatDist_(generator_) * TWO_PI; return floatDist_(generator_) * TWO_PI;
} }
/**
* @brief
* @return [-1.0, 1.0]
*/
float Random::getSigned() { return floatDist_(generator_) * 2.0f - 1.0f; } float Random::getSigned() { return floatDist_(generator_) * 2.0f - 1.0f; }
} // namespace extra2d } // namespace extra2d

View File

@ -5,12 +5,23 @@ namespace extra2d {
uint32 Timer::nextId_ = 1; uint32 Timer::nextId_ = 1;
/**
* @brief
* @param interval
* @param repeat
* @param callback
*/
Timer::Timer(float interval, bool repeat, Callback callback) Timer::Timer(float interval, bool repeat, Callback callback)
: interval_(interval), elapsed_(0.0f), repeat_(repeat), paused_(false), : interval_(interval), elapsed_(0.0f), repeat_(repeat), paused_(false),
valid_(true), callback_(std::move(callback)) { valid_(true), callback_(std::move(callback)) {
id_ = nextId_++; id_ = nextId_++;
} }
/**
* @brief
* @param deltaTime
* @return truefalse
*/
bool Timer::update(float deltaTime) { bool Timer::update(float deltaTime) {
if (!valid_ || paused_) { if (!valid_ || paused_) {
return false; return false;
@ -35,18 +46,38 @@ bool Timer::update(float deltaTime) {
return false; return false;
} }
/**
* @brief
*
*
*/
void Timer::reset() { void Timer::reset() {
elapsed_ = 0.0f; elapsed_ = 0.0f;
valid_ = true; valid_ = true;
paused_ = false; paused_ = false;
} }
/**
* @brief
*/
void Timer::pause() { paused_ = true; } void Timer::pause() { paused_ = true; }
/**
* @brief
*/
void Timer::resume() { paused_ = false; } void Timer::resume() { paused_ = false; }
/**
* @brief
*
*
*/
void Timer::cancel() { valid_ = false; } void Timer::cancel() { valid_ = false; }
/**
* @brief
* @return 0
*/
float Timer::getRemaining() const { float Timer::getRemaining() const {
if (!valid_ || paused_) { if (!valid_ || paused_) {
return 0.0f; return 0.0f;
@ -58,6 +89,12 @@ float Timer::getRemaining() const {
// TimerManager 实现 // TimerManager 实现
// ============================================================================ // ============================================================================
/**
* @brief
* @param delay
* @param callback
* @return ID
*/
uint32 TimerManager::addTimer(float delay, Timer::Callback callback) { uint32 TimerManager::addTimer(float delay, Timer::Callback callback) {
auto timer = std::make_unique<Timer>(delay, false, std::move(callback)); auto timer = std::make_unique<Timer>(delay, false, std::move(callback));
uint32 id = timer->getId(); uint32 id = timer->getId();
@ -65,6 +102,12 @@ uint32 TimerManager::addTimer(float delay, Timer::Callback callback) {
return id; return id;
} }
/**
* @brief
* @param interval
* @param callback
* @return ID
*/
uint32 TimerManager::addRepeatingTimer(float interval, uint32 TimerManager::addRepeatingTimer(float interval,
Timer::Callback callback) { Timer::Callback callback) {
auto timer = std::make_unique<Timer>(interval, true, std::move(callback)); auto timer = std::make_unique<Timer>(interval, true, std::move(callback));
@ -73,6 +116,10 @@ uint32 TimerManager::addRepeatingTimer(float interval,
return id; return id;
} }
/**
* @brief
* @param timerId ID
*/
void TimerManager::cancelTimer(uint32 timerId) { void TimerManager::cancelTimer(uint32 timerId) {
auto it = timers_.find(timerId); auto it = timers_.find(timerId);
if (it != timers_.end()) { if (it != timers_.end()) {
@ -81,6 +128,10 @@ void TimerManager::cancelTimer(uint32 timerId) {
} }
} }
/**
* @brief
* @param timerId ID
*/
void TimerManager::pauseTimer(uint32 timerId) { void TimerManager::pauseTimer(uint32 timerId) {
auto it = timers_.find(timerId); auto it = timers_.find(timerId);
if (it != timers_.end()) { if (it != timers_.end()) {
@ -88,6 +139,10 @@ void TimerManager::pauseTimer(uint32 timerId) {
} }
} }
/**
* @brief
* @param timerId ID
*/
void TimerManager::resumeTimer(uint32 timerId) { void TimerManager::resumeTimer(uint32 timerId) {
auto it = timers_.find(timerId); auto it = timers_.find(timerId);
if (it != timers_.end()) { if (it != timers_.end()) {
@ -95,6 +150,12 @@ void TimerManager::resumeTimer(uint32 timerId) {
} }
} }
/**
* @brief
* @param deltaTime
*
*
*/
void TimerManager::update(float deltaTime) { void TimerManager::update(float deltaTime) {
timersToRemove_.clear(); timersToRemove_.clear();
@ -110,6 +171,9 @@ void TimerManager::update(float deltaTime) {
} }
} }
/**
* @brief
*/
void TimerManager::clear() { void TimerManager::clear() {
timers_.clear(); timers_.clear();
timersToRemove_.clear(); timersToRemove_.clear();

View File

@ -79,14 +79,3 @@ includes("xmake/engine.lua")
-- 定义引擎库 -- 定义引擎库
define_extra2d_engine() 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("========================================")