diff --git a/Extra2D/include/extra2d/graphics/texture/texture_pool.h b/Extra2D/include/extra2d/graphics/texture/texture_pool.h index 1bebf67..e2f9178 100644 --- a/Extra2D/include/extra2d/graphics/texture/texture_pool.h +++ b/Extra2D/include/extra2d/graphics/texture/texture_pool.h @@ -1,18 +1,19 @@ #pragma once -#include -#include -#include -#include - #include #include #include +#include +#include +#include +#include +#include #include #include #include #include + namespace extra2d { // 前向声明 diff --git a/Extra2D/include/extra2d/services/logger_service.h b/Extra2D/include/extra2d/services/logger_service.h index b0edcaa..2be0dc2 100644 --- a/Extra2D/include/extra2d/services/logger_service.h +++ b/Extra2D/include/extra2d/services/logger_service.h @@ -3,7 +3,6 @@ #include #include #include -#include #include #include @@ -13,13 +12,13 @@ namespace extra2d { * @brief 日志级别枚举 */ enum class LogLevel { - Trace = 0, - Debug = 1, - Info = 2, - Warn = 3, - Error = 4, - Fatal = 5, - Off = 6 + Trace = 0, + Debug = 1, + Info = 2, + Warn = 3, + Error = 4, + Fatal = 5, + Off = 6 }; /** @@ -27,70 +26,70 @@ enum class LogLevel { */ class ILogger : public IService { public: - virtual ~ILogger() = default; - - /** - * @brief 设置日志级别 - */ - virtual void setLevel(LogLevel level) = 0; - - /** - * @brief 获取日志级别 - */ - virtual LogLevel getLevel() const = 0; - - /** - * @brief 检查日志级别是否启用 - */ - virtual bool isEnabled(LogLevel level) const = 0; - - /** - * @brief 记录日志(格式化) - */ - virtual void log(LogLevel level, const char* fmt, ...) = 0; - - /** - * @brief 记录日志(字符串) - */ - virtual void log(LogLevel level, const std::string& msg) = 0; - - /** - * @brief Trace级别日志 - */ - virtual void trace(const char* fmt, ...) = 0; - - /** - * @brief Debug级别日志 - */ - virtual void debug(const char* fmt, ...) = 0; - - /** - * @brief Info级别日志 - */ - virtual void info(const char* fmt, ...) = 0; - - /** - * @brief Warn级别日志 - */ - virtual void warn(const char* fmt, ...) = 0; - - /** - * @brief Error级别日志 - */ - virtual void error(const char* fmt, ...) = 0; - - /** - * @brief Fatal级别日志 - */ - virtual void fatal(const char* fmt, ...) = 0; - - ServiceInfo getServiceInfo() const override { - ServiceInfo info; - info.name = "Logger"; - info.priority = ServicePriority::Core; - info.enabled = true; - return info; - } + virtual ~ILogger() = default; + + /** + * @brief 设置日志级别 + */ + virtual void setLevel(LogLevel level) = 0; + + /** + * @brief 获取日志级别 + */ + virtual LogLevel getLevel() const = 0; + + /** + * @brief 检查日志级别是否启用 + */ + virtual bool isEnabled(LogLevel level) const = 0; + + /** + * @brief 记录日志(格式化) + */ + virtual void log(LogLevel level, const char *fmt, ...) = 0; + + /** + * @brief 记录日志(字符串) + */ + virtual void log(LogLevel level, const std::string &msg) = 0; + + /** + * @brief Trace级别日志 + */ + virtual void trace(const char *fmt, ...) = 0; + + /** + * @brief Debug级别日志 + */ + virtual void debug(const char *fmt, ...) = 0; + + /** + * @brief Info级别日志 + */ + virtual void info(const char *fmt, ...) = 0; + + /** + * @brief Warn级别日志 + */ + virtual void warn(const char *fmt, ...) = 0; + + /** + * @brief Error级别日志 + */ + virtual void error(const char *fmt, ...) = 0; + + /** + * @brief Fatal级别日志 + */ + virtual void fatal(const char *fmt, ...) = 0; + + ServiceInfo getServiceInfo() const override { + ServiceInfo info; + info.name = "Logger"; + info.priority = ServicePriority::Core; + info.enabled = true; + return info; + } }; /** @@ -98,36 +97,36 @@ public: */ class ConsoleLogger : public ILogger { public: - ConsoleLogger(); - ~ConsoleLogger() override; - - bool initialize() override; - void shutdown() override; - - void setLevel(LogLevel level) override; - LogLevel getLevel() const override; - bool isEnabled(LogLevel level) const override; - - void log(LogLevel level, const char* fmt, ...) override; - void log(LogLevel level, const std::string& msg) override; - - void trace(const char* fmt, ...) override; - void debug(const char* fmt, ...) override; - void info(const char* fmt, ...) override; - void warn(const char* fmt, ...) override; - void error(const char* fmt, ...) override; - void fatal(const char* fmt, ...) override; + ConsoleLogger(); + ~ConsoleLogger() override; + + bool initialize() override; + void shutdown() override; + + void setLevel(LogLevel level) override; + LogLevel getLevel() const override; + bool isEnabled(LogLevel level) const override; + + void log(LogLevel level, const char *fmt, ...) override; + void log(LogLevel level, const std::string &msg) override; + + void trace(const char *fmt, ...) override; + void debug(const char *fmt, ...) override; + void info(const char *fmt, ...) override; + void warn(const char *fmt, ...) override; + void error(const char *fmt, ...) override; + void fatal(const char *fmt, ...) override; private: - void output(LogLevel level, const char* msg); - const char* getLevelString(LogLevel level); + void output(LogLevel level, const char *msg); + const char *getLevelString(LogLevel level); - LogLevel level_; - class Impl; - UniquePtr impl_; + LogLevel level_; + class Impl; + UniquePtr impl_; - // 服务注册元数据 - E2D_AUTO_REGISTER_SERVICE(ILogger, ConsoleLogger); + // 服务注册元数据 + E2D_AUTO_REGISTER_SERVICE(ILogger, ConsoleLogger); }; } // namespace extra2d @@ -135,87 +134,80 @@ private: // 格式化辅助函数 - 将参数转换为字符串 namespace extra2d { namespace detail { - template - std::string to_string(T&& value) { - using Decayed = std::decay_t; - if constexpr (std::is_same_v) { - return value; - } else if constexpr (std::is_same_v) { - return value ? value : "(null)"; - } else if constexpr (std::is_arithmetic_v) { - if constexpr (std::is_same_v) { - return value ? "true" : "false"; - } else if constexpr (std::is_floating_point_v) { - return std::to_string(value); - } else { - return std::to_string(value); - } - } else { - return ""; - } - } - - inline void format_impl(std::string& result, const char* fmt) { - result += fmt; - } - - template - void format_impl(std::string& result, const char* fmt, T&& value, Args&&... args) { - const char* p = fmt; - while (*p) { - if (*p == '{' && *(p + 1) == '}') { - result += to_string(std::forward(value)); - format_impl(result, p + 2, std::forward(args)...); - return; - } - result += *p++; - } - // 没有更多的 {},追加剩余参数(不应该发生) - result += " "; - result += to_string(std::forward(value)); - format_impl(result, p, std::forward(args)...); +template std::string to_string(T &&value) { + using Decayed = std::decay_t; + if constexpr (std::is_same_v) { + return value; + } else if constexpr (std::is_same_v) { + return value ? value : "(null)"; + } else if constexpr (std::is_arithmetic_v) { + if constexpr (std::is_same_v) { + return value ? "true" : "false"; + } else if constexpr (std::is_floating_point_v) { + return std::to_string(value); + } else { + return std::to_string(value); } + } else { + return ""; + } } -template -std::string format_str(const char* fmt, Args&&... args) { - if constexpr (sizeof...(args) == 0) { - return std::string(fmt); - } else { - std::string result; - detail::format_impl(result, fmt, std::forward(args)...); - return result; +inline void format_impl(std::string &result, const char *fmt) { result += fmt; } + +template +void format_impl(std::string &result, const char *fmt, T &&value, + Args &&...args) { + const char *p = fmt; + while (*p) { + if (*p == '{' && *(p + 1) == '}') { + result += to_string(std::forward(value)); + format_impl(result, p + 2, std::forward(args)...); + return; } + result += *p++; + } + // 没有更多的 {},追加剩余参数(不应该发生) + result += " "; + result += to_string(std::forward(value)); + format_impl(result, p, std::forward(args)...); } +} // namespace detail + +template +std::string format_str(const char *fmt, Args &&...args) { + if constexpr (sizeof...(args) == 0) { + return std::string(fmt); + } else { + std::string result; + detail::format_impl(result, fmt, std::forward(args)...); + return result; + } } +} // namespace extra2d // 便捷宏 - 自动获取日志服务 -#define E2D_LOG(level, ...) \ - do { \ - if (auto logService = ::extra2d::ServiceLocator::instance().tryGetService<::extra2d::ILogger>()) { \ - if (logService->isEnabled(level)) { \ - logService->log(level, ::extra2d::format_str(__VA_ARGS__)); \ - } \ - } \ - } while(0) +#define E2D_LOG(level, ...) \ + do { \ + if (auto logService = ::extra2d::ServiceLocator::instance() \ + .tryGetService<::extra2d::ILogger>()) { \ + if (logService->isEnabled(level)) { \ + logService->log(level, ::extra2d::format_str(__VA_ARGS__)); \ + } \ + } \ + } while (0) -#define E2D_LOG_TRACE(...) \ - E2D_LOG(::extra2d::LogLevel::Trace, __VA_ARGS__) +#define E2D_LOG_TRACE(...) E2D_LOG(::extra2d::LogLevel::Trace, __VA_ARGS__) -#define E2D_LOG_DEBUG(...) \ - E2D_LOG(::extra2d::LogLevel::Debug, __VA_ARGS__) +#define E2D_LOG_DEBUG(...) E2D_LOG(::extra2d::LogLevel::Debug, __VA_ARGS__) -#define E2D_LOG_INFO(...) \ - E2D_LOG(::extra2d::LogLevel::Info, __VA_ARGS__) +#define E2D_LOG_INFO(...) E2D_LOG(::extra2d::LogLevel::Info, __VA_ARGS__) -#define E2D_LOG_WARN(...) \ - E2D_LOG(::extra2d::LogLevel::Warn, __VA_ARGS__) +#define E2D_LOG_WARN(...) E2D_LOG(::extra2d::LogLevel::Warn, __VA_ARGS__) -#define E2D_LOG_ERROR(...) \ - E2D_LOG(::extra2d::LogLevel::Error, __VA_ARGS__) +#define E2D_LOG_ERROR(...) E2D_LOG(::extra2d::LogLevel::Error, __VA_ARGS__) -#define E2D_LOG_FATAL(...) \ - E2D_LOG(::extra2d::LogLevel::Fatal, __VA_ARGS__) +#define E2D_LOG_FATAL(...) E2D_LOG(::extra2d::LogLevel::Fatal, __VA_ARGS__) // 简写宏 #define E2D_INFO(...) E2D_LOG_INFO(__VA_ARGS__) @@ -224,9 +216,9 @@ std::string format_str(const char* fmt, Args&&... args) { #define E2D_FATAL(...) E2D_LOG_FATAL(__VA_ARGS__) #ifdef E2D_DEBUG - #define E2D_DEBUG_LOG(...) E2D_LOG_DEBUG(__VA_ARGS__) - #define E2D_TRACE(...) E2D_LOG_TRACE(__VA_ARGS__) +#define E2D_DEBUG_LOG(...) E2D_LOG_DEBUG(__VA_ARGS__) +#define E2D_TRACE(...) E2D_LOG_TRACE(__VA_ARGS__) #else - #define E2D_DEBUG_LOG(...) - #define E2D_TRACE(...) +#define E2D_DEBUG_LOG(...) +#define E2D_TRACE(...) #endif diff --git a/Extra2D/include/extra2d/utils/logger.h b/Extra2D/include/extra2d/utils/logger.h deleted file mode 100644 index 086f3f9..0000000 --- a/Extra2D/include/extra2d/utils/logger.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -/** - * @file logger.h - * @brief 日志工具头文件 - * - * 提供便捷的日志宏定义,实际实现位于 logger_service.h - */ - -#include -#include - diff --git a/Extra2D/src/core/registry.cpp b/Extra2D/src/core/registry.cpp index f9eb1cb..43f641c 100644 --- a/Extra2D/src/core/registry.cpp +++ b/Extra2D/src/core/registry.cpp @@ -1,96 +1,97 @@ #include -#include -#include -#include -#include +#include +#include #include +#include namespace extra2d { -Registry& Registry::instance() { - static Registry instance; - return instance; +Registry &Registry::instance() { + static Registry instance; + return instance; } bool Registry::init() { - auto sorted = topologicalSort(); + auto sorted = topologicalSort(); - std::cout << "[Registry] Initializing " << sorted.size() << " modules..." << std::endl; + std::cout << "[Registry] Initializing " << sorted.size() << " modules..." + << std::endl; - for (auto* module : sorted) { - std::cout << "[Registry] Initializing module: " << module->name() << std::endl; - if (!module->init()) { - std::cerr << "[Registry] Failed to initialize module: " << module->name() << std::endl; - return false; - } - std::cout << "[Registry] Module " << module->name() << " initialized successfully" << std::endl; + for (auto *module : sorted) { + std::cout << "[Registry] Initializing module: " << module->name() + << std::endl; + if (!module->init()) { + std::cerr << "[Registry] Failed to initialize module: " << module->name() + << std::endl; + return false; } + std::cout << "[Registry] Module " << module->name() + << " initialized successfully" << std::endl; + } - std::cout << "[Registry] All modules initialized" << std::endl; - return true; + std::cout << "[Registry] All modules initialized" << std::endl; + return true; } void Registry::shutdown() { - auto sorted = topologicalSort(); - - // 反向关闭 - for (auto it = sorted.rbegin(); it != sorted.rend(); ++it) { - (*it)->shutdown(); - } + auto sorted = topologicalSort(); + + // 反向关闭 + for (auto it = sorted.rbegin(); it != sorted.rend(); ++it) { + (*it)->shutdown(); + } } void Registry::clear() { - shutdown(); - modules_.clear(); + shutdown(); + modules_.clear(); } -std::vector Registry::topologicalSort() { - std::vector result; - std::unordered_map inDegree; - std::unordered_map> adj; - - // 构建图 - for (auto& [typeIdx, module] : modules_) { - inDegree[module.get()] = 0; +std::vector Registry::topologicalSort() { + std::vector result; + std::unordered_map inDegree; + std::unordered_map> adj; + + // 构建图 + for (auto &[typeIdx, module] : modules_) { + inDegree[module.get()] = 0; + } + + for (auto &[typeIdx, module] : modules_) { + for (auto &depType : module->deps()) { + Module *dep = get(depType); + if (dep) { + adj[dep].push_back(module.get()); + inDegree[module.get()]++; + } } - - for (auto& [typeIdx, module] : modules_) { - for (auto& depType : module->deps()) { - Module* dep = get(depType); - if (dep) { - adj[dep].push_back(module.get()); - inDegree[module.get()]++; - } - } + } + + // 优先级队列(优先级小的先处理) + auto cmp = [](Module *a, Module *b) { return a->priority() > b->priority(); }; + std::priority_queue, decltype(cmp)> pq(cmp); + + for (auto &[mod, degree] : inDegree) { + if (degree == 0) { + pq.push(mod); } - - // 优先级队列(优先级小的先处理) - auto cmp = [](Module* a, Module* b) { - return a->priority() > b->priority(); - }; - std::priority_queue, decltype(cmp)> pq(cmp); - - for (auto& [mod, degree] : inDegree) { - if (degree == 0) { - pq.push(mod); - } + } + + // 拓扑排序 + while (!pq.empty()) { + Module *curr = pq.top(); + pq.pop(); + result.push_back(curr); + + for (Module *next : adj[curr]) { + inDegree[next]--; + if (inDegree[next] == 0) { + pq.push(next); + } } - - // 拓扑排序 - while (!pq.empty()) { - Module* curr = pq.top(); - pq.pop(); - result.push_back(curr); - - for (Module* next : adj[curr]) { - inDegree[next]--; - if (inDegree[next] == 0) { - pq.push(next); - } - } - } - - return result; + } + + return result; } } // namespace extra2d diff --git a/Extra2D/src/graphics/backends/backend_factory.cpp b/Extra2D/src/graphics/backends/backend_factory.cpp index 5f29487..e60613d 100644 --- a/Extra2D/src/graphics/backends/backend_factory.cpp +++ b/Extra2D/src/graphics/backends/backend_factory.cpp @@ -1,135 +1,142 @@ +#include #include -#include +#include namespace extra2d { namespace graphics { -std::unordered_map& BackendFactory::registry() { - static std::unordered_map reg; - return reg; +std::unordered_map & +BackendFactory::registry() { + static std::unordered_map reg; + return reg; } -void BackendFactory::reg(const std::string& name, BackendFn backend, - const std::vector& windowBackends) { - registry()[name] = {backend, windowBackends}; - E2D_LOG_DEBUG("Registered graphics backend: {} (window backends: {})", - name, windowBackends.size()); +void BackendFactory::reg(const std::string &name, BackendFn backend, + const std::vector &windowBackends) { + registry()[name] = {backend, windowBackends}; + E2D_LOG_DEBUG("Registered graphics backend: {} (window backends: {})", name, + windowBackends.size()); } -UniquePtr BackendFactory::createBackend(const std::string& name) { - auto& reg = registry(); - auto it = reg.find(name); - if (it != reg.end() && it->second.createFn) { - E2D_LOG_INFO("Creating graphics backend: {}", name); - return it->second.createFn(); - } - E2D_LOG_ERROR("Graphics backend '{}' not found", name); - return nullptr; +UniquePtr +BackendFactory::createBackend(const std::string &name) { + auto ® = registry(); + auto it = reg.find(name); + if (it != reg.end() && it->second.createFn) { + E2D_LOG_INFO("Creating graphics backend: {}", name); + return it->second.createFn(); + } + E2D_LOG_ERROR("Graphics backend '{}' not found", name); + return nullptr; } UniquePtr BackendFactory::createDefaultBackend() { - std::string recommended = getRecommendedBackend(); - if (recommended.empty()) { - E2D_LOG_ERROR("No graphics backend available"); - return nullptr; - } - return createBackend(recommended); + std::string recommended = getRecommendedBackend(); + if (recommended.empty()) { + E2D_LOG_ERROR("No graphics backend available"); + return nullptr; + } + return createBackend(recommended); } -UniquePtr BackendFactory::createBackendForWindow(const std::string& windowBackend) { - std::string recommended = getRecommendedBackendForWindow(windowBackend); - if (recommended.empty()) { - E2D_LOG_ERROR("No compatible graphics backend for window backend: {}", windowBackend); - return nullptr; - } - return createBackend(recommended); +UniquePtr +BackendFactory::createBackendForWindow(const std::string &windowBackend) { + std::string recommended = getRecommendedBackendForWindow(windowBackend); + if (recommended.empty()) { + E2D_LOG_ERROR("No compatible graphics backend for window backend: {}", + windowBackend); + return nullptr; + } + return createBackend(recommended); } std::vector BackendFactory::backends() { - std::vector result; - for (const auto& pair : registry()) { - result.push_back(pair.first); - } - return result; + std::vector result; + for (const auto &pair : registry()) { + result.push_back(pair.first); + } + return result; } -bool BackendFactory::has(const std::string& name) { - return registry().find(name) != registry().end(); +bool BackendFactory::has(const std::string &name) { + return registry().find(name) != registry().end(); } std::string BackendFactory::getRecommendedBackend() { - auto& reg = registry(); - - static const std::vector priority = { - "vulkan", "opengl", "d3d12", "d3d11", "metal", "opengles" - }; - - for (const auto& name : priority) { - if (reg.find(name) != reg.end()) { - return name; - } + auto ® = registry(); + + static const std::vector priority = { + "vulkan", "opengl", "d3d12", "d3d11", "metal", "opengles"}; + + for (const auto &name : priority) { + if (reg.find(name) != reg.end()) { + return name; } - - if (!reg.empty()) { - return reg.begin()->first; - } - - E2D_LOG_WARN("No graphics backend registered"); - return ""; + } + + if (!reg.empty()) { + return reg.begin()->first; + } + + E2D_LOG_WARN("No graphics backend registered"); + return ""; } -std::string BackendFactory::getRecommendedBackendForWindow(const std::string& windowBackend) { - auto& reg = registry(); - - static const std::vector priority = { - "vulkan", "opengl", "d3d12", "d3d11", "metal", "opengles" - }; - - for (const auto& name : priority) { - auto it = reg.find(name); - if (it != reg.end() && isCompatible(name, windowBackend)) { - return name; - } +std::string BackendFactory::getRecommendedBackendForWindow( + const std::string &windowBackend) { + auto ® = registry(); + + static const std::vector priority = { + "vulkan", "opengl", "d3d12", "d3d11", "metal", "opengles"}; + + for (const auto &name : priority) { + auto it = reg.find(name); + if (it != reg.end() && isCompatible(name, windowBackend)) { + return name; } - - for (const auto& pair : reg) { - if (isCompatible(pair.first, windowBackend)) { - return pair.first; - } + } + + for (const auto &pair : reg) { + if (isCompatible(pair.first, windowBackend)) { + return pair.first; } - - E2D_LOG_WARN("No compatible graphics backend for window backend: {}", windowBackend); - return ""; + } + + E2D_LOG_WARN("No compatible graphics backend for window backend: {}", + windowBackend); + return ""; } -bool BackendFactory::isCompatible(const std::string& graphicsBackend, const std::string& windowBackend) { - auto& reg = registry(); - auto it = reg.find(graphicsBackend); - if (it == reg.end()) { - return false; - } - - const auto& windowBackends = it->second.windowBackends; - if (windowBackends.empty()) { - return true; - } - - for (const auto& wb : windowBackends) { - if (wb == windowBackend) { - return true; - } - } - +bool BackendFactory::isCompatible(const std::string &graphicsBackend, + const std::string &windowBackend) { + auto ® = registry(); + auto it = reg.find(graphicsBackend); + if (it == reg.end()) { return false; + } + + const auto &windowBackends = it->second.windowBackends; + if (windowBackends.empty()) { + return true; + } + + for (const auto &wb : windowBackends) { + if (wb == windowBackend) { + return true; + } + } + + return false; } -std::vector BackendFactory::getSupportedWindowBackends(const std::string& graphicsBackend) { - auto& reg = registry(); - auto it = reg.find(graphicsBackend); - if (it != reg.end()) { - return it->second.windowBackends; - } - return {}; +std::vector +BackendFactory::getSupportedWindowBackends(const std::string &graphicsBackend) { + auto ® = registry(); + auto it = reg.find(graphicsBackend); + if (it != reg.end()) { + return it->second.windowBackends; + } + return {}; } } // namespace graphics diff --git a/Extra2D/src/graphics/backends/opengl/gl_buffer.cpp b/Extra2D/src/graphics/backends/opengl/gl_buffer.cpp index 153010a..adf5260 100644 --- a/Extra2D/src/graphics/backends/opengl/gl_buffer.cpp +++ b/Extra2D/src/graphics/backends/opengl/gl_buffer.cpp @@ -1,7 +1,9 @@ +#include +#include #include #include -#include -#include +#include + namespace extra2d { @@ -11,161 +13,162 @@ namespace extra2d { GLBuffer::GLBuffer() = default; -GLBuffer::~GLBuffer() { +GLBuffer::~GLBuffer() { shutdown(); } + +bool GLBuffer::init(const BufferDesc &desc) { + if (bufferID_ != 0) { shutdown(); -} + } -bool GLBuffer::init(const BufferDesc& desc) { - if (bufferID_ != 0) { - shutdown(); - } + type_ = desc.type; + usage_ = desc.usage; + size_ = desc.size; + target_ = convertType(type_); + glUsage_ = convertUsage(usage_); - type_ = desc.type; - usage_ = desc.usage; - size_ = desc.size; - target_ = convertType(type_); - glUsage_ = convertUsage(usage_); + // 生成缓冲区 + glGenBuffers(1, &bufferID_); + if (bufferID_ == 0) { + E2D_LOG_ERROR("Failed to generate OpenGL buffer"); + return false; + } - // 生成缓冲区 - glGenBuffers(1, &bufferID_); - if (bufferID_ == 0) { - E2D_LOG_ERROR("Failed to generate OpenGL buffer"); - return false; - } + // 绑定并分配缓冲区 + glBindBuffer(target_, bufferID_); + glBufferData(target_, static_cast(size_), desc.initialData, + glUsage_); + glBindBuffer(target_, 0); - // 绑定并分配缓冲区 - glBindBuffer(target_, bufferID_); - glBufferData(target_, static_cast(size_), desc.initialData, glUsage_); - glBindBuffer(target_, 0); + // 追踪显存使用 + VRAMMgr::get().allocBuffer(size_); - // 追踪显存使用 - VRAMMgr::get().allocBuffer(size_); + E2D_LOG_DEBUG("GLBuffer created: ID={}, Size={}, Type={}, Usage={}", + bufferID_, size_, static_cast(type_), + static_cast(usage_)); - E2D_LOG_DEBUG("GLBuffer created: ID={}, Size={}, Type={}, Usage={}", - bufferID_, size_, static_cast(type_), static_cast(usage_)); - - return true; + return true; } void GLBuffer::shutdown() { - if (bufferID_ != 0) { - if (mapped_) { - unmap(); - } - // 释放显存追踪 - VRAMMgr::get().freeBuffer(size_); - glDeleteBuffers(1, &bufferID_); - E2D_LOG_DEBUG("GLBuffer destroyed: ID={}", bufferID_); - bufferID_ = 0; + if (bufferID_ != 0) { + if (mapped_) { + unmap(); } - size_ = 0; - mapped_ = false; - mappedPtr_ = nullptr; + // 释放显存追踪 + VRAMMgr::get().freeBuffer(size_); + glDeleteBuffers(1, &bufferID_); + E2D_LOG_DEBUG("GLBuffer destroyed: ID={}", bufferID_); + bufferID_ = 0; + } + size_ = 0; + mapped_ = false; + mappedPtr_ = nullptr; } void GLBuffer::bind() { - if (bufferID_ != 0) { - glBindBuffer(target_, bufferID_); - } + if (bufferID_ != 0) { + glBindBuffer(target_, bufferID_); + } } -void GLBuffer::unbind() { - glBindBuffer(target_, 0); +void GLBuffer::unbind() { glBindBuffer(target_, 0); } + +void GLBuffer::setData(const void *data, size_t size) { + if (bufferID_ == 0) { + return; + } + + bind(); + + // 如果大小相同,使用 glBufferSubData 更高效 + if (size == size_) { + glBufferSubData(target_, 0, static_cast(size), data); + } else { + // 大小不同,重新分配 + size_ = size; + glBufferData(target_, static_cast(size_), data, glUsage_); + } + + unbind(); } -void GLBuffer::setData(const void* data, size_t size) { - if (bufferID_ == 0) { - return; - } +void GLBuffer::updateData(const void *data, size_t offset, size_t size) { + if (bufferID_ == 0 || data == nullptr || size == 0) { + return; + } - bind(); + if (offset + size > size_) { + E2D_LOG_WARN( + "GLBuffer updateData out of bounds: offset={}, size={}, bufferSize={}", + offset, size, size_); + return; + } - // 如果大小相同,使用 glBufferSubData 更高效 - if (size == size_) { - glBufferSubData(target_, 0, static_cast(size), data); - } else { - // 大小不同,重新分配 - size_ = size; - glBufferData(target_, static_cast(size_), data, glUsage_); - } - - unbind(); + bind(); + glBufferSubData(target_, static_cast(offset), + static_cast(size), data); + unbind(); } -void GLBuffer::updateData(const void* data, size_t offset, size_t size) { - if (bufferID_ == 0 || data == nullptr || size == 0) { - return; - } +void *GLBuffer::map() { + if (bufferID_ == 0 || mapped_) { + return nullptr; + } - if (offset + size > size_) { - E2D_LOG_WARN("GLBuffer updateData out of bounds: offset={}, size={}, bufferSize={}", - offset, size, size_); - return; - } + bind(); - bind(); - glBufferSubData(target_, static_cast(offset), static_cast(size), data); - unbind(); -} + // 使用 glMapBufferRange 替代 glMapBuffer,更现代且安全 + GLbitfield access = GL_MAP_WRITE_BIT; + if (usage_ == BufferUsage::Dynamic || usage_ == BufferUsage::Stream) { + access |= GL_MAP_INVALIDATE_BUFFER_BIT; // 暗示驱动可以丢弃旧数据 + } -void* GLBuffer::map() { - if (bufferID_ == 0 || mapped_) { - return nullptr; - } + mappedPtr_ = + glMapBufferRange(target_, 0, static_cast(size_), access); + if (mappedPtr_) { + mapped_ = true; + } else { + E2D_LOG_ERROR("Failed to map GLBuffer"); + } - bind(); - - // 使用 glMapBufferRange 替代 glMapBuffer,更现代且安全 - GLbitfield access = GL_MAP_WRITE_BIT; - if (usage_ == BufferUsage::Dynamic || usage_ == BufferUsage::Stream) { - access |= GL_MAP_INVALIDATE_BUFFER_BIT; // 暗示驱动可以丢弃旧数据 - } - - mappedPtr_ = glMapBufferRange(target_, 0, static_cast(size_), access); - if (mappedPtr_) { - mapped_ = true; - } else { - E2D_LOG_ERROR("Failed to map GLBuffer"); - } - - return mappedPtr_; + return mappedPtr_; } void GLBuffer::unmap() { - if (!mapped_ || bufferID_ == 0) { - return; - } + if (!mapped_ || bufferID_ == 0) { + return; + } - glUnmapBuffer(target_); - mapped_ = false; - mappedPtr_ = nullptr; - unbind(); + glUnmapBuffer(target_); + mapped_ = false; + mappedPtr_ = nullptr; + unbind(); } GLenum GLBuffer::convertUsage(BufferUsage usage) { - switch (usage) { - case BufferUsage::Static: - return GL_STATIC_DRAW; - case BufferUsage::Dynamic: - return GL_DYNAMIC_DRAW; - case BufferUsage::Stream: - return GL_STREAM_DRAW; - default: - return GL_STATIC_DRAW; - } + switch (usage) { + case BufferUsage::Static: + return GL_STATIC_DRAW; + case BufferUsage::Dynamic: + return GL_DYNAMIC_DRAW; + case BufferUsage::Stream: + return GL_STREAM_DRAW; + default: + return GL_STATIC_DRAW; + } } GLenum GLBuffer::convertType(BufferType type) { - switch (type) { - case BufferType::Vertex: - return GL_ARRAY_BUFFER; - case BufferType::Index: - return GL_ELEMENT_ARRAY_BUFFER; - case BufferType::Uniform: - return GL_UNIFORM_BUFFER; - default: - return GL_ARRAY_BUFFER; - } + switch (type) { + case BufferType::Vertex: + return GL_ARRAY_BUFFER; + case BufferType::Index: + return GL_ELEMENT_ARRAY_BUFFER; + case BufferType::Uniform: + return GL_UNIFORM_BUFFER; + default: + return GL_ARRAY_BUFFER; + } } } // namespace extra2d diff --git a/Extra2D/src/graphics/backends/opengl/gl_context.cpp b/Extra2D/src/graphics/backends/opengl/gl_context.cpp index f200581..cd925f9 100644 --- a/Extra2D/src/graphics/backends/opengl/gl_context.cpp +++ b/Extra2D/src/graphics/backends/opengl/gl_context.cpp @@ -1,8 +1,7 @@ +#include #include #include -#include -#include -#include +#include namespace extra2d { @@ -10,158 +9,162 @@ namespace extra2d { // GLContext 实现 // ============================================================================ -GLContext& GLContext::get() { - static GLContext instance; - return instance; +GLContext &GLContext::get() { + static GLContext instance; + return instance; } bool GLContext::init() { - if (initialized_) { - return true; - } - - // 解析 OpenGL 版本 - parseVersion(); - - // 加载扩展(GLAD 已在 glad.c 中完成) - if (!loadExtensions()) { - E2D_LOG_ERROR("Failed to load OpenGL extensions"); - return false; - } - - initialized_ = true; - - // 标记 GPU 上下文为有效 - GPUContext::get().markValid(); - - E2D_LOG_INFO("OpenGL Context initialized"); - E2D_LOG_INFO(" Version: {}", getVersionString()); - E2D_LOG_INFO(" Vendor: {}", getVendor()); - E2D_LOG_INFO(" Renderer: {}", getRenderer()); - E2D_LOG_INFO(" Max Texture Size: {}", getMaxTextureSize()); - E2D_LOG_INFO(" Max Texture Units: {}", getMaxTextureUnits()); - + if (initialized_) { return true; + } + + // 解析 OpenGL 版本 + parseVersion(); + + // 加载扩展(GLAD 已在 glad.c 中完成) + if (!loadExtensions()) { + E2D_LOG_ERROR("Failed to load OpenGL extensions"); + return false; + } + + initialized_ = true; + + // 标记 GPU 上下文为有效 + GPUContext::get().markValid(); + + E2D_LOG_INFO("OpenGL Context initialized"); + E2D_LOG_INFO(" Version: {}", getVersionString()); + E2D_LOG_INFO(" Vendor: {}", getVendor()); + E2D_LOG_INFO(" Renderer: {}", getRenderer()); + E2D_LOG_INFO(" Max Texture Size: {}", getMaxTextureSize()); + E2D_LOG_INFO(" Max Texture Units: {}", getMaxTextureUnits()); + + return true; } void GLContext::shutdown() { - // 标记 GPU 上下文为无效 - GPUContext::get().markInvalid(); + // 标记 GPU 上下文为无效 + GPUContext::get().markInvalid(); - initialized_ = false; - version_ = GLVersion{}; - maxTextureSize_ = -1; - maxTextureUnits_ = -1; - maxVertexAttribs_ = -1; - maxUniformBufferBindings_ = -1; + initialized_ = false; + version_ = GLVersion{}; + maxTextureSize_ = -1; + maxTextureUnits_ = -1; + maxVertexAttribs_ = -1; + maxUniformBufferBindings_ = -1; } std::string GLContext::getVersionString() const { - const char* version = reinterpret_cast(glGetString(GL_VERSION)); - return version ? version : "Unknown"; + const char *version = reinterpret_cast(glGetString(GL_VERSION)); + return version ? version : "Unknown"; } std::string GLContext::getVendor() const { - const char* vendor = reinterpret_cast(glGetString(GL_VENDOR)); - return vendor ? vendor : "Unknown"; + const char *vendor = reinterpret_cast(glGetString(GL_VENDOR)); + return vendor ? vendor : "Unknown"; } std::string GLContext::getRenderer() const { - const char* renderer = reinterpret_cast(glGetString(GL_RENDERER)); - return renderer ? renderer : "Unknown"; + const char *renderer = + reinterpret_cast(glGetString(GL_RENDERER)); + return renderer ? renderer : "Unknown"; } -bool GLContext::hasExtension(const std::string& extension) const { - GLint numExtensions = 0; - glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); +bool GLContext::hasExtension(const std::string &extension) const { + GLint numExtensions = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); - for (GLint i = 0; i < numExtensions; ++i) { - const char* ext = reinterpret_cast(glGetStringi(GL_EXTENSIONS, i)); - if (ext && extension == ext) { - return true; - } + for (GLint i = 0; i < numExtensions; ++i) { + const char *ext = + reinterpret_cast(glGetStringi(GL_EXTENSIONS, i)); + if (ext && extension == ext) { + return true; } + } - return false; + return false; } int GLContext::getMaxTextureSize() const { - if (maxTextureSize_ < 0) { - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize_); - } - return maxTextureSize_; + if (maxTextureSize_ < 0) { + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize_); + } + return maxTextureSize_; } int GLContext::getMaxTextureUnits() const { - if (maxTextureUnits_ < 0) { - glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits_); - } - return maxTextureUnits_; + if (maxTextureUnits_ < 0) { + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits_); + } + return maxTextureUnits_; } int GLContext::getMaxVertexAttribs() const { - if (maxVertexAttribs_ < 0) { - glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs_); - } - return maxVertexAttribs_; + if (maxVertexAttribs_ < 0) { + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs_); + } + return maxVertexAttribs_; } int GLContext::getMaxUniformBufferBindings() const { - if (maxUniformBufferBindings_ < 0) { - glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxUniformBufferBindings_); - } - return maxUniformBufferBindings_; + if (maxUniformBufferBindings_ < 0) { + glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxUniformBufferBindings_); + } + return maxUniformBufferBindings_; } bool GLContext::hasVAO() const { - // OpenGL 3.0+ 或 OpenGL ES 3.0+ 原生支持 VAO - if (version_.es) { - return version_.major >= 3; - } - return version_.major > 3 || (version_.major == 3 && version_.minor >= 0); + // OpenGL 3.0+ 或 OpenGL ES 3.0+ 原生支持 VAO + if (version_.es) { + return version_.major >= 3; + } + return version_.major > 3 || (version_.major == 3 && version_.minor >= 0); } bool GLContext::hasFBO() const { - // OpenGL 3.0+ 或 OpenGL ES 2.0+ 原生支持 FBO - if (version_.es) { - return version_.major >= 2; - } - return version_.major >= 3; + // OpenGL 3.0+ 或 OpenGL ES 2.0+ 原生支持 FBO + if (version_.es) { + return version_.major >= 2; + } + return version_.major >= 3; } bool GLContext::hasShader() const { - // OpenGL 2.0+ 或 OpenGL ES 2.0+ 原生支持 Shader - if (version_.es) { - return version_.major >= 2; - } + // OpenGL 2.0+ 或 OpenGL ES 2.0+ 原生支持 Shader + if (version_.es) { return version_.major >= 2; + } + return version_.major >= 2; } void GLContext::parseVersion() { - const char* versionStr = reinterpret_cast(glGetString(GL_VERSION)); - if (!versionStr) { - version_ = GLVersion{0, 0, false}; - return; - } + const char *versionStr = + reinterpret_cast(glGetString(GL_VERSION)); + if (!versionStr) { + version_ = GLVersion{0, 0, false}; + return; + } - std::string version(versionStr); + std::string version(versionStr); - // 检查是否为 OpenGL ES - if (version.find("OpenGL ES") != std::string::npos) { - version_.es = true; - // 解析 ES 版本号,格式如 "OpenGL ES 3.0" - std::sscanf(version.c_str(), "OpenGL ES %d.%d", &version_.major, &version_.minor); - } else { - version_.es = false; - // 解析桌面版本号,格式如 "3.3.0 NVIDIA" - std::sscanf(version.c_str(), "%d.%d", &version_.major, &version_.minor); - } + // 检查是否为 OpenGL ES + if (version.find("OpenGL ES") != std::string::npos) { + version_.es = true; + // 解析 ES 版本号,格式如 "OpenGL ES 3.0" + std::sscanf(version.c_str(), "OpenGL ES %d.%d", &version_.major, + &version_.minor); + } else { + version_.es = false; + // 解析桌面版本号,格式如 "3.3.0 NVIDIA" + std::sscanf(version.c_str(), "%d.%d", &version_.major, &version_.minor); + } } bool GLContext::loadExtensions() { - // GLAD 已经在 glad.c 中加载了所有扩展 - // 这里可以添加额外的扩展检查 - return true; + // GLAD 已经在 glad.c 中加载了所有扩展 + // 这里可以添加额外的扩展检查 + return true; } } // namespace extra2d diff --git a/Extra2D/src/graphics/backends/opengl/gl_font_atlas.cpp b/Extra2D/src/graphics/backends/opengl/gl_font_atlas.cpp index a578afe..76b3ede 100644 --- a/Extra2D/src/graphics/backends/opengl/gl_font_atlas.cpp +++ b/Extra2D/src/graphics/backends/opengl/gl_font_atlas.cpp @@ -1,8 +1,8 @@ +#include #include -#include +#include #include -#include #include #include diff --git a/Extra2D/src/graphics/backends/opengl/gl_framebuffer.cpp b/Extra2D/src/graphics/backends/opengl/gl_framebuffer.cpp index fdf44c8..42f3719 100644 --- a/Extra2D/src/graphics/backends/opengl/gl_framebuffer.cpp +++ b/Extra2D/src/graphics/backends/opengl/gl_framebuffer.cpp @@ -1,6 +1,8 @@ +#include #include #include -#include +#include + namespace extra2d { @@ -10,259 +12,261 @@ namespace extra2d { GLFramebuffer::GLFramebuffer() = default; -GLFramebuffer::~GLFramebuffer() { +GLFramebuffer::~GLFramebuffer() { shutdown(); } + +bool GLFramebuffer::init(const FramebufferDesc &desc) { + if (fboID_ != 0) { shutdown(); -} + } -bool GLFramebuffer::init(const FramebufferDesc& desc) { - if (fboID_ != 0) { - shutdown(); - } + width_ = desc.width; + height_ = desc.height; + numColorAttachments_ = desc.colorAttachments; + hasDepth_ = desc.hasDepth; + hasStencil_ = desc.hasStencil; - width_ = desc.width; - height_ = desc.height; - numColorAttachments_ = desc.colorAttachments; - hasDepth_ = desc.hasDepth; - hasStencil_ = desc.hasStencil; + // 限制颜色附件数 + if (numColorAttachments_ > MAX_COLOR_ATTACHMENTS) { + numColorAttachments_ = MAX_COLOR_ATTACHMENTS; + } - // 限制颜色附件数 - if (numColorAttachments_ > MAX_COLOR_ATTACHMENTS) { - numColorAttachments_ = MAX_COLOR_ATTACHMENTS; - } + // 生成 FBO + glGenFramebuffers(1, &fboID_); + if (fboID_ == 0) { + E2D_LOG_ERROR("Failed to generate OpenGL framebuffer"); + return false; + } - // 生成 FBO - glGenFramebuffers(1, &fboID_); - if (fboID_ == 0) { - E2D_LOG_ERROR("Failed to generate OpenGL framebuffer"); - return false; - } + E2D_LOG_DEBUG("GLFramebuffer created: ID={}, Size={}x{}, ColorAttachments={}", + fboID_, width_, height_, numColorAttachments_); - E2D_LOG_DEBUG("GLFramebuffer created: ID={}, Size={}x{}, ColorAttachments={}", - fboID_, width_, height_, numColorAttachments_); - - return true; + return true; } void GLFramebuffer::shutdown() { - if (fboID_ != 0) { - glDeleteFramebuffers(1, &fboID_); - E2D_LOG_DEBUG("GLFramebuffer destroyed: ID={}", fboID_); - fboID_ = 0; - } + if (fboID_ != 0) { + glDeleteFramebuffers(1, &fboID_); + E2D_LOG_DEBUG("GLFramebuffer destroyed: ID={}", fboID_); + fboID_ = 0; + } - // 清理纹理引用 - for (auto& tex : colorTextures_) { - tex.reset(); - } - depthTexture_.reset(); - depthStencilTexture_.reset(); + // 清理纹理引用 + for (auto &tex : colorTextures_) { + tex.reset(); + } + depthTexture_.reset(); + depthStencilTexture_.reset(); - hasInternalTextures_ = false; + hasInternalTextures_ = false; } void GLFramebuffer::bind() { - if (fboID_ != 0) { - glBindFramebuffer(GL_FRAMEBUFFER, fboID_); - } + if (fboID_ != 0) { + glBindFramebuffer(GL_FRAMEBUFFER, fboID_); + } } -void GLFramebuffer::unbind() { - glBindFramebuffer(GL_FRAMEBUFFER, 0); -} +void GLFramebuffer::unbind() { glBindFramebuffer(GL_FRAMEBUFFER, 0); } void GLFramebuffer::attachColorTexture(Ptr texture, int attachment) { - if (fboID_ == 0 || !texture || attachment < 0 || attachment >= MAX_COLOR_ATTACHMENTS) { - return; - } + if (fboID_ == 0 || !texture || attachment < 0 || + attachment >= MAX_COLOR_ATTACHMENTS) { + return; + } - bind(); + bind(); - // 获取 OpenGL 纹理 ID - GLuint texID = static_cast(reinterpret_cast(texture->getNativeHandle())); + // 获取 OpenGL 纹理 ID + GLuint texID = static_cast( + reinterpret_cast(texture->getNativeHandle())); - glFramebufferTexture2D(GL_FRAMEBUFFER, getColorAttachment(attachment), - GL_TEXTURE_2D, texID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, getColorAttachment(attachment), + GL_TEXTURE_2D, texID, 0); - colorTextures_[attachment] = texture; + colorTextures_[attachment] = texture; - unbind(); + unbind(); } void GLFramebuffer::attachDepthTexture(Ptr texture) { - if (fboID_ == 0 || !texture) { - return; - } + if (fboID_ == 0 || !texture) { + return; + } - bind(); + bind(); - // 获取 OpenGL 纹理 ID - GLuint texID = static_cast(reinterpret_cast(texture->getNativeHandle())); + // 获取 OpenGL 纹理 ID + GLuint texID = static_cast( + reinterpret_cast(texture->getNativeHandle())); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_TEXTURE_2D, texID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, + texID, 0); - depthTexture_ = texture; - hasDepth_ = true; - hasStencil_ = false; + depthTexture_ = texture; + hasDepth_ = true; + hasStencil_ = false; - unbind(); + unbind(); } void GLFramebuffer::attachDepthStencilTexture(Ptr texture) { - if (fboID_ == 0 || !texture) { - return; - } + if (fboID_ == 0 || !texture) { + return; + } - bind(); + bind(); - // 获取 OpenGL 纹理 ID - GLuint texID = static_cast(reinterpret_cast(texture->getNativeHandle())); + // 获取 OpenGL 纹理 ID + GLuint texID = static_cast( + reinterpret_cast(texture->getNativeHandle())); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, - GL_TEXTURE_2D, texID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, + GL_TEXTURE_2D, texID, 0); - depthStencilTexture_ = texture; - hasDepth_ = true; - hasStencil_ = true; + depthStencilTexture_ = texture; + hasDepth_ = true; + hasStencil_ = true; - unbind(); + unbind(); } bool GLFramebuffer::isComplete() { - if (fboID_ == 0) { - return false; - } + if (fboID_ == 0) { + return false; + } - bind(); - bool complete = checkStatus(); - unbind(); + bind(); + bool complete = checkStatus(); + unbind(); - return complete; + return complete; } Ptr GLFramebuffer::getColorTexture(int attachment) const { - if (attachment >= 0 && attachment < MAX_COLOR_ATTACHMENTS) { - return colorTextures_[attachment]; - } - return nullptr; + if (attachment >= 0 && attachment < MAX_COLOR_ATTACHMENTS) { + return colorTextures_[attachment]; + } + return nullptr; } -Ptr GLFramebuffer::getDepthTexture() const { - return depthTexture_; -} +Ptr GLFramebuffer::getDepthTexture() const { return depthTexture_; } -void GLFramebuffer::clear(const Color& color, bool clearColor, - bool clearDepth, bool clearStencil) { - if (fboID_ == 0) { - return; - } +void GLFramebuffer::clear(const Color &color, bool clearColor, bool clearDepth, + bool clearStencil) { + if (fboID_ == 0) { + return; + } - bind(); + bind(); - GLbitfield mask = 0; + GLbitfield mask = 0; - if (clearColor) { - mask |= GL_COLOR_BUFFER_BIT; - glClearColor(color.r, color.g, color.b, color.a); - } + if (clearColor) { + mask |= GL_COLOR_BUFFER_BIT; + glClearColor(color.r, color.g, color.b, color.a); + } - if (clearDepth) { - mask |= GL_DEPTH_BUFFER_BIT; - glClearDepthf(1.0f); - } + if (clearDepth) { + mask |= GL_DEPTH_BUFFER_BIT; + glClearDepthf(1.0f); + } - if (clearStencil) { - mask |= GL_STENCIL_BUFFER_BIT; - glClearStencil(0); - } + if (clearStencil) { + mask |= GL_STENCIL_BUFFER_BIT; + glClearStencil(0); + } - if (mask != 0) { - glClear(mask); - } + if (mask != 0) { + glClear(mask); + } - unbind(); + unbind(); } void GLFramebuffer::setViewport(int x, int y, int width, int height) { - glViewport(x, y, width, height); + glViewport(x, y, width, height); } -bool GLFramebuffer::readPixels(int x, int y, int width, int height, - std::vector& outData) { - if (fboID_ == 0 || width <= 0 || height <= 0) { - return false; - } +bool GLFramebuffer::readPixels(int x, int y, int width, int height, + std::vector &outData) { + if (fboID_ == 0 || width <= 0 || height <= 0) { + return false; + } - // 计算需要的缓冲区大小 (RGBA8) - size_t dataSize = width * height * 4; - outData.resize(dataSize); + // 计算需要的缓冲区大小 (RGBA8) + size_t dataSize = width * height * 4; + outData.resize(dataSize); - bind(); - glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, outData.data()); - unbind(); + bind(); + glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, outData.data()); + unbind(); - return true; + return true; } -bool GLFramebuffer::createWithTextures(int width, int height, +bool GLFramebuffer::createWithTextures(int width, int height, PixelFormat colorFormat, PixelFormat depthFormat) { - FramebufferDesc desc; - desc.width = width; - desc.height = height; - desc.colorAttachments = 1; - desc.hasDepth = (depthFormat != PixelFormat::RGBA8); - desc.hasStencil = (depthFormat == PixelFormat::Depth24Stencil8); + FramebufferDesc desc; + desc.width = width; + desc.height = height; + desc.colorAttachments = 1; + desc.hasDepth = (depthFormat != PixelFormat::RGBA8); + desc.hasStencil = (depthFormat == PixelFormat::Depth24Stencil8); - if (!init(desc)) { - return false; - } + if (!init(desc)) { + return false; + } - hasInternalTextures_ = true; + hasInternalTextures_ = true; - // 创建颜色纹理 - // 注意:这里简化处理,实际应该通过纹理工厂创建 - // 暂时返回 true,实际纹理创建由调用者处理 + // 创建颜色纹理 + // 注意:这里简化处理,实际应该通过纹理工厂创建 + // 暂时返回 true,实际纹理创建由调用者处理 - return true; + return true; } bool GLFramebuffer::checkStatus() { - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - switch (status) { - case GL_FRAMEBUFFER_COMPLETE: - return true; - case GL_FRAMEBUFFER_UNDEFINED: - E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_UNDEFINED"); - break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); - break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"); - break; + switch (status) { + case GL_FRAMEBUFFER_COMPLETE: + return true; + case GL_FRAMEBUFFER_UNDEFINED: + E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_UNDEFINED"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + E2D_LOG_ERROR( + "Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + E2D_LOG_ERROR( + "Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"); + break; #ifndef GL_ES_VERSION_2_0 - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: - E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"); - break; - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: - E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"); - break; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: + E2D_LOG_ERROR( + "Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: + E2D_LOG_ERROR( + "Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"); + break; #endif - case GL_FRAMEBUFFER_UNSUPPORTED: - E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_UNSUPPORTED"); - break; - default: - E2D_LOG_ERROR("Framebuffer incomplete: Unknown error {}", status); - break; - } + case GL_FRAMEBUFFER_UNSUPPORTED: + E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_UNSUPPORTED"); + break; + default: + E2D_LOG_ERROR("Framebuffer incomplete: Unknown error {}", status); + break; + } - return false; + return false; } GLenum GLFramebuffer::getColorAttachment(int index) { - return GL_COLOR_ATTACHMENT0 + index; + return GL_COLOR_ATTACHMENT0 + index; } } // namespace extra2d diff --git a/Extra2D/src/graphics/backends/opengl/gl_pipeline.cpp b/Extra2D/src/graphics/backends/opengl/gl_pipeline.cpp index 17d9349..cc7f168 100644 --- a/Extra2D/src/graphics/backends/opengl/gl_pipeline.cpp +++ b/Extra2D/src/graphics/backends/opengl/gl_pipeline.cpp @@ -1,5 +1,7 @@ +#include #include -#include +#include + namespace extra2d { @@ -9,214 +11,225 @@ namespace extra2d { GLPipeline::GLPipeline() = default; -GLPipeline::~GLPipeline() { +GLPipeline::~GLPipeline() { shutdown(); } + +bool GLPipeline::init(const PipelineDesc &desc) { + if (initialized_) { shutdown(); + } + + blendMode_ = desc.blendMode; + blendEnabled_ = desc.blendEnabled; + depthTest_ = desc.depthTest; + depthWrite_ = desc.depthWrite; + depthFunc_ = desc.depthFunc; + cullMode_ = desc.cullMode; + + initialized_ = true; + + E2D_LOG_DEBUG( + "GLPipeline initialized: blendMode={}, depthTest={}, cullMode={}", + static_cast(blendMode_), depthTest_, static_cast(cullMode_)); + + return true; } -bool GLPipeline::init(const PipelineDesc& desc) { - if (initialized_) { - shutdown(); - } - - blendMode_ = desc.blendMode; - blendEnabled_ = desc.blendEnabled; - depthTest_ = desc.depthTest; - depthWrite_ = desc.depthWrite; - depthFunc_ = desc.depthFunc; - cullMode_ = desc.cullMode; - - initialized_ = true; - - E2D_LOG_DEBUG("GLPipeline initialized: blendMode={}, depthTest={}, cullMode={}", - static_cast(blendMode_), depthTest_, static_cast(cullMode_)); - - return true; -} - -void GLPipeline::shutdown() { - initialized_ = false; -} +void GLPipeline::shutdown() { initialized_ = false; } void GLPipeline::bind() { - if (!initialized_) { - return; - } + if (!initialized_) { + return; + } - applyAllStates(); + applyAllStates(); } void GLPipeline::unbind() { - // OpenGL 不需要显式解绑管线 + // OpenGL 不需要显式解绑管线 } void GLPipeline::setBlendMode(BlendMode mode) { - blendMode_ = mode; - applyBlendState(); + blendMode_ = mode; + applyBlendState(); } void GLPipeline::setDepthTest(bool enabled) { - depthTest_ = enabled; - applyDepthState(); + depthTest_ = enabled; + applyDepthState(); } void GLPipeline::setDepthWrite(bool enabled) { - depthWrite_ = enabled; - applyDepthState(); + depthWrite_ = enabled; + applyDepthState(); } void GLPipeline::setDepthFunc(DepthFunc func) { - depthFunc_ = func; - applyDepthState(); + depthFunc_ = func; + applyDepthState(); } void GLPipeline::setCullMode(CullMode mode) { - cullMode_ = mode; - applyCullState(); + cullMode_ = mode; + applyCullState(); } void GLPipeline::setViewport(int x, int y, int width, int height) { - viewportX_ = x; - viewportY_ = y; - viewportWidth_ = width; - viewportHeight_ = height; + viewportX_ = x; + viewportY_ = y; + viewportWidth_ = width; + viewportHeight_ = height; - // 检查缓存,避免冗余调用 - if (x != cachedViewportX_ || y != cachedViewportY_ || - width != cachedViewportWidth_ || height != cachedViewportHeight_) { - glViewport(x, y, width, height); - cachedViewportX_ = x; - cachedViewportY_ = y; - cachedViewportWidth_ = width; - cachedViewportHeight_ = height; - } + // 检查缓存,避免冗余调用 + if (x != cachedViewportX_ || y != cachedViewportY_ || + width != cachedViewportWidth_ || height != cachedViewportHeight_) { + glViewport(x, y, width, height); + cachedViewportX_ = x; + cachedViewportY_ = y; + cachedViewportWidth_ = width; + cachedViewportHeight_ = height; + } } -void GLPipeline::getViewport(int& x, int& y, int& width, int& height) const { - x = viewportX_; - y = viewportY_; - width = viewportWidth_; - height = viewportHeight_; +void GLPipeline::getViewport(int &x, int &y, int &width, int &height) const { + x = viewportX_; + y = viewportY_; + width = viewportWidth_; + height = viewportHeight_; } void GLPipeline::applyAllStates() { - applyBlendState(); - applyDepthState(); - applyCullState(); + applyBlendState(); + applyDepthState(); + applyCullState(); - // 应用视口 - if (viewportWidth_ > 0 && viewportHeight_ > 0) { - setViewport(viewportX_, viewportY_, viewportWidth_, viewportHeight_); - } + // 应用视口 + if (viewportWidth_ > 0 && viewportHeight_ > 0) { + setViewport(viewportX_, viewportY_, viewportWidth_, viewportHeight_); + } } void GLPipeline::applyBlendState() { - // 检查是否需要启用/禁用混合 - if (blendEnabled_ != cachedBlendEnabled_) { - if (blendEnabled_) { - glEnable(GL_BLEND); - } else { - glDisable(GL_BLEND); - } - cachedBlendEnabled_ = blendEnabled_; + // 检查是否需要启用/禁用混合 + if (blendEnabled_ != cachedBlendEnabled_) { + if (blendEnabled_) { + glEnable(GL_BLEND); + } else { + glDisable(GL_BLEND); } + cachedBlendEnabled_ = blendEnabled_; + } - // 如果禁用了混合,不需要设置混合函数 - if (!blendEnabled_) { - return; - } + // 如果禁用了混合,不需要设置混合函数 + if (!blendEnabled_) { + return; + } - // 检查混合模式是否改变 - if (blendMode_ != cachedBlendMode_) { - GLenum srcFactor, dstFactor; - getBlendFactors(blendMode_, srcFactor, dstFactor); - glBlendFunc(srcFactor, dstFactor); - cachedBlendMode_ = blendMode_; - } + // 检查混合模式是否改变 + if (blendMode_ != cachedBlendMode_) { + GLenum srcFactor, dstFactor; + getBlendFactors(blendMode_, srcFactor, dstFactor); + glBlendFunc(srcFactor, dstFactor); + cachedBlendMode_ = blendMode_; + } } void GLPipeline::applyDepthState() { - // 深度测试 - if (depthTest_ != cachedDepthTest_) { - if (depthTest_) { - glEnable(GL_DEPTH_TEST); - } else { - glDisable(GL_DEPTH_TEST); - } - cachedDepthTest_ = depthTest_; + // 深度测试 + if (depthTest_ != cachedDepthTest_) { + if (depthTest_) { + glEnable(GL_DEPTH_TEST); + } else { + glDisable(GL_DEPTH_TEST); } + cachedDepthTest_ = depthTest_; + } - // 深度写入 - if (depthWrite_ != cachedDepthWrite_) { - glDepthMask(depthWrite_ ? GL_TRUE : GL_FALSE); - cachedDepthWrite_ = depthWrite_; - } + // 深度写入 + if (depthWrite_ != cachedDepthWrite_) { + glDepthMask(depthWrite_ ? GL_TRUE : GL_FALSE); + cachedDepthWrite_ = depthWrite_; + } - // 深度函数 - if (depthFunc_ != cachedDepthFunc_) { - glDepthFunc(convertDepthFunc(depthFunc_)); - cachedDepthFunc_ = depthFunc_; - } + // 深度函数 + if (depthFunc_ != cachedDepthFunc_) { + glDepthFunc(convertDepthFunc(depthFunc_)); + cachedDepthFunc_ = depthFunc_; + } } void GLPipeline::applyCullState() { - // 检查裁剪模式是否改变 - if (cullMode_ != cachedCullMode_) { - if (cullMode_ == CullMode::None) { - glDisable(GL_CULL_FACE); - } else { - glEnable(GL_CULL_FACE); - glCullFace(convertCullMode(cullMode_)); - } - cachedCullMode_ = cullMode_; + // 检查裁剪模式是否改变 + if (cullMode_ != cachedCullMode_) { + if (cullMode_ == CullMode::None) { + glDisable(GL_CULL_FACE); + } else { + glEnable(GL_CULL_FACE); + glCullFace(convertCullMode(cullMode_)); } + cachedCullMode_ = cullMode_; + } } -void GLPipeline::getBlendFactors(BlendMode mode, GLenum& srcFactor, GLenum& dstFactor) { - switch (mode) { - case BlendMode::None: - srcFactor = GL_ONE; - dstFactor = GL_ZERO; - break; - case BlendMode::Alpha: - srcFactor = GL_SRC_ALPHA; - dstFactor = GL_ONE_MINUS_SRC_ALPHA; - break; - case BlendMode::Additive: - srcFactor = GL_SRC_ALPHA; - dstFactor = GL_ONE; - break; - case BlendMode::Multiply: - srcFactor = GL_DST_COLOR; - dstFactor = GL_ONE_MINUS_SRC_ALPHA; - break; - default: - srcFactor = GL_SRC_ALPHA; - dstFactor = GL_ONE_MINUS_SRC_ALPHA; - break; - } +void GLPipeline::getBlendFactors(BlendMode mode, GLenum &srcFactor, + GLenum &dstFactor) { + switch (mode) { + case BlendMode::None: + srcFactor = GL_ONE; + dstFactor = GL_ZERO; + break; + case BlendMode::Alpha: + srcFactor = GL_SRC_ALPHA; + dstFactor = GL_ONE_MINUS_SRC_ALPHA; + break; + case BlendMode::Additive: + srcFactor = GL_SRC_ALPHA; + dstFactor = GL_ONE; + break; + case BlendMode::Multiply: + srcFactor = GL_DST_COLOR; + dstFactor = GL_ONE_MINUS_SRC_ALPHA; + break; + default: + srcFactor = GL_SRC_ALPHA; + dstFactor = GL_ONE_MINUS_SRC_ALPHA; + break; + } } GLenum GLPipeline::convertDepthFunc(DepthFunc func) { - switch (func) { - case DepthFunc::Never: return GL_NEVER; - case DepthFunc::Less: return GL_LESS; - case DepthFunc::Equal: return GL_EQUAL; - case DepthFunc::LessEqual: return GL_LEQUAL; - case DepthFunc::Greater: return GL_GREATER; - case DepthFunc::NotEqual: return GL_NOTEQUAL; - case DepthFunc::GreaterEqual: return GL_GEQUAL; - case DepthFunc::Always: return GL_ALWAYS; - default: return GL_LESS; - } + switch (func) { + case DepthFunc::Never: + return GL_NEVER; + case DepthFunc::Less: + return GL_LESS; + case DepthFunc::Equal: + return GL_EQUAL; + case DepthFunc::LessEqual: + return GL_LEQUAL; + case DepthFunc::Greater: + return GL_GREATER; + case DepthFunc::NotEqual: + return GL_NOTEQUAL; + case DepthFunc::GreaterEqual: + return GL_GEQUAL; + case DepthFunc::Always: + return GL_ALWAYS; + default: + return GL_LESS; + } } GLenum GLPipeline::convertCullMode(CullMode mode) { - switch (mode) { - case CullMode::Front: return GL_FRONT; - case CullMode::Back: return GL_BACK; - case CullMode::Both: return GL_FRONT_AND_BACK; - default: return GL_BACK; - } + switch (mode) { + case CullMode::Front: + return GL_FRONT; + case CullMode::Back: + return GL_BACK; + case CullMode::Both: + return GL_FRONT_AND_BACK; + default: + return GL_BACK; + } } } // namespace extra2d diff --git a/Extra2D/src/graphics/backends/opengl/gl_renderer.cpp b/Extra2D/src/graphics/backends/opengl/gl_renderer.cpp index 7db2540..26a4c19 100644 --- a/Extra2D/src/graphics/backends/opengl/gl_renderer.cpp +++ b/Extra2D/src/graphics/backends/opengl/gl_renderer.cpp @@ -1,6 +1,6 @@ -#include #include #include +#include #include #include #include @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include namespace extra2d { @@ -23,8 +23,8 @@ static constexpr size_t SHAPE_VBO_SIZE = 1024 * sizeof(float); * @brief 构造函数,初始化OpenGL渲染器成员变量 */ GLRenderer::GLRenderer() - : window_(nullptr), shapeVao_(0), lineVao_(0), - vsync_(true), shapeVertexCount_(0), currentShapeMode_(GL_TRIANGLES), + : window_(nullptr), shapeVao_(0), lineVao_(0), vsync_(true), + shapeVertexCount_(0), currentShapeMode_(GL_TRIANGLES), lineVertexCount_(0), currentLineWidth_(1.0f) { resetStats(); for (auto &v : shapeVertexCache_) { @@ -48,7 +48,8 @@ GLRenderer::~GLRenderer() { shutdown(); } bool GLRenderer::init(IWindow *window) { window_ = window; - // 初始化 OpenGL 上下文(Switch 平台已通过 SDL2 + EGL 初始化,GLContext 会处理兼容性) + // 初始化 OpenGL 上下文(Switch 平台已通过 SDL2 + EGL 初始化,GLContext + // 会处理兼容性) if (!GLContext::get().init()) { E2D_LOG_ERROR("Failed to initialize OpenGL context"); return false; @@ -937,7 +938,7 @@ void GLRenderer::flushLineBatch() { * @param desc 帧缓冲描述 * @return 创建的帧缓冲智能指针 */ -Ptr GLRenderer::createFramebuffer(const FramebufferDesc& desc) { +Ptr GLRenderer::createFramebuffer(const FramebufferDesc &desc) { auto framebuffer = makePtr(); if (!framebuffer->init(desc)) { E2D_LOG_ERROR("Failed to create framebuffer"); @@ -950,7 +951,7 @@ Ptr GLRenderer::createFramebuffer(const FramebufferDesc& desc) { * @brief 绑定帧缓冲(作为渲染目标) * @param framebuffer 帧缓冲对象指针,传入 nullptr 则绑定默认帧缓冲 */ -void GLRenderer::bindFramebuffer(GLFramebuffer* framebuffer) { +void GLRenderer::bindFramebuffer(GLFramebuffer *framebuffer) { // 先刷新所有待处理的渲染批次 flush(); flushShapeBatch(); @@ -972,9 +973,7 @@ void GLRenderer::bindFramebuffer(GLFramebuffer* framebuffer) { /** * @brief 解绑帧缓冲(恢复到默认帧缓冲) */ -void GLRenderer::unbindFramebuffer() { - bindFramebuffer(nullptr); -} +void GLRenderer::unbindFramebuffer() { bindFramebuffer(nullptr); } /** * @brief 获取默认帧缓冲 @@ -996,7 +995,7 @@ Ptr GLRenderer::getDefaultFramebuffer() const { * @param clearDepth 是否清除深度缓冲 * @param clearStencil 是否清除模板缓冲 */ -void GLRenderer::clearFramebuffer(const Color& color, bool clearColor, +void GLRenderer::clearFramebuffer(const Color &color, bool clearColor, bool clearDepth, bool clearStencil) { GLbitfield mask = 0; diff --git a/Extra2D/src/graphics/backends/opengl/gl_shader.cpp b/Extra2D/src/graphics/backends/opengl/gl_shader.cpp index 0d04452..1f927db 100644 --- a/Extra2D/src/graphics/backends/opengl/gl_shader.cpp +++ b/Extra2D/src/graphics/backends/opengl/gl_shader.cpp @@ -1,45 +1,42 @@ +#include #include -#include +#include + namespace extra2d { /** * @brief 构造函数,初始化着色器程序ID为0 */ -GLShader::GLShader() : programID_(0) { -} +GLShader::GLShader() : programID_(0) {} /** * @brief 析构函数,删除OpenGL着色器程序 */ GLShader::~GLShader() { - if (programID_ != 0) { - glDeleteProgram(programID_); - programID_ = 0; - } + if (programID_ != 0) { + glDeleteProgram(programID_); + programID_ = 0; + } } /** * @brief 绑定Shader程序 */ -void GLShader::bind() const { - glUseProgram(programID_); -} +void GLShader::bind() const { glUseProgram(programID_); } /** * @brief 解绑Shader程序 */ -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) { - glUniform1i(getUniformLocation(name), value ? 1 : 0); +void GLShader::setBool(const std::string &name, bool value) { + glUniform1i(getUniformLocation(name), value ? 1 : 0); } /** @@ -47,8 +44,8 @@ void GLShader::setBool(const std::string& name, bool value) { * @param name uniform变量名 * @param value 整数值 */ -void GLShader::setInt(const std::string& name, int value) { - glUniform1i(getUniformLocation(name), value); +void GLShader::setInt(const std::string &name, int value) { + glUniform1i(getUniformLocation(name), value); } /** @@ -56,8 +53,8 @@ void GLShader::setInt(const std::string& name, int value) { * @param name uniform变量名 * @param value 浮点值 */ -void GLShader::setFloat(const std::string& name, float value) { - glUniform1f(getUniformLocation(name), value); +void GLShader::setFloat(const std::string &name, float value) { + glUniform1f(getUniformLocation(name), value); } /** @@ -65,8 +62,8 @@ void GLShader::setFloat(const std::string& name, float value) { * @param name uniform变量名 * @param value 二维向量值 */ -void GLShader::setVec2(const std::string& name, const glm::vec2& value) { - glUniform2fv(getUniformLocation(name), 1, &value[0]); +void GLShader::setVec2(const std::string &name, const glm::vec2 &value) { + glUniform2fv(getUniformLocation(name), 1, &value[0]); } /** @@ -74,8 +71,8 @@ void GLShader::setVec2(const std::string& name, const glm::vec2& value) { * @param name uniform变量名 * @param value 三维向量值 */ -void GLShader::setVec3(const std::string& name, const glm::vec3& value) { - glUniform3fv(getUniformLocation(name), 1, &value[0]); +void GLShader::setVec3(const std::string &name, const glm::vec3 &value) { + glUniform3fv(getUniformLocation(name), 1, &value[0]); } /** @@ -83,8 +80,8 @@ void GLShader::setVec3(const std::string& name, const glm::vec3& value) { * @param name uniform变量名 * @param value 四维向量值 */ -void GLShader::setVec4(const std::string& name, const glm::vec4& value) { - glUniform4fv(getUniformLocation(name), 1, &value[0]); +void GLShader::setVec4(const std::string &name, const glm::vec4 &value) { + glUniform4fv(getUniformLocation(name), 1, &value[0]); } /** @@ -92,8 +89,8 @@ void GLShader::setVec4(const std::string& name, const glm::vec4& value) { * @param name uniform变量名 * @param value 4x4矩阵值 */ -void GLShader::setMat4(const std::string& name, const glm::mat4& value) { - glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, &value[0][0]); +void GLShader::setMat4(const std::string &name, const glm::mat4 &value) { + glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, &value[0][0]); } /** @@ -101,8 +98,8 @@ void GLShader::setMat4(const std::string& name, const glm::mat4& value) { * @param name uniform变量名 * @param color 颜色值 */ -void GLShader::setColor(const std::string& name, const Color& color) { - glUniform4f(getUniformLocation(name), color.r, color.g, color.b, color.a); +void GLShader::setColor(const std::string &name, const Color &color) { + glUniform4f(getUniformLocation(name), color.r, color.g, color.b, color.a); } /** @@ -111,42 +108,43 @@ void GLShader::setColor(const std::string& name, const Color& color) { * @param fragmentSource 片段着色器源码 * @return 编译成功返回true,失败返回false */ -bool GLShader::compileFromSource(const char* vertexSource, const char* fragmentSource) { - GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexSource); - if (vertexShader == 0) { - return false; - } - - GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentSource); - if (fragmentShader == 0) { - glDeleteShader(vertexShader); - return false; - } - - if (programID_ != 0) { - glDeleteProgram(programID_); - uniformCache_.clear(); - } - - programID_ = glCreateProgram(); - glAttachShader(programID_, vertexShader); - glAttachShader(programID_, fragmentShader); - glLinkProgram(programID_); - - GLint success; - glGetProgramiv(programID_, GL_LINK_STATUS, &success); - if (!success) { - char infoLog[512]; - glGetProgramInfoLog(programID_, 512, nullptr, infoLog); - E2D_LOG_ERROR("Shader program linking failed: {}", infoLog); - glDeleteProgram(programID_); - programID_ = 0; - } +bool GLShader::compileFromSource(const char *vertexSource, + const char *fragmentSource) { + GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexSource); + if (vertexShader == 0) { + return false; + } + GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentSource); + if (fragmentShader == 0) { glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); + return false; + } - return success == GL_TRUE; + if (programID_ != 0) { + glDeleteProgram(programID_); + uniformCache_.clear(); + } + + programID_ = glCreateProgram(); + glAttachShader(programID_, vertexShader); + glAttachShader(programID_, fragmentShader); + glLinkProgram(programID_); + + GLint success; + glGetProgramiv(programID_, GL_LINK_STATUS, &success); + if (!success) { + char infoLog[512]; + glGetProgramInfoLog(programID_, 512, nullptr, infoLog); + E2D_LOG_ERROR("Shader program linking failed: {}", infoLog); + glDeleteProgram(programID_); + programID_ = 0; + } + + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + + return success == GL_TRUE; } /** @@ -154,43 +152,45 @@ bool GLShader::compileFromSource(const char* vertexSource, const char* fragmentS * @param binary 二进制数据 * @return 创建成功返回true,失败返回false */ -bool GLShader::compileFromBinary(const std::vector& binary) { - if (binary.empty()) { - E2D_LOG_ERROR("Binary data is empty"); - return false; - } +bool GLShader::compileFromBinary(const std::vector &binary) { + if (binary.empty()) { + E2D_LOG_ERROR("Binary data is empty"); + return false; + } - GLint numFormats = 0; - glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numFormats); - if (numFormats == 0) { - E2D_LOG_ERROR("Program binary formats not supported"); - return false; - } + GLint numFormats = 0; + glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numFormats); + if (numFormats == 0) { + E2D_LOG_ERROR("Program binary formats not supported"); + return false; + } - if (programID_ != 0) { - glDeleteProgram(programID_); - uniformCache_.clear(); - } + if (programID_ != 0) { + glDeleteProgram(programID_); + uniformCache_.clear(); + } - programID_ = glCreateProgram(); + programID_ = glCreateProgram(); - GLenum binaryFormat = 0; - glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, reinterpret_cast(&binaryFormat)); + GLenum binaryFormat = 0; + glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, + reinterpret_cast(&binaryFormat)); - glProgramBinary(programID_, binaryFormat, binary.data(), static_cast(binary.size())); + glProgramBinary(programID_, binaryFormat, binary.data(), + static_cast(binary.size())); - GLint success = 0; - glGetProgramiv(programID_, GL_LINK_STATUS, &success); - if (!success) { - char infoLog[512]; - glGetProgramInfoLog(programID_, 512, nullptr, infoLog); - E2D_LOG_ERROR("Failed to load shader from binary: {}", infoLog); - glDeleteProgram(programID_); - programID_ = 0; - return false; - } + GLint success = 0; + glGetProgramiv(programID_, GL_LINK_STATUS, &success); + if (!success) { + char infoLog[512]; + glGetProgramInfoLog(programID_, 512, nullptr, infoLog); + E2D_LOG_ERROR("Failed to load shader from binary: {}", infoLog); + glDeleteProgram(programID_); + programID_ = 0; + return false; + } - return true; + return true; } /** @@ -198,47 +198,49 @@ bool GLShader::compileFromBinary(const std::vector& binary) { * @param outBinary 输出的二进制数据 * @return 成功返回true,失败返回false */ -bool GLShader::getBinary(std::vector& outBinary) { - if (programID_ == 0) { - E2D_LOG_WARN("Cannot get binary: shader program is 0"); - return false; - } +bool GLShader::getBinary(std::vector &outBinary) { + if (programID_ == 0) { + E2D_LOG_WARN("Cannot get binary: shader program is 0"); + return false; + } - GLint binaryLength = 0; - glGetProgramiv(programID_, GL_PROGRAM_BINARY_LENGTH, &binaryLength); - - E2D_LOG_DEBUG("Shader binary length: {}", binaryLength); - - if (binaryLength <= 0) { - E2D_LOG_WARN("Shader binary length is 0 or negative"); - return false; - } + GLint binaryLength = 0; + glGetProgramiv(programID_, GL_PROGRAM_BINARY_LENGTH, &binaryLength); - outBinary.resize(binaryLength); + E2D_LOG_DEBUG("Shader binary length: {}", binaryLength); - GLenum binaryFormat = 0; - GLsizei actualLength = 0; - glGetProgramBinary(programID_, binaryLength, &actualLength, &binaryFormat, outBinary.data()); - - GLenum err = glGetError(); - if (err != GL_NO_ERROR) { - E2D_LOG_ERROR("glGetProgramBinary failed with error: {}", err); - outBinary.clear(); - return false; - } - - if (actualLength == 0) { - E2D_LOG_WARN("glGetProgramBinary returned 0 bytes"); - outBinary.clear(); - return false; - } - - if (actualLength != binaryLength) { - outBinary.resize(actualLength); - } + if (binaryLength <= 0) { + E2D_LOG_WARN("Shader binary length is 0 or negative"); + return false; + } - E2D_LOG_DEBUG("Shader binary retrieved: {} bytes, format: {}", actualLength, binaryFormat); - return true; + outBinary.resize(binaryLength); + + GLenum binaryFormat = 0; + GLsizei actualLength = 0; + glGetProgramBinary(programID_, binaryLength, &actualLength, &binaryFormat, + outBinary.data()); + + GLenum err = glGetError(); + if (err != GL_NO_ERROR) { + E2D_LOG_ERROR("glGetProgramBinary failed with error: {}", err); + outBinary.clear(); + return false; + } + + if (actualLength == 0) { + E2D_LOG_WARN("glGetProgramBinary returned 0 bytes"); + outBinary.clear(); + return false; + } + + if (actualLength != binaryLength) { + outBinary.resize(actualLength); + } + + E2D_LOG_DEBUG("Shader binary retrieved: {} bytes, format: {}", actualLength, + binaryFormat); + return true; } /** @@ -247,22 +249,22 @@ bool GLShader::getBinary(std::vector& outBinary) { * @param source 着色器源码 * @return 着色器ID,失败返回0 */ -GLuint GLShader::compileShader(GLenum type, const char* source) { - GLuint shader = glCreateShader(type); - glShaderSource(shader, 1, &source, nullptr); - glCompileShader(shader); +GLuint GLShader::compileShader(GLenum type, const char *source) { + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &source, nullptr); + glCompileShader(shader); - GLint success; - glGetShaderiv(shader, GL_COMPILE_STATUS, &success); - if (!success) { - char infoLog[512]; - glGetShaderInfoLog(shader, 512, nullptr, infoLog); - E2D_LOG_ERROR("Shader compilation failed: {}", infoLog); - glDeleteShader(shader); - return 0; - } + GLint success; + glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + if (!success) { + char infoLog[512]; + glGetShaderInfoLog(shader, 512, nullptr, infoLog); + E2D_LOG_ERROR("Shader compilation failed: {}", infoLog); + glDeleteShader(shader); + return 0; + } - return shader; + return shader; } /** @@ -270,15 +272,15 @@ GLuint GLShader::compileShader(GLenum type, const char* source) { * @param name uniform变量名 * @return uniform位置 */ -GLint GLShader::getUniformLocation(const std::string& name) { - auto it = uniformCache_.find(name); - if (it != uniformCache_.end()) { - return it->second; - } +GLint GLShader::getUniformLocation(const std::string &name) { + auto it = uniformCache_.find(name); + if (it != uniformCache_.end()) { + return it->second; + } - GLint location = glGetUniformLocation(programID_, name.c_str()); - uniformCache_[name] = location; - return location; + GLint location = glGetUniformLocation(programID_, name.c_str()); + uniformCache_[name] = location; + return location; } // ============================================================================ @@ -292,20 +294,19 @@ GLint GLShader::getUniformLocation(const std::string& name) { * @param fragSource 片段着色器源码 * @return 创建的Shader实例 */ -Ptr GLShaderFactory::createFromSource( - const std::string& name, - const std::string& vertSource, - const std::string& fragSource) { - - auto shader = std::make_shared(); - shader->setName(name); - - if (!shader->compileFromSource(vertSource.c_str(), fragSource.c_str())) { - E2D_LOG_ERROR("Failed to compile shader from source: {}", name); - return nullptr; - } +Ptr GLShaderFactory::createFromSource(const std::string &name, + const std::string &vertSource, + const std::string &fragSource) { - return shader; + auto shader = std::make_shared(); + shader->setName(name); + + if (!shader->compileFromSource(vertSource.c_str(), fragSource.c_str())) { + E2D_LOG_ERROR("Failed to compile shader from source: {}", name); + return nullptr; + } + + return shader; } /** @@ -314,19 +315,19 @@ Ptr GLShaderFactory::createFromSource( * @param binary 编译后的二进制数据 * @return 创建的Shader实例 */ -Ptr GLShaderFactory::createFromBinary( - const std::string& name, - const std::vector& binary) { - - auto shader = std::make_shared(); - shader->setName(name); - - if (!shader->compileFromBinary(binary)) { - E2D_LOG_ERROR("Failed to create shader from binary: {}", name); - return nullptr; - } +Ptr +GLShaderFactory::createFromBinary(const std::string &name, + const std::vector &binary) { - return shader; + auto shader = std::make_shared(); + shader->setName(name); + + if (!shader->compileFromBinary(binary)) { + E2D_LOG_ERROR("Failed to create shader from binary: {}", name); + return nullptr; + } + + return shader; } /** @@ -335,14 +336,15 @@ Ptr GLShaderFactory::createFromBinary( * @param outBinary 输出的二进制数据 * @return 成功返回true,失败返回false */ -bool GLShaderFactory::getShaderBinary(const IShader& shader, std::vector& outBinary) { - const GLShader* glShader = dynamic_cast(&shader); - if (!glShader) { - E2D_LOG_ERROR("Shader is not a GLShader instance"); - return false; - } +bool GLShaderFactory::getShaderBinary(const IShader &shader, + std::vector &outBinary) { + const GLShader *glShader = dynamic_cast(&shader); + if (!glShader) { + E2D_LOG_ERROR("Shader is not a GLShader instance"); + return false; + } - return const_cast(glShader)->getBinary(outBinary); + return const_cast(glShader)->getBinary(outBinary); } } // namespace extra2d diff --git a/Extra2D/src/graphics/backends/opengl/gl_sprite_batch.cpp b/Extra2D/src/graphics/backends/opengl/gl_sprite_batch.cpp index 14dc4f3..43134b5 100644 --- a/Extra2D/src/graphics/backends/opengl/gl_sprite_batch.cpp +++ b/Extra2D/src/graphics/backends/opengl/gl_sprite_batch.cpp @@ -1,7 +1,9 @@ +#include #include #include #include -#include +#include + namespace extra2d { @@ -36,16 +38,19 @@ bool GLSpriteBatch::init() { // 设置顶点属性 glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(SpriteVertex), - reinterpret_cast(offsetof(SpriteVertex, position))); + glVertexAttribPointer( + 0, 2, GL_FLOAT, GL_FALSE, sizeof(SpriteVertex), + reinterpret_cast(offsetof(SpriteVertex, position))); glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(SpriteVertex), - reinterpret_cast(offsetof(SpriteVertex, texCoord))); + glVertexAttribPointer( + 1, 2, GL_FLOAT, GL_FALSE, sizeof(SpriteVertex), + reinterpret_cast(offsetof(SpriteVertex, texCoord))); glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(SpriteVertex), - reinterpret_cast(offsetof(SpriteVertex, color))); + glVertexAttribPointer( + 2, 4, GL_FLOAT, GL_FALSE, sizeof(SpriteVertex), + reinterpret_cast(offsetof(SpriteVertex, color))); // 初始化 EBO(索引缓冲区)- 静态使用模式 BufferDesc eboDesc; @@ -172,12 +177,12 @@ void GLSpriteBatch::submitBatch() { // 通过传入 nullptr 进行 orphaning,告诉驱动器可以丢弃旧缓冲区并分配新内存 // 这样可以避免 GPU 等待,提高性能 size_t vertexDataSize = batch_.getVertices().size() * sizeof(SpriteVertex); - vbo_.setData(nullptr, vertexDataSize); // orphaning + vbo_.setData(nullptr, vertexDataSize); // orphaning vbo_.updateData(batch_.getVertices().data(), 0, vertexDataSize); // 绘制 currentTexture_->bind(0); - + size_t indexCount = batch_.getSpriteCount() * 6; glDrawElements(GL_TRIANGLES, static_cast(indexCount), GL_UNSIGNED_SHORT, nullptr); diff --git a/Extra2D/src/graphics/backends/opengl/gl_texture.cpp b/Extra2D/src/graphics/backends/opengl/gl_texture.cpp index b88aa31..308ccd3 100644 --- a/Extra2D/src/graphics/backends/opengl/gl_texture.cpp +++ b/Extra2D/src/graphics/backends/opengl/gl_texture.cpp @@ -3,10 +3,12 @@ #include #define STB_IMAGE_IMPLEMENTATION #include -#include +#include +#include #include #include + namespace extra2d { // ============================================================================ diff --git a/Extra2D/src/graphics/backends/vulkan/vk_renderer.cpp b/Extra2D/src/graphics/backends/vulkan/vk_renderer.cpp index fc09612..39c090a 100644 --- a/Extra2D/src/graphics/backends/vulkan/vk_renderer.cpp +++ b/Extra2D/src/graphics/backends/vulkan/vk_renderer.cpp @@ -1,150 +1,150 @@ +#include #include -#include +#include + namespace extra2d { VulkanRenderer::VulkanRenderer() = default; -VulkanRenderer::~VulkanRenderer() { - shutdown(); +VulkanRenderer::~VulkanRenderer() { shutdown(); } + +bool VulkanRenderer::init(IWindow *window) { + E2D_LOG_WARN("Vulkan renderer is not fully implemented yet"); + initialized_ = true; + return true; } -bool VulkanRenderer::init(IWindow* window) { - E2D_LOG_WARN("Vulkan renderer is not fully implemented yet"); - initialized_ = true; - return true; -} - -void VulkanRenderer::shutdown() { - initialized_ = false; -} +void VulkanRenderer::shutdown() { initialized_ = false; } void VulkanRenderer::beginFrame(const Color &clearColor) { - // TODO: 实现Vulkan帧开始 + // TODO: 实现Vulkan帧开始 } void VulkanRenderer::endFrame() { - // TODO: 实现Vulkan帧结束 + // TODO: 实现Vulkan帧结束 } void VulkanRenderer::setViewport(int x, int y, int width, int height) { - // TODO: 实现视口设置 + // TODO: 实现视口设置 } void VulkanRenderer::setVSync(bool enabled) { - // TODO: 实现垂直同步设置 + // TODO: 实现垂直同步设置 } void VulkanRenderer::setBlendMode(BlendMode mode) { - // TODO: 实现混合模式设置 + // TODO: 实现混合模式设置 } void VulkanRenderer::setViewProjection(const glm::mat4 &matrix) { - // TODO: 实现视图投影矩阵设置 + // TODO: 实现视图投影矩阵设置 } void VulkanRenderer::pushTransform(const glm::mat4 &transform) { - // TODO: 实现变换矩阵入栈 + // TODO: 实现变换矩阵入栈 } void VulkanRenderer::popTransform() { - // TODO: 实现变换矩阵出栈 + // TODO: 实现变换矩阵出栈 } glm::mat4 VulkanRenderer::getCurrentTransform() const { - return glm::mat4(1.0f); + return glm::mat4(1.0f); } -Ptr VulkanRenderer::createTexture(int width, int height, const uint8_t *pixels, int channels) { - // TODO: 实现Vulkan纹理创建 - return nullptr; +Ptr VulkanRenderer::createTexture(int width, int height, + const uint8_t *pixels, + int channels) { + // TODO: 实现Vulkan纹理创建 + return nullptr; } Ptr VulkanRenderer::loadTexture(const std::string &filepath) { - // TODO: 实现Vulkan纹理加载 - return nullptr; + // TODO: 实现Vulkan纹理加载 + return nullptr; } void VulkanRenderer::beginSpriteBatch() { - // TODO: 实现精灵批处理开始 + // TODO: 实现精灵批处理开始 } void VulkanRenderer::drawSprite(const Texture &texture, const Rect &destRect, - const Rect &srcRect, const Color &tint, float rotation, - const Vec2 &anchor) { - // TODO: 实现精灵绘制 + const Rect &srcRect, const Color &tint, + float rotation, const Vec2 &anchor) { + // TODO: 实现精灵绘制 } void VulkanRenderer::drawSprite(const Texture &texture, const Vec2 &position, - const Color &tint) { - // TODO: 实现简化精灵绘制 + const Color &tint) { + // TODO: 实现简化精灵绘制 } void VulkanRenderer::endSpriteBatch() { - // TODO: 实现精灵批处理结束 + // TODO: 实现精灵批处理结束 } -void VulkanRenderer::drawLine(const Vec2 &start, const Vec2 &end, const Color &color, - float width) { - // TODO: 实现线条绘制 +void VulkanRenderer::drawLine(const Vec2 &start, const Vec2 &end, + const Color &color, float width) { + // TODO: 实现线条绘制 } -void VulkanRenderer::drawRect(const Rect &rect, const Color &color, float width) { - // TODO: 实现矩形边框绘制 +void VulkanRenderer::drawRect(const Rect &rect, const Color &color, + float width) { + // TODO: 实现矩形边框绘制 } void VulkanRenderer::fillRect(const Rect &rect, const Color &color) { - // TODO: 实现矩形填充 + // TODO: 实现矩形填充 } -void VulkanRenderer::drawCircle(const Vec2 ¢er, float radius, const Color &color, - int segments, float width) { - // TODO: 实现圆形边框绘制 +void VulkanRenderer::drawCircle(const Vec2 ¢er, float radius, + const Color &color, int segments, float width) { + // TODO: 实现圆形边框绘制 } -void VulkanRenderer::fillCircle(const Vec2 ¢er, float radius, const Color &color, - int segments) { - // TODO: 实现圆形填充 +void VulkanRenderer::fillCircle(const Vec2 ¢er, float radius, + const Color &color, int segments) { + // TODO: 实现圆形填充 } -void VulkanRenderer::drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3, - const Color &color, float width) { - // TODO: 实现三角形边框绘制 +void VulkanRenderer::drawTriangle(const Vec2 &p1, const Vec2 &p2, + const Vec2 &p3, const Color &color, + float width) { + // TODO: 实现三角形边框绘制 } -void VulkanRenderer::fillTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3, - const Color &color) { - // TODO: 实现三角形填充 +void VulkanRenderer::fillTriangle(const Vec2 &p1, const Vec2 &p2, + const Vec2 &p3, const Color &color) { + // TODO: 实现三角形填充 } -void VulkanRenderer::drawPolygon(const std::vector &points, const Color &color, - float width) { - // TODO: 实现多边形边框绘制 +void VulkanRenderer::drawPolygon(const std::vector &points, + const Color &color, float width) { + // TODO: 实现多边形边框绘制 } void VulkanRenderer::fillPolygon(const std::vector &points, - const Color &color) { - // TODO: 实现多边形填充 + const Color &color) { + // TODO: 实现多边形填充 } -Ptr VulkanRenderer::createFontAtlas(const std::string &filepath, int fontSize, - bool useSDF) { - // TODO: 实现字体图集创建 - return nullptr; +Ptr VulkanRenderer::createFontAtlas(const std::string &filepath, + int fontSize, bool useSDF) { + // TODO: 实现字体图集创建 + return nullptr; } void VulkanRenderer::drawText(const FontAtlas &font, const std::string &text, - const Vec2 &position, const Color &color) { - // TODO: 实现文本绘制 + const Vec2 &position, const Color &color) { + // TODO: 实现文本绘制 } -void VulkanRenderer::drawText(const FontAtlas &font, const std::string &text, float x, - float y, const Color &color) { - // TODO: 实现文本绘制 +void VulkanRenderer::drawText(const FontAtlas &font, const std::string &text, + float x, float y, const Color &color) { + // TODO: 实现文本绘制 } -void VulkanRenderer::resetStats() { - stats_ = Stats{}; -} +void VulkanRenderer::resetStats() { stats_ = Stats{}; } } // namespace extra2d diff --git a/Extra2D/src/graphics/batch/sprite_batch.cpp b/Extra2D/src/graphics/batch/sprite_batch.cpp index 45189ba..ee3c667 100644 --- a/Extra2D/src/graphics/batch/sprite_batch.cpp +++ b/Extra2D/src/graphics/batch/sprite_batch.cpp @@ -1,5 +1,7 @@ +#include #include -#include +#include + #include #include @@ -10,196 +12,195 @@ namespace extra2d { // TrigLookup 实现 - 三角函数查表 // ============================================================================ TrigLookup::TrigLookup() { - constexpr float PI = 3.14159265359f; - constexpr float DEG2RAD = PI / 180.0f; - - for (int i = 0; i < TABLE_SIZE; ++i) { - float angle = static_cast(i) * (360.0f / TABLE_SIZE) * DEG2RAD; - sinTable_[i] = std::sin(angle); - cosTable_[i] = std::cos(angle); - } + constexpr float PI = 3.14159265359f; + constexpr float DEG2RAD = PI / 180.0f; + + for (int i = 0; i < TABLE_SIZE; ++i) { + float angle = static_cast(i) * (360.0f / TABLE_SIZE) * DEG2RAD; + sinTable_[i] = std::sin(angle); + cosTable_[i] = std::cos(angle); + } } float TrigLookup::sin(int angle) const { - // 规范化角度到 0-360 - angle = ((angle % 360) + 360) % 360; - return sinTable_[angle * 4]; + // 规范化角度到 0-360 + angle = ((angle % 360) + 360) % 360; + return sinTable_[angle * 4]; } float TrigLookup::cos(int angle) const { - // 规范化角度到 0-360 - angle = ((angle % 360) + 360) % 360; - return cosTable_[angle * 4]; + // 规范化角度到 0-360 + angle = ((angle % 360) + 360) % 360; + return cosTable_[angle * 4]; } float TrigLookup::sinRad(float rad) const { - constexpr float RAD2DEG = 180.0f / 3.14159265359f; - int angle = static_cast(rad * RAD2DEG); - return sin(angle); + constexpr float RAD2DEG = 180.0f / 3.14159265359f; + int angle = static_cast(rad * RAD2DEG); + return sin(angle); } float TrigLookup::cosRad(float rad) const { - constexpr float RAD2DEG = 180.0f / 3.14159265359f; - int angle = static_cast(rad * RAD2DEG); - return cos(angle); + constexpr float RAD2DEG = 180.0f / 3.14159265359f; + int angle = static_cast(rad * RAD2DEG); + return cos(angle); } // ============================================================================ // SpriteBatch 实现 // ============================================================================ -SpriteBatch::SpriteBatch() - : spriteCount_(0) - , vpDirty_(true) { - // 预分配顶点缓冲区 - vertices_.reserve(MAX_VERTICES); - indices_.reserve(MAX_INDICES); - - // 生成静态索引缓冲区 - generateIndices(); +SpriteBatch::SpriteBatch() : spriteCount_(0), vpDirty_(true) { + // 预分配顶点缓冲区 + vertices_.reserve(MAX_VERTICES); + indices_.reserve(MAX_INDICES); + + // 生成静态索引缓冲区 + generateIndices(); } void SpriteBatch::generateIndices() { - indices_.clear(); - for (size_t i = 0; i < MAX_SPRITES; ++i) { - uint16_t base = static_cast(i * 4); - // 两个三角形: (0,1,2) 和 (0,2,3) - indices_.push_back(base + 0); - indices_.push_back(base + 1); - indices_.push_back(base + 2); - indices_.push_back(base + 0); - indices_.push_back(base + 2); - indices_.push_back(base + 3); - } + indices_.clear(); + for (size_t i = 0; i < MAX_SPRITES; ++i) { + uint16_t base = static_cast(i * 4); + // 两个三角形: (0,1,2) 和 (0,2,3) + indices_.push_back(base + 0); + indices_.push_back(base + 1); + indices_.push_back(base + 2); + indices_.push_back(base + 0); + indices_.push_back(base + 2); + indices_.push_back(base + 3); + } } -void SpriteBatch::begin(const glm::mat4& viewProjection) { - viewProjection_ = viewProjection; - vpDirty_ = true; - spriteCount_ = 0; - vertices_.clear(); +void SpriteBatch::begin(const glm::mat4 &viewProjection) { + viewProjection_ = viewProjection; + vpDirty_ = true; + spriteCount_ = 0; + vertices_.clear(); } void SpriteBatch::end() { - // 批次结束,数据已准备好供后端使用 + // 批次结束,数据已准备好供后端使用 } -void SpriteBatch::draw(const SpriteData& sprite) { - if (spriteCount_ >= MAX_SPRITES) { - // 缓冲区已满,需要刷新 - flush(); +void SpriteBatch::draw(const SpriteData &sprite) { + if (spriteCount_ >= MAX_SPRITES) { + // 缓冲区已满,需要刷新 + flush(); + } + + generateVertices(sprite, spriteCount_ * VERTICES_PER_SPRITE); + spriteCount_++; +} + +void SpriteBatch::drawBatch(const std::vector &sprites) { + size_t index = 0; + while (index < sprites.size()) { + // 计算剩余空间 + size_t remainingSpace = MAX_SPRITES - spriteCount_; + size_t batchSize = std::min(remainingSpace, sprites.size() - index); + + // 批量生成顶点 + for (size_t i = 0; i < batchSize; ++i) { + generateVertices(sprites[index + i], spriteCount_ * VERTICES_PER_SPRITE); + spriteCount_++; } - - generateVertices(sprite, spriteCount_ * VERTICES_PER_SPRITE); - spriteCount_++; -} -void SpriteBatch::drawBatch(const std::vector& sprites) { - size_t index = 0; - while (index < sprites.size()) { - // 计算剩余空间 - size_t remainingSpace = MAX_SPRITES - spriteCount_; - size_t batchSize = std::min(remainingSpace, sprites.size() - index); - - // 批量生成顶点 - for (size_t i = 0; i < batchSize; ++i) { - generateVertices(sprites[index + i], spriteCount_ * VERTICES_PER_SPRITE); - spriteCount_++; - } - - index += batchSize; - - // 如果缓冲区已满,需要刷新(由后端处理) - if (spriteCount_ >= MAX_SPRITES && index < sprites.size()) { - // 通知后端刷新,然后继续 - // 注意:这里只是准备数据,实际 GPU 提交由后端决定 - break; - } + index += batchSize; + + // 如果缓冲区已满,需要刷新(由后端处理) + if (spriteCount_ >= MAX_SPRITES && index < sprites.size()) { + // 通知后端刷新,然后继续 + // 注意:这里只是准备数据,实际 GPU 提交由后端决定 + break; } + } } -void SpriteBatch::drawImmediate(const SpriteData& sprite) { - // 立即绘制模式:清空当前批次,只绘制这一个精灵 - clear(); - draw(sprite); +void SpriteBatch::drawImmediate(const SpriteData &sprite) { + // 立即绘制模式:清空当前批次,只绘制这一个精灵 + clear(); + draw(sprite); } -void SpriteBatch::generateVertices(const SpriteData& sprite, size_t vertexOffset) { - // 确保顶点缓冲区足够 - if (vertices_.size() < vertexOffset + VERTICES_PER_SPRITE) { - vertices_.resize(vertexOffset + VERTICES_PER_SPRITE); - } - - // 计算旋转(使用查表) - float c = 1.0f; - float s = 0.0f; +void SpriteBatch::generateVertices(const SpriteData &sprite, + size_t vertexOffset) { + // 确保顶点缓冲区足够 + if (vertices_.size() < vertexOffset + VERTICES_PER_SPRITE) { + vertices_.resize(vertexOffset + VERTICES_PER_SPRITE); + } + + // 计算旋转(使用查表) + float c = 1.0f; + float s = 0.0f; + if (sprite.rotation != 0.0f) { + c = trigLookup_.cosRad(sprite.rotation); + s = trigLookup_.sinRad(sprite.rotation); + } + + // 计算精灵的四个角(相对于中心点) + float halfWidth = sprite.size.x * 0.5f; + float halfHeight = sprite.size.y * 0.5f; + + // 考虑 pivot 偏移 + float pivotOffsetX = (sprite.pivot.x - 0.5f) * sprite.size.x; + float pivotOffsetY = (sprite.pivot.y - 0.5f) * sprite.size.y; + + // 四个角的本地坐标 + Vec2 localCorners[4] = { + Vec2(-halfWidth - pivotOffsetX, -halfHeight - pivotOffsetY), // 左下 + Vec2(halfWidth - pivotOffsetX, -halfHeight - pivotOffsetY), // 右下 + Vec2(halfWidth - pivotOffsetX, halfHeight - pivotOffsetY), // 右上 + Vec2(-halfWidth - pivotOffsetX, halfHeight - pivotOffsetY) // 左上 + }; + + // 应用旋转和平移 + Vec2 worldPos = sprite.position; + + for (int i = 0; i < 4; ++i) { + Vec2 rotated; if (sprite.rotation != 0.0f) { - c = trigLookup_.cosRad(sprite.rotation); - s = trigLookup_.sinRad(sprite.rotation); - } - - // 计算精灵的四个角(相对于中心点) - float halfWidth = sprite.size.x * 0.5f; - float halfHeight = sprite.size.y * 0.5f; - - // 考虑 pivot 偏移 - float pivotOffsetX = (sprite.pivot.x - 0.5f) * sprite.size.x; - float pivotOffsetY = (sprite.pivot.y - 0.5f) * sprite.size.y; - - // 四个角的本地坐标 - Vec2 localCorners[4] = { - Vec2(-halfWidth - pivotOffsetX, -halfHeight - pivotOffsetY), // 左下 - Vec2( halfWidth - pivotOffsetX, -halfHeight - pivotOffsetY), // 右下 - Vec2( halfWidth - pivotOffsetX, halfHeight - pivotOffsetY), // 右上 - Vec2(-halfWidth - pivotOffsetX, halfHeight - pivotOffsetY) // 左上 - }; - - // 应用旋转和平移 - Vec2 worldPos = sprite.position; - - for (int i = 0; i < 4; ++i) { - Vec2 rotated; - if (sprite.rotation != 0.0f) { - rotated.x = localCorners[i].x * c - localCorners[i].y * s; - rotated.y = localCorners[i].x * s + localCorners[i].y * c; - } else { - rotated = localCorners[i]; - } - - vertices_[vertexOffset + i].position = worldPos + rotated; - } - - // 设置纹理坐标 - // uvRect.origin = (u0, v0) - 左下 - // uvRect.size = (width, height) - 从左上到右下的尺寸 - float u0 = sprite.uvRect.origin.x; - float v0 = sprite.uvRect.origin.y; - float u1 = u0 + sprite.uvRect.size.width; - float v1 = v0 + sprite.uvRect.size.height; - - // 顶点顺序: 左下, 右下, 右上, 左上 - // 注意: 在 gl_font_atlas 中 v0 > v1 (因为翻转了V坐标) - // 所以 v0 对应底部,v1 对应顶部 - vertices_[vertexOffset + 0].texCoord = Vec2(u0, v0); // 左下 - vertices_[vertexOffset + 1].texCoord = Vec2(u1, v0); // 右下 - vertices_[vertexOffset + 2].texCoord = Vec2(u1, v1); // 右上 - vertices_[vertexOffset + 3].texCoord = Vec2(u0, v1); // 左上 - - // 设置颜色 - for (int i = 0; i < 4; ++i) { - vertices_[vertexOffset + i].color = sprite.color; + rotated.x = localCorners[i].x * c - localCorners[i].y * s; + rotated.y = localCorners[i].x * s + localCorners[i].y * c; + } else { + rotated = localCorners[i]; } + + vertices_[vertexOffset + i].position = worldPos + rotated; + } + + // 设置纹理坐标 + // uvRect.origin = (u0, v0) - 左下 + // uvRect.size = (width, height) - 从左上到右下的尺寸 + float u0 = sprite.uvRect.origin.x; + float v0 = sprite.uvRect.origin.y; + float u1 = u0 + sprite.uvRect.size.width; + float v1 = v0 + sprite.uvRect.size.height; + + // 顶点顺序: 左下, 右下, 右上, 左上 + // 注意: 在 gl_font_atlas 中 v0 > v1 (因为翻转了V坐标) + // 所以 v0 对应底部,v1 对应顶部 + vertices_[vertexOffset + 0].texCoord = Vec2(u0, v0); // 左下 + vertices_[vertexOffset + 1].texCoord = Vec2(u1, v0); // 右下 + vertices_[vertexOffset + 2].texCoord = Vec2(u1, v1); // 右上 + vertices_[vertexOffset + 3].texCoord = Vec2(u0, v1); // 左上 + + // 设置颜色 + for (int i = 0; i < 4; ++i) { + vertices_[vertexOffset + i].color = sprite.color; + } } void SpriteBatch::flush() { - // 标记需要刷新 - 实际刷新由后端处理 - // 这里只是重置计数器,让后端知道需要提交当前批次 - spriteCount_ = 0; - vertices_.clear(); + // 标记需要刷新 - 实际刷新由后端处理 + // 这里只是重置计数器,让后端知道需要提交当前批次 + spriteCount_ = 0; + vertices_.clear(); } void SpriteBatch::clear() { - spriteCount_ = 0; - vertices_.clear(); + spriteCount_ = 0; + vertices_.clear(); } } // namespace extra2d diff --git a/Extra2D/src/graphics/core/render_module.cpp b/Extra2D/src/graphics/core/render_module.cpp index 3b43d68..c75b6e0 100644 --- a/Extra2D/src/graphics/core/render_module.cpp +++ b/Extra2D/src/graphics/core/render_module.cpp @@ -1,12 +1,12 @@ -#include -#include -#include -#include +#include #include #include -#include +#include +#include +#include +#include #include -#include +#include #include namespace extra2d { @@ -19,91 +19,97 @@ void initOpenGLBackend(); #ifdef E2D_BACKEND_VULKAN void initVulkanBackend(); #endif -} +} // namespace graphics -RenderModule::RenderModule(std::function configFn) { - configFn(cfg_); +RenderModule::RenderModule(std::function configFn) { + configFn(cfg_); } RenderModule::~RenderModule() { - if (initialized_) { - shutdown(); - } + if (initialized_) { + shutdown(); + } } static std::string getExecutableDir() { - try { - auto currentPath = std::filesystem::current_path(); - return currentPath.string() + "/"; - } catch (...) { - return "./"; - } + try { + auto currentPath = std::filesystem::current_path(); + return currentPath.string() + "/"; + } catch (...) { + return "./"; + } } bool RenderModule::init() { - if (initialized_) return true; - - auto* winMod = Registry::instance().get(); - if (!winMod || !winMod->win()) { - E2D_LOG_ERROR("WindowModule not available"); - return false; - } - - // 初始化图形后端(注册到工厂) + if (initialized_) + return true; + + auto *winMod = Registry::instance().get(); + if (!winMod || !winMod->win()) { + E2D_LOG_ERROR("WindowModule not available"); + return false; + } + + // 初始化图形后端(注册到工厂) #ifdef E2D_BACKEND_OPENGL - graphics::initOpenGLBackend(); + graphics::initOpenGLBackend(); #endif #ifdef E2D_BACKEND_VULKAN - graphics::initVulkanBackend(); + graphics::initVulkanBackend(); #endif - - if (!ShaderManager::getInstance().isInitialized()) { - auto factory = makeShared(); - std::string shaderDir = getExecutableDir() + "shaders/"; - std::string cacheDir = getExecutableDir() + "shader_cache/"; - if (!ShaderManager::getInstance().init(shaderDir, cacheDir, factory)) { - E2D_LOG_WARN("Failed to initialize ShaderManager with dir: {}", shaderDir); - } + + if (!ShaderManager::getInstance().isInitialized()) { + auto factory = makeShared(); + std::string shaderDir = getExecutableDir() + "shaders/"; + std::string cacheDir = getExecutableDir() + "shader_cache/"; + if (!ShaderManager::getInstance().init(shaderDir, cacheDir, factory)) { + E2D_LOG_WARN("Failed to initialize ShaderManager with dir: {}", + shaderDir); } - - std::string windowBackend = winMod->getWindowBackend(); - - if (cfg_.backend.empty()) { - E2D_LOG_INFO("No graphics backend specified, auto-selecting for window backend: {}", windowBackend); - renderer_ = graphics::BackendFactory::createBackendForWindow(windowBackend); - } else { - if (!graphics::BackendFactory::isCompatible(cfg_.backend, windowBackend)) { - E2D_LOG_WARN("Graphics backend '{}' is not compatible with window backend '{}'", - cfg_.backend, windowBackend); - } - renderer_ = graphics::BackendFactory::createBackend(cfg_.backend); + } + + std::string windowBackend = winMod->getWindowBackend(); + + if (cfg_.backend.empty()) { + E2D_LOG_INFO( + "No graphics backend specified, auto-selecting for window backend: {}", + windowBackend); + renderer_ = graphics::BackendFactory::createBackendForWindow(windowBackend); + } else { + if (!graphics::BackendFactory::isCompatible(cfg_.backend, windowBackend)) { + E2D_LOG_WARN( + "Graphics backend '{}' is not compatible with window backend '{}'", + cfg_.backend, windowBackend); } - - if (!renderer_) { - E2D_LOG_ERROR("Failed to create render backend"); - return false; - } - - if (!renderer_->init(winMod->win())) { - E2D_LOG_ERROR("Failed to initialize render backend"); - renderer_.reset(); - return false; - } - - E2D_LOG_INFO("Render module initialized successfully"); - initialized_ = true; - return true; + renderer_ = graphics::BackendFactory::createBackend(cfg_.backend); + } + + if (!renderer_) { + E2D_LOG_ERROR("Failed to create render backend"); + return false; + } + + if (!renderer_->init(winMod->win())) { + E2D_LOG_ERROR("Failed to initialize render backend"); + renderer_.reset(); + return false; + } + + E2D_LOG_INFO("Render module initialized successfully"); + initialized_ = true; + return true; } void RenderModule::shutdown() { - if (!initialized_) return; - - if (renderer_) { - renderer_->shutdown(); - renderer_.reset(); - } - - initialized_ = false; + if (!initialized_) + return; + + if (renderer_) { + renderer_->shutdown(); + renderer_.reset(); + } + + initialized_ = false; } } // namespace extra2d diff --git a/Extra2D/src/graphics/core/render_target.cpp b/Extra2D/src/graphics/core/render_target.cpp index bb6adff..d7abeaf 100644 --- a/Extra2D/src/graphics/core/render_target.cpp +++ b/Extra2D/src/graphics/core/render_target.cpp @@ -1,7 +1,9 @@ -#include +#include #include #include -#include +#include +#include + #define STB_IMAGE_WRITE_IMPLEMENTATION #include diff --git a/Extra2D/src/graphics/memory/vram_manager.cpp b/Extra2D/src/graphics/memory/vram_manager.cpp index b8e11e4..f4f7c11 100644 --- a/Extra2D/src/graphics/memory/vram_manager.cpp +++ b/Extra2D/src/graphics/memory/vram_manager.cpp @@ -1,6 +1,8 @@ #include +#include #include -#include +#include + namespace extra2d { diff --git a/Extra2D/src/graphics/shader/shader_cache.cpp b/Extra2D/src/graphics/shader/shader_cache.cpp index ca2a044..498a384 100644 --- a/Extra2D/src/graphics/shader/shader_cache.cpp +++ b/Extra2D/src/graphics/shader/shader_cache.cpp @@ -1,10 +1,12 @@ -#include -#include #include +#include +#include +#include #include #include #include + namespace extra2d { namespace fs = std::filesystem; @@ -13,9 +15,9 @@ namespace fs = std::filesystem; * @brief 获取单例实例 * @return 缓存管理器实例引用 */ -ShaderCache& ShaderCache::getInstance() { - static ShaderCache instance; - return instance; +ShaderCache &ShaderCache::getInstance() { + static ShaderCache instance; + return instance; } /** @@ -23,35 +25,35 @@ ShaderCache& ShaderCache::getInstance() { * @param cacheDir 缓存目录路径 * @return 初始化成功返回true,失败返回false */ -bool ShaderCache::init(const std::string& cacheDir) { - cacheDir_ = cacheDir; +bool ShaderCache::init(const std::string &cacheDir) { + cacheDir_ = cacheDir; - if (!ensureCacheDirectory()) { - E2D_LOG_ERROR("Failed to create cache directory: {}", cacheDir); - return false; - } + if (!ensureCacheDirectory()) { + E2D_LOG_ERROR("Failed to create cache directory: {}", cacheDir); + return false; + } - if (!loadCacheIndex()) { - E2D_LOG_WARN("Failed to load cache index, starting fresh"); - } + if (!loadCacheIndex()) { + E2D_LOG_WARN("Failed to load cache index, starting fresh"); + } - initialized_ = true; - E2D_LOG_INFO("Shader cache initialized at: {}", cacheDir); - return true; + initialized_ = true; + E2D_LOG_INFO("Shader cache initialized at: {}", cacheDir); + return true; } /** * @brief 关闭缓存系统 */ void ShaderCache::shutdown() { - if (!initialized_) { - return; - } + if (!initialized_) { + return; + } - saveCacheIndex(); - cacheMap_.clear(); - initialized_ = false; - E2D_LOG_INFO("Shader cache shutdown"); + saveCacheIndex(); + cacheMap_.clear(); + initialized_ = false; + E2D_LOG_INFO("Shader cache shutdown"); } /** @@ -60,13 +62,14 @@ void ShaderCache::shutdown() { * @param sourceHash 源码哈希值 * @return 缓存有效返回true,否则返回false */ -bool ShaderCache::hasValidCache(const std::string& name, const std::string& sourceHash) { - auto it = cacheMap_.find(name); - if (it == cacheMap_.end()) { - return false; - } +bool ShaderCache::hasValidCache(const std::string &name, + const std::string &sourceHash) { + auto it = cacheMap_.find(name); + if (it == cacheMap_.end()) { + return false; + } - return it->second.sourceHash == sourceHash; + return it->second.sourceHash == sourceHash; } /** @@ -74,30 +77,30 @@ bool ShaderCache::hasValidCache(const std::string& name, const std::string& sour * @param name Shader名称 * @return 缓存条目指针,不存在返回nullptr */ -Ptr ShaderCache::loadCache(const std::string& name) { - auto it = cacheMap_.find(name); - if (it == cacheMap_.end()) { - return nullptr; - } +Ptr ShaderCache::loadCache(const std::string &name) { + auto it = cacheMap_.find(name); + if (it == cacheMap_.end()) { + return nullptr; + } - std::string cachePath = getCachePath(name); - std::ifstream file(cachePath, std::ios::binary); - if (!file.is_open()) { - E2D_LOG_WARN("Failed to open cache file: {}", cachePath); - return nullptr; - } + std::string cachePath = getCachePath(name); + std::ifstream file(cachePath, std::ios::binary); + if (!file.is_open()) { + E2D_LOG_WARN("Failed to open cache file: {}", cachePath); + return nullptr; + } - auto entry = std::make_shared(it->second); - entry->binary.clear(); + auto entry = std::make_shared(it->second); + entry->binary.clear(); - file.seekg(0, std::ios::end); - size_t fileSize = static_cast(file.tellg()); - file.seekg(0, std::ios::beg); + file.seekg(0, std::ios::end); + size_t fileSize = static_cast(file.tellg()); + file.seekg(0, std::ios::beg); - entry->binary.resize(fileSize); - file.read(reinterpret_cast(entry->binary.data()), fileSize); + entry->binary.resize(fileSize); + file.read(reinterpret_cast(entry->binary.data()), fileSize); - return entry; + return entry; } /** @@ -105,68 +108,72 @@ Ptr ShaderCache::loadCache(const std::string& name) { * @param entry 缓存条目 * @return 保存成功返回true,失败返回false */ -bool ShaderCache::saveCache(const ShaderCacheEntry& entry) { - if (!initialized_) { - E2D_LOG_WARN("ShaderCache not initialized, cannot save cache"); - return false; - } +bool ShaderCache::saveCache(const ShaderCacheEntry &entry) { + if (!initialized_) { + E2D_LOG_WARN("ShaderCache not initialized, cannot save cache"); + return false; + } - if (entry.binary.empty()) { - E2D_LOG_WARN("Shader binary is empty, skipping cache save for: {}", entry.name); - return false; - } + if (entry.binary.empty()) { + E2D_LOG_WARN("Shader binary is empty, skipping cache save for: {}", + entry.name); + return false; + } - std::string cachePath = getCachePath(entry.name); - E2D_LOG_DEBUG("Saving shader cache to: {} ({} bytes)", cachePath, entry.binary.size()); - - std::ofstream file(cachePath, std::ios::binary); - if (!file.is_open()) { - E2D_LOG_ERROR("Failed to create cache file: {}", cachePath); - return false; - } + std::string cachePath = getCachePath(entry.name); + E2D_LOG_DEBUG("Saving shader cache to: {} ({} bytes)", cachePath, + entry.binary.size()); - file.write(reinterpret_cast(entry.binary.data()), entry.binary.size()); - file.close(); + std::ofstream file(cachePath, std::ios::binary); + if (!file.is_open()) { + E2D_LOG_ERROR("Failed to create cache file: {}", cachePath); + return false; + } - cacheMap_[entry.name] = entry; - saveCacheIndex(); + file.write(reinterpret_cast(entry.binary.data()), + entry.binary.size()); + file.close(); - E2D_LOG_INFO("Shader cache saved: {} ({} bytes)", entry.name, entry.binary.size()); - return true; + cacheMap_[entry.name] = entry; + saveCacheIndex(); + + E2D_LOG_INFO("Shader cache saved: {} ({} bytes)", entry.name, + entry.binary.size()); + return true; } /** * @brief 使缓存失效 * @param name Shader名称 */ -void ShaderCache::invalidate(const std::string& name) { - auto it = cacheMap_.find(name); - if (it == cacheMap_.end()) { - return; - } +void ShaderCache::invalidate(const std::string &name) { + auto it = cacheMap_.find(name); + if (it == cacheMap_.end()) { + return; + } - std::string cachePath = getCachePath(name); - fs::remove(cachePath); + std::string cachePath = getCachePath(name); + fs::remove(cachePath); - cacheMap_.erase(it); - saveCacheIndex(); + cacheMap_.erase(it); + saveCacheIndex(); - E2D_LOG_DEBUG("Shader cache invalidated: {}", name); + E2D_LOG_DEBUG("Shader cache invalidated: {}", name); } /** * @brief 清除所有缓存 */ void ShaderCache::clearAll() { - for (const auto& pair : cacheMap_) { - std::string cachePath = getCachePath(pair.first); - fs::remove(cachePath); - } + for (const auto &pair : cacheMap_) { + std::string cachePath = getCachePath(pair.first); + fs::remove(cachePath); + } - cacheMap_.clear(); - saveCacheIndex(); + cacheMap_.clear(); + saveCacheIndex(); - E2D_LOG_INFO("All shader caches cleared"); + E2D_LOG_INFO("All shader caches cleared"); } /** @@ -175,18 +182,18 @@ void ShaderCache::clearAll() { * @param fragSource 片段着色器源码 * @return 哈希值字符串 */ -std::string ShaderCache::computeHash(const std::string& vertSource, - const std::string& fragSource) { - std::string combined = vertSource + fragSource; +std::string ShaderCache::computeHash(const std::string &vertSource, + const std::string &fragSource) { + std::string combined = vertSource + fragSource; - uint32_t hash = 5381; - for (char c : combined) { - hash = ((hash << 5) + hash) + static_cast(c); - } + uint32_t hash = 5381; + for (char c : combined) { + hash = ((hash << 5) + hash) + static_cast(c); + } - std::stringstream ss; - ss << std::hex << hash; - return ss.str(); + std::stringstream ss; + ss << std::hex << hash; + return ss.str(); } /** @@ -194,43 +201,43 @@ std::string ShaderCache::computeHash(const std::string& vertSource, * @return 加载成功返回true,失败返回false */ bool ShaderCache::loadCacheIndex() { - std::string indexPath = cacheDir_ + "/.cache_index"; - - if (!fs::exists(indexPath)) { - return true; - } - - std::ifstream file(indexPath); - if (!file.is_open()) { - return false; - } - - std::string line; - while (std::getline(file, line)) { - if (line.empty() || line[0] == '#') { - continue; - } - - size_t pos = line.find('='); - if (pos == std::string::npos) { - continue; - } - - std::string name = line.substr(0, pos); - std::string hash = line.substr(pos + 1); - - std::string cachePath = getCachePath(name); - if (fs::exists(cachePath)) { - ShaderCacheEntry entry; - entry.name = name; - entry.sourceHash = hash; - entry.compileTime = static_cast( - std::chrono::system_clock::now().time_since_epoch().count()); - cacheMap_[name] = entry; - } - } + std::string indexPath = cacheDir_ + "/.cache_index"; + if (!fs::exists(indexPath)) { return true; + } + + std::ifstream file(indexPath); + if (!file.is_open()) { + return false; + } + + std::string line; + while (std::getline(file, line)) { + if (line.empty() || line[0] == '#') { + continue; + } + + size_t pos = line.find('='); + if (pos == std::string::npos) { + continue; + } + + std::string name = line.substr(0, pos); + std::string hash = line.substr(pos + 1); + + std::string cachePath = getCachePath(name); + if (fs::exists(cachePath)) { + ShaderCacheEntry entry; + entry.name = name; + entry.sourceHash = hash; + entry.compileTime = static_cast( + std::chrono::system_clock::now().time_since_epoch().count()); + cacheMap_[name] = entry; + } + } + + return true; } /** @@ -238,21 +245,21 @@ bool ShaderCache::loadCacheIndex() { * @return 保存成功返回true,失败返回false */ bool ShaderCache::saveCacheIndex() { - std::string indexPath = cacheDir_ + "/.cache_index"; + std::string indexPath = cacheDir_ + "/.cache_index"; - std::ofstream file(indexPath); - if (!file.is_open()) { - return false; - } + std::ofstream file(indexPath); + if (!file.is_open()) { + return false; + } - file << "# Extra2D Shader Cache Index\n"; - file << "# Format: name=hash\n"; + file << "# Extra2D Shader Cache Index\n"; + file << "# Format: name=hash\n"; - for (const auto& pair : cacheMap_) { - file << pair.first << "=" << pair.second.sourceHash << "\n"; - } + for (const auto &pair : cacheMap_) { + file << pair.first << "=" << pair.second.sourceHash << "\n"; + } - return true; + return true; } /** @@ -260,8 +267,8 @@ bool ShaderCache::saveCacheIndex() { * @param name Shader名称 * @return 缓存文件完整路径 */ -std::string ShaderCache::getCachePath(const std::string& name) const { - return cacheDir_ + "/" + name + ".cache"; +std::string ShaderCache::getCachePath(const std::string &name) const { + return cacheDir_ + "/" + name + ".cache"; } /** @@ -269,18 +276,18 @@ std::string ShaderCache::getCachePath(const std::string& name) const { * @return 目录存在或创建成功返回true,否则返回false */ bool ShaderCache::ensureCacheDirectory() { - if (cacheDir_.empty()) { - return false; - } + if (cacheDir_.empty()) { + return false; + } - std::error_code ec; - if (!fs::exists(cacheDir_)) { - if (!fs::create_directories(cacheDir_, ec)) { - return false; - } + std::error_code ec; + if (!fs::exists(cacheDir_)) { + if (!fs::create_directories(cacheDir_, ec)) { + return false; } + } - return true; + return true; } } // namespace extra2d diff --git a/Extra2D/src/graphics/shader/shader_hot_reloader.cpp b/Extra2D/src/graphics/shader/shader_hot_reloader.cpp index 1afd919..ad00f05 100644 --- a/Extra2D/src/graphics/shader/shader_hot_reloader.cpp +++ b/Extra2D/src/graphics/shader/shader_hot_reloader.cpp @@ -1,8 +1,10 @@ -#include -#include #include +#include +#include +#include #include + namespace extra2d { namespace fs = std::filesystem; @@ -11,9 +13,9 @@ namespace fs = std::filesystem; * @brief 获取单例实例 * @return 热重载管理器实例引用 */ -ShaderHotReloader& ShaderHotReloader::getInstance() { - static ShaderHotReloader instance; - return instance; +ShaderHotReloader &ShaderHotReloader::getInstance() { + static ShaderHotReloader instance; + return instance; } /** @@ -21,38 +23,38 @@ ShaderHotReloader& ShaderHotReloader::getInstance() { * @return 初始化成功返回true,失败返回false */ bool ShaderHotReloader::init() { - if (initialized_) { - return true; - } + if (initialized_) { + return true; + } #ifdef _WIN32 - buffer_.resize(4096); + buffer_.resize(4096); #endif - initialized_ = true; - E2D_LOG_INFO("Shader hot reloader initialized"); - return true; + initialized_ = true; + E2D_LOG_INFO("Shader hot reloader initialized"); + return true; } /** * @brief 关闭热重载系统 */ void ShaderHotReloader::shutdown() { - if (!initialized_) { - return; - } + if (!initialized_) { + return; + } #ifdef _WIN32 - if (watchHandle_ != nullptr) { - FindCloseChangeNotification(watchHandle_); - watchHandle_ = nullptr; - } + if (watchHandle_ != nullptr) { + FindCloseChangeNotification(watchHandle_); + watchHandle_ = nullptr; + } #endif - watchMap_.clear(); - initialized_ = false; - enabled_ = false; - E2D_LOG_INFO("Shader hot reloader shutdown"); + watchMap_.clear(); + initialized_ = false; + enabled_ = false; + E2D_LOG_INFO("Shader hot reloader shutdown"); } /** @@ -61,47 +63,47 @@ void ShaderHotReloader::shutdown() { * @param filePaths 要监视的文件列表 * @param callback 文件变化时的回调 */ -void ShaderHotReloader::watch(const std::string& shaderName, - const std::vector& filePaths, +void ShaderHotReloader::watch(const std::string &shaderName, + const std::vector &filePaths, FileChangeCallback callback) { - if (!initialized_) { - E2D_LOG_WARN("Hot reloader not initialized"); - return; - } + if (!initialized_) { + E2D_LOG_WARN("Hot reloader not initialized"); + return; + } - WatchInfo info; - info.filePaths = filePaths; - info.callback = callback; + WatchInfo info; + info.filePaths = filePaths; + info.callback = callback; - for (const auto& path : filePaths) { - info.modifiedTimes[path] = getFileModifiedTime(path); - } + for (const auto &path : filePaths) { + info.modifiedTimes[path] = getFileModifiedTime(path); + } - watchMap_[shaderName] = std::move(info); - E2D_LOG_DEBUG("Watching shader: {} ({} files)", shaderName, filePaths.size()); + watchMap_[shaderName] = std::move(info); + E2D_LOG_DEBUG("Watching shader: {} ({} files)", shaderName, filePaths.size()); } /** * @brief 取消监视 * @param shaderName Shader名称 */ -void ShaderHotReloader::unwatch(const std::string& shaderName) { - auto it = watchMap_.find(shaderName); - if (it != watchMap_.end()) { - watchMap_.erase(it); - E2D_LOG_DEBUG("Stopped watching shader: {}", shaderName); - } +void ShaderHotReloader::unwatch(const std::string &shaderName) { + auto it = watchMap_.find(shaderName); + if (it != watchMap_.end()) { + watchMap_.erase(it); + E2D_LOG_DEBUG("Stopped watching shader: {}", shaderName); + } } /** * @brief 更新文件监视(在主循环中调用) */ void ShaderHotReloader::update() { - if (!initialized_ || !enabled_) { - return; - } + if (!initialized_ || !enabled_) { + return; + } - pollChanges(); + pollChanges(); } /** @@ -109,40 +111,41 @@ void ShaderHotReloader::update() { * @param enabled 是否启用 */ void ShaderHotReloader::setEnabled(bool enabled) { - enabled_ = enabled; - E2D_LOG_DEBUG("Hot reload {}", enabled ? "enabled" : "disabled"); + enabled_ = enabled; + E2D_LOG_DEBUG("Hot reload {}", enabled ? "enabled" : "disabled"); } /** * @brief 轮询检查文件变化 */ void ShaderHotReloader::pollChanges() { - auto now = static_cast( - std::chrono::system_clock::now().time_since_epoch().count()); + auto now = static_cast( + std::chrono::system_clock::now().time_since_epoch().count()); - for (auto& pair : watchMap_) { - WatchInfo& info = pair.second; + for (auto &pair : watchMap_) { + WatchInfo &info = pair.second; - for (const auto& filePath : info.filePaths) { - uint64_t currentModTime = getFileModifiedTime(filePath); - uint64_t lastModTime = info.modifiedTimes[filePath]; + for (const auto &filePath : info.filePaths) { + uint64_t currentModTime = getFileModifiedTime(filePath); + uint64_t lastModTime = info.modifiedTimes[filePath]; - if (currentModTime != 0 && lastModTime != 0 && currentModTime != lastModTime) { - info.modifiedTimes[filePath] = currentModTime; + if (currentModTime != 0 && lastModTime != 0 && + currentModTime != lastModTime) { + info.modifiedTimes[filePath] = currentModTime; - FileChangeEvent event; - event.filepath = filePath; - event.type = FileChangeEvent::Type::Modified; - event.timestamp = now; + FileChangeEvent event; + event.filepath = filePath; + event.type = FileChangeEvent::Type::Modified; + event.timestamp = now; - E2D_LOG_DEBUG("Shader file changed: {}", filePath); + E2D_LOG_DEBUG("Shader file changed: {}", filePath); - if (info.callback) { - info.callback(event); - } - } + if (info.callback) { + info.callback(event); } + } } + } } /** @@ -150,15 +153,16 @@ void ShaderHotReloader::pollChanges() { * @param filepath 文件路径 * @return 修改时间戳 */ -uint64_t ShaderHotReloader::getFileModifiedTime(const std::string& filepath) { - try { - auto ftime = fs::last_write_time(filepath); - auto sctp = std::chrono::time_point_cast( - ftime - fs::file_time_type::clock::now() + std::chrono::system_clock::now()); - return static_cast(sctp.time_since_epoch().count()); - } catch (...) { - return 0; - } +uint64_t ShaderHotReloader::getFileModifiedTime(const std::string &filepath) { + try { + auto ftime = fs::last_write_time(filepath); + auto sctp = std::chrono::time_point_cast( + ftime - fs::file_time_type::clock::now() + + std::chrono::system_clock::now()); + return static_cast(sctp.time_since_epoch().count()); + } catch (...) { + return 0; + } } } // namespace extra2d diff --git a/Extra2D/src/graphics/shader/shader_loader.cpp b/Extra2D/src/graphics/shader/shader_loader.cpp index 43c3599..62ebac1 100644 --- a/Extra2D/src/graphics/shader/shader_loader.cpp +++ b/Extra2D/src/graphics/shader/shader_loader.cpp @@ -1,7 +1,7 @@ -#include -#include #include -#include +#include +#include +#include #include #include #include @@ -13,8 +13,7 @@ namespace fs = std::filesystem; /** * @brief 构造函数,初始化Shader加载器 */ -ShaderLoader::ShaderLoader() { -} +ShaderLoader::ShaderLoader() {} /** * @brief 从分离文件加载Shader (.vert + .frag) @@ -23,51 +22,53 @@ ShaderLoader::ShaderLoader() { * @param fragPath 片段着色器文件路径 * @return 加载结果 */ -ShaderLoadResult ShaderLoader::loadFromSeparateFiles( - const std::string& name, - const std::string& vertPath, - const std::string& fragPath) { - - ShaderLoadResult result; +ShaderLoadResult +ShaderLoader::loadFromSeparateFiles(const std::string &name, + const std::string &vertPath, + const std::string &fragPath) { - if (!fileExists(vertPath)) { - result.errorMessage = "Vertex shader file not found: " + vertPath; - E2D_LOG_ERROR("{}", result.errorMessage); - return result; - } - - if (!fileExists(fragPath)) { - result.errorMessage = "Fragment shader file not found: " + fragPath; - E2D_LOG_ERROR("{}", result.errorMessage); - return result; - } - - std::string vertSource = readFile(vertPath); - std::string fragSource = readFile(fragPath); - - if (vertSource.empty()) { - result.errorMessage = "Failed to read vertex shader file: " + vertPath; - E2D_LOG_ERROR("{}", result.errorMessage); - return result; - } - - if (fragSource.empty()) { - result.errorMessage = "Failed to read fragment shader file: " + fragPath; - E2D_LOG_ERROR("{}", result.errorMessage); - return result; - } - - fs::path vertDir = fs::path(vertPath).parent_path(); - fs::path fragDir = fs::path(fragPath).parent_path(); - - vertSource = processIncludes(vertSource, vertDir.string(), result.dependencies); - fragSource = processIncludes(fragSource, fragDir.string(), result.dependencies); - - result.vertSource = vertSource; - result.fragSource = fragSource; - result.success = true; + ShaderLoadResult result; + if (!fileExists(vertPath)) { + result.errorMessage = "Vertex shader file not found: " + vertPath; + E2D_LOG_ERROR("{}", result.errorMessage); return result; + } + + if (!fileExists(fragPath)) { + result.errorMessage = "Fragment shader file not found: " + fragPath; + E2D_LOG_ERROR("{}", result.errorMessage); + return result; + } + + std::string vertSource = readFile(vertPath); + std::string fragSource = readFile(fragPath); + + if (vertSource.empty()) { + result.errorMessage = "Failed to read vertex shader file: " + vertPath; + E2D_LOG_ERROR("{}", result.errorMessage); + return result; + } + + if (fragSource.empty()) { + result.errorMessage = "Failed to read fragment shader file: " + fragPath; + E2D_LOG_ERROR("{}", result.errorMessage); + return result; + } + + fs::path vertDir = fs::path(vertPath).parent_path(); + fs::path fragDir = fs::path(fragPath).parent_path(); + + vertSource = + processIncludes(vertSource, vertDir.string(), result.dependencies); + fragSource = + processIncludes(fragSource, fragDir.string(), result.dependencies); + + result.vertSource = vertSource; + result.fragSource = fragSource; + result.success = true; + + return result; } /** @@ -75,40 +76,42 @@ ShaderLoadResult ShaderLoader::loadFromSeparateFiles( * @param path 组合Shader文件路径 * @return 加载结果 */ -ShaderLoadResult ShaderLoader::loadFromCombinedFile(const std::string& path) { - ShaderLoadResult result; - - if (!fileExists(path)) { - result.errorMessage = "Shader file not found: " + path; - E2D_LOG_ERROR("{}", result.errorMessage); - return result; - } - - std::string content = readFile(path); - if (content.empty()) { - result.errorMessage = "Failed to read shader file: " + path; - E2D_LOG_ERROR("{}", result.errorMessage); - return result; - } - - ShaderMetadata metadata; - std::string vertSource, fragSource; - - if (!parseCombinedFile(content, vertSource, fragSource, metadata)) { - result.errorMessage = "Failed to parse combined shader file: " + path; - E2D_LOG_ERROR("{}", result.errorMessage); - return result; - } - - fs::path baseDir = fs::path(path).parent_path(); - vertSource = processIncludes(vertSource, baseDir.string(), result.dependencies); - fragSource = processIncludes(fragSource, baseDir.string(), result.dependencies); - - result.vertSource = vertSource; - result.fragSource = fragSource; - result.success = true; +ShaderLoadResult ShaderLoader::loadFromCombinedFile(const std::string &path) { + ShaderLoadResult result; + if (!fileExists(path)) { + result.errorMessage = "Shader file not found: " + path; + E2D_LOG_ERROR("{}", result.errorMessage); return result; + } + + std::string content = readFile(path); + if (content.empty()) { + result.errorMessage = "Failed to read shader file: " + path; + E2D_LOG_ERROR("{}", result.errorMessage); + return result; + } + + ShaderMetadata metadata; + std::string vertSource, fragSource; + + if (!parseCombinedFile(content, vertSource, fragSource, metadata)) { + result.errorMessage = "Failed to parse combined shader file: " + path; + E2D_LOG_ERROR("{}", result.errorMessage); + return result; + } + + fs::path baseDir = fs::path(path).parent_path(); + vertSource = + processIncludes(vertSource, baseDir.string(), result.dependencies); + fragSource = + processIncludes(fragSource, baseDir.string(), result.dependencies); + + result.vertSource = vertSource; + result.fragSource = fragSource; + result.success = true; + + return result; } /** @@ -117,15 +120,14 @@ ShaderLoadResult ShaderLoader::loadFromCombinedFile(const std::string& path) { * @param fragSource 片段着色器源码 * @return 加载结果 */ -ShaderLoadResult ShaderLoader::loadFromSource( - const std::string& vertSource, - const std::string& fragSource) { - - ShaderLoadResult result; - result.vertSource = vertSource; - result.fragSource = fragSource; - result.success = true; - return result; +ShaderLoadResult ShaderLoader::loadFromSource(const std::string &vertSource, + const std::string &fragSource) { + + ShaderLoadResult result; + result.vertSource = vertSource; + result.fragSource = fragSource; + result.success = true; + return result; } /** @@ -135,51 +137,52 @@ ShaderLoadResult ShaderLoader::loadFromSource( * @param outDependencies 输出依赖列表 * @return 处理后的源码 */ -std::string ShaderLoader::processIncludes( - const std::string& source, - const std::string& baseDir, - std::vector& outDependencies) { - - std::string result; - std::istringstream stream(source); - std::string line; +std::string +ShaderLoader::processIncludes(const std::string &source, + const std::string &baseDir, + std::vector &outDependencies) { - while (std::getline(stream, line)) { - size_t includePos = line.find("#include"); - if (includePos != std::string::npos) { - size_t startQuote = line.find('"', includePos); - size_t endQuote = line.find('"', startQuote + 1); - - if (startQuote != std::string::npos && endQuote != std::string::npos) { - std::string includeName = line.substr(startQuote + 1, endQuote - startQuote - 1); - std::string includePath = findIncludeFile(includeName, baseDir); - - if (!includePath.empty()) { - auto cacheIt = includeCache_.find(includePath); - std::string includeContent; - - if (cacheIt != includeCache_.end()) { - includeContent = cacheIt->second; - } else { - includeContent = readFile(includePath); - includeCache_[includePath] = includeContent; - } - - outDependencies.push_back(includePath); - result += includeContent; - result += "\n"; - continue; - } else { - E2D_LOG_WARN("Include file not found: {}", includeName); - } - } + std::string result; + std::istringstream stream(source); + std::string line; + + while (std::getline(stream, line)) { + size_t includePos = line.find("#include"); + if (includePos != std::string::npos) { + size_t startQuote = line.find('"', includePos); + size_t endQuote = line.find('"', startQuote + 1); + + if (startQuote != std::string::npos && endQuote != std::string::npos) { + std::string includeName = + line.substr(startQuote + 1, endQuote - startQuote - 1); + std::string includePath = findIncludeFile(includeName, baseDir); + + if (!includePath.empty()) { + auto cacheIt = includeCache_.find(includePath); + std::string includeContent; + + if (cacheIt != includeCache_.end()) { + includeContent = cacheIt->second; + } else { + includeContent = readFile(includePath); + includeCache_[includePath] = includeContent; + } + + outDependencies.push_back(includePath); + result += includeContent; + result += "\n"; + continue; + } else { + E2D_LOG_WARN("Include file not found: {}", includeName); } - - result += line; - result += "\n"; + } } - return result; + result += line; + result += "\n"; + } + + return result; } /** @@ -188,40 +191,40 @@ std::string ShaderLoader::processIncludes( * @param defines 预处理器定义列表 * @return 处理后的源码 */ -std::string ShaderLoader::applyDefines( - const std::string& source, - const std::vector& defines) { - - if (defines.empty()) { - return source; +std::string +ShaderLoader::applyDefines(const std::string &source, + const std::vector &defines) { + + if (defines.empty()) { + return source; + } + + std::string defineBlock; + for (const auto &def : defines) { + defineBlock += "#define " + def + "\n"; + } + + std::string result; + std::istringstream stream(source); + std::string line; + bool inserted = false; + + while (std::getline(stream, line)) { + if (!inserted && (line.find("#version") != std::string::npos || + line.find("precision") != std::string::npos)) { + result += line + "\n"; + continue; } - std::string defineBlock; - for (const auto& def : defines) { - defineBlock += "#define " + def + "\n"; + if (!inserted) { + result += defineBlock; + inserted = true; } - std::string result; - std::istringstream stream(source); - std::string line; - bool inserted = false; + result += line + "\n"; + } - while (std::getline(stream, line)) { - if (!inserted && (line.find("#version") != std::string::npos || - line.find("precision") != std::string::npos)) { - result += line + "\n"; - continue; - } - - if (!inserted) { - result += defineBlock; - inserted = true; - } - - result += line + "\n"; - } - - return result; + return result; } /** @@ -229,30 +232,31 @@ std::string ShaderLoader::applyDefines( * @param path Shader文件路径 * @return 元数据 */ -ShaderMetadata ShaderLoader::getMetadata(const std::string& path) { - ShaderMetadata metadata; - - if (!fileExists(path)) { - return metadata; - } - - metadata.combinedPath = path; - metadata.lastModified = getFileModifiedTime(path); - - fs::path p(path); - metadata.name = p.stem().string(); +ShaderMetadata ShaderLoader::getMetadata(const std::string &path) { + ShaderMetadata metadata; + if (!fileExists(path)) { return metadata; + } + + metadata.combinedPath = path; + metadata.lastModified = getFileModifiedTime(path); + + fs::path p(path); + metadata.name = p.stem().string(); + + return metadata; } /** * @brief 添加include搜索路径 * @param path 搜索路径 */ -void ShaderLoader::addIncludePath(const std::string& path) { - if (std::find(includePaths_.begin(), includePaths_.end(), path) == includePaths_.end()) { - includePaths_.push_back(path); - } +void ShaderLoader::addIncludePath(const std::string &path) { + if (std::find(includePaths_.begin(), includePaths_.end(), path) == + includePaths_.end()) { + includePaths_.push_back(path); + } } /** @@ -260,15 +264,15 @@ void ShaderLoader::addIncludePath(const std::string& path) { * @param filepath 文件路径 * @return 文件内容字符串 */ -std::string ShaderLoader::readFile(const std::string& filepath) { - std::ifstream file(filepath, std::ios::binary); - if (!file.is_open()) { - return ""; - } +std::string ShaderLoader::readFile(const std::string &filepath) { + std::ifstream file(filepath, std::ios::binary); + if (!file.is_open()) { + return ""; + } - std::ostringstream content; - content << file.rdbuf(); - return content.str(); + std::ostringstream content; + content << file.rdbuf(); + return content.str(); } /** @@ -276,19 +280,20 @@ std::string ShaderLoader::readFile(const std::string& filepath) { * @param filepath 文件路径 * @return 修改时间戳 */ -uint64_t ShaderLoader::getFileModifiedTime(const std::string& filepath) { +uint64_t ShaderLoader::getFileModifiedTime(const std::string &filepath) { #ifdef __SWITCH__ - (void)filepath; - return 1; + (void)filepath; + return 1; #else - try { - auto ftime = fs::last_write_time(filepath); - auto sctp = std::chrono::time_point_cast( - ftime - fs::file_time_type::clock::now() + std::chrono::system_clock::now()); - return static_cast(sctp.time_since_epoch().count()); - } catch (...) { - return 0; - } + try { + auto ftime = fs::last_write_time(filepath); + auto sctp = std::chrono::time_point_cast( + ftime - fs::file_time_type::clock::now() + + std::chrono::system_clock::now()); + return static_cast(sctp.time_since_epoch().count()); + } catch (...) { + return 0; + } #endif } @@ -297,8 +302,8 @@ uint64_t ShaderLoader::getFileModifiedTime(const std::string& filepath) { * @param filepath 文件路径 * @return 存在返回true,否则返回false */ -bool ShaderLoader::fileExists(const std::string& filepath) { - return fs::exists(filepath); +bool ShaderLoader::fileExists(const std::string &filepath) { + return fs::exists(filepath); } /** @@ -309,73 +314,67 @@ bool ShaderLoader::fileExists(const std::string& filepath) { * @param outMetadata 输出元数据 * @return 解析成功返回true,失败返回false */ -bool ShaderLoader::parseCombinedFile(const std::string& content, - std::string& outVert, - std::string& outFrag, - ShaderMetadata& outMetadata) { - enum class Section { - None, - Meta, - Vertex, - Fragment - }; +bool ShaderLoader::parseCombinedFile(const std::string &content, + std::string &outVert, std::string &outFrag, + ShaderMetadata &outMetadata) { + enum class Section { None, Meta, Vertex, Fragment }; - Section currentSection = Section::None; - std::string metaContent; - std::string vertContent; - std::string fragContent; + Section currentSection = Section::None; + std::string metaContent; + std::string vertContent; + std::string fragContent; - std::istringstream stream(content); - std::string line; + std::istringstream stream(content); + std::string line; - while (std::getline(stream, line)) { - std::string trimmedLine = line; - size_t start = trimmedLine.find_first_not_of(" \t\r\n"); - if (start != std::string::npos) { - trimmedLine = trimmedLine.substr(start); - } - size_t end = trimmedLine.find_last_not_of(" \t\r\n"); - if (end != std::string::npos) { - trimmedLine = trimmedLine.substr(0, end + 1); - } - - if (trimmedLine == "#meta") { - currentSection = Section::Meta; - continue; - } else if (trimmedLine == "#vertex") { - currentSection = Section::Vertex; - continue; - } else if (trimmedLine == "#fragment") { - currentSection = Section::Fragment; - continue; - } - - switch (currentSection) { - case Section::Meta: - metaContent += line + "\n"; - break; - case Section::Vertex: - vertContent += line + "\n"; - break; - case Section::Fragment: - fragContent += line + "\n"; - break; - default: - break; - } + while (std::getline(stream, line)) { + std::string trimmedLine = line; + size_t start = trimmedLine.find_first_not_of(" \t\r\n"); + if (start != std::string::npos) { + trimmedLine = trimmedLine.substr(start); + } + size_t end = trimmedLine.find_last_not_of(" \t\r\n"); + if (end != std::string::npos) { + trimmedLine = trimmedLine.substr(0, end + 1); } - if (vertContent.empty() || fragContent.empty()) { - return false; + if (trimmedLine == "#meta") { + currentSection = Section::Meta; + continue; + } else if (trimmedLine == "#vertex") { + currentSection = Section::Vertex; + continue; + } else if (trimmedLine == "#fragment") { + currentSection = Section::Fragment; + continue; } - if (!metaContent.empty()) { - parseMetadata(metaContent, outMetadata); + switch (currentSection) { + case Section::Meta: + metaContent += line + "\n"; + break; + case Section::Vertex: + vertContent += line + "\n"; + break; + case Section::Fragment: + fragContent += line + "\n"; + break; + default: + break; } + } - outVert = vertContent; - outFrag = fragContent; - return true; + if (vertContent.empty() || fragContent.empty()) { + return false; + } + + if (!metaContent.empty()) { + parseMetadata(metaContent, outMetadata); + } + + outVert = vertContent; + outFrag = fragContent; + return true; } /** @@ -384,44 +383,45 @@ bool ShaderLoader::parseCombinedFile(const std::string& content, * @param outMetadata 输出元数据 * @return 解析成功返回true,失败返回false */ -bool ShaderLoader::parseMetadata(const std::string& jsonContent, ShaderMetadata& outMetadata) { - std::string content = jsonContent; - - size_t start = content.find('{'); - size_t end = content.rfind('}'); - if (start == std::string::npos || end == std::string::npos || end <= start) { - return false; +bool ShaderLoader::parseMetadata(const std::string &jsonContent, + ShaderMetadata &outMetadata) { + std::string content = jsonContent; + + size_t start = content.find('{'); + size_t end = content.rfind('}'); + if (start == std::string::npos || end == std::string::npos || end <= start) { + return false; + } + + content = content.substr(start, end - start + 1); + + auto extractString = [&content](const std::string &key) -> std::string { + std::string searchKey = "\"" + key + "\""; + size_t keyPos = content.find(searchKey); + if (keyPos == std::string::npos) { + return ""; } - - content = content.substr(start, end - start + 1); - auto extractString = [&content](const std::string& key) -> std::string { - std::string searchKey = "\"" + key + "\""; - size_t keyPos = content.find(searchKey); - if (keyPos == std::string::npos) { - return ""; - } - - size_t colonPos = content.find(':', keyPos); - if (colonPos == std::string::npos) { - return ""; - } - - size_t quoteStart = content.find('"', colonPos); - if (quoteStart == std::string::npos) { - return ""; - } - - size_t quoteEnd = content.find('"', quoteStart + 1); - if (quoteEnd == std::string::npos) { - return ""; - } - - return content.substr(quoteStart + 1, quoteEnd - quoteStart - 1); - }; + size_t colonPos = content.find(':', keyPos); + if (colonPos == std::string::npos) { + return ""; + } - outMetadata.name = extractString("name"); - return true; + size_t quoteStart = content.find('"', colonPos); + if (quoteStart == std::string::npos) { + return ""; + } + + size_t quoteEnd = content.find('"', quoteStart + 1); + if (quoteEnd == std::string::npos) { + return ""; + } + + return content.substr(quoteStart + 1, quoteEnd - quoteStart - 1); + }; + + outMetadata.name = extractString("name"); + return true; } /** @@ -430,22 +430,23 @@ bool ShaderLoader::parseMetadata(const std::string& jsonContent, ShaderMetadata& * @param baseDir 基础目录 * @return 找到的完整路径,未找到返回空字符串 */ -std::string ShaderLoader::findIncludeFile(const std::string& includeName, const std::string& baseDir) { - fs::path basePath(baseDir); - fs::path includePath = basePath / includeName; - +std::string ShaderLoader::findIncludeFile(const std::string &includeName, + const std::string &baseDir) { + fs::path basePath(baseDir); + fs::path includePath = basePath / includeName; + + if (fs::exists(includePath)) { + return includePath.string(); + } + + for (const auto &searchPath : includePaths_) { + includePath = fs::path(searchPath) / includeName; if (fs::exists(includePath)) { - return includePath.string(); + return includePath.string(); } + } - for (const auto& searchPath : includePaths_) { - includePath = fs::path(searchPath) / includeName; - if (fs::exists(includePath)) { - return includePath.string(); - } - } - - return ""; + return ""; } } // namespace extra2d diff --git a/Extra2D/src/graphics/shader/shader_manager.cpp b/Extra2D/src/graphics/shader/shader_manager.cpp index 3c0b651..8b682ee 100644 --- a/Extra2D/src/graphics/shader/shader_manager.cpp +++ b/Extra2D/src/graphics/shader/shader_manager.cpp @@ -1,5 +1,7 @@ +#include #include -#include +#include + #include @@ -11,9 +13,9 @@ namespace extra2d { * @brief 获取单例实例 * @return Shader管理器实例引用 */ -ShaderManager& ShaderManager::getInstance() { - static ShaderManager instance; - return instance; +ShaderManager &ShaderManager::getInstance() { + static ShaderManager instance; + return instance; } /** @@ -23,22 +25,23 @@ ShaderManager& ShaderManager::getInstance() { * @param appName 应用名称(用于缓存目录) * @return 初始化成功返回true,失败返回false */ -bool ShaderManager::init(Ptr factory, const std::string& appName) { - // 使用相对路径作为Shader目录 - std::string shaderDir = "shaders/"; - std::string cacheDir = "cache/shaders/"; +bool ShaderManager::init(Ptr factory, + const std::string &appName) { + // 使用相对路径作为Shader目录 + std::string shaderDir = "shaders/"; + std::string cacheDir = "cache/shaders/"; - // 非Switch平台支持热重载 + // 非Switch平台支持热重载 #ifndef __SWITCH__ - hotReloadSupported_ = true; + hotReloadSupported_ = true; #else - hotReloadSupported_ = false; + hotReloadSupported_ = false; #endif - E2D_LOG_INFO("ShaderManager init (HotReload: {})", - hotReloadSupported_ ? "supported" : "not supported"); + E2D_LOG_INFO("ShaderManager init (HotReload: {})", + hotReloadSupported_ ? "supported" : "not supported"); - return init(shaderDir, cacheDir, factory); + return init(shaderDir, cacheDir, factory); } /** @@ -48,75 +51,76 @@ bool ShaderManager::init(Ptr factory, const std::string& appName * @param factory 渲染后端Shader工厂 * @return 初始化成功返回true,失败返回false */ -bool ShaderManager::init(const std::string& shaderDir, - const std::string& cacheDir, +bool ShaderManager::init(const std::string &shaderDir, + const std::string &cacheDir, Ptr factory) { - if (initialized_) { - E2D_LOG_WARN("ShaderManager already initialized"); - return true; - } + if (initialized_) { + E2D_LOG_WARN("ShaderManager already initialized"); + return true; + } - if (!factory) { - E2D_LOG_ERROR("Shader factory is null"); - return false; - } + if (!factory) { + E2D_LOG_ERROR("Shader factory is null"); + return false; + } - shaderDir_ = shaderDir; - cacheDir_ = cacheDir; - factory_ = factory; + shaderDir_ = shaderDir; + cacheDir_ = cacheDir; + factory_ = factory; - // 非Switch平台支持热重载 + // 非Switch平台支持热重载 #ifndef __SWITCH__ - hotReloadSupported_ = true; + hotReloadSupported_ = true; #else - hotReloadSupported_ = false; + hotReloadSupported_ = false; #endif #ifdef __SWITCH__ - if (!ShaderCache::getInstance().init(cacheDir_)) { - E2D_LOG_WARN("Failed to initialize shader cache on Switch"); - } + if (!ShaderCache::getInstance().init(cacheDir_)) { + E2D_LOG_WARN("Failed to initialize shader cache on Switch"); + } #else - if (!ShaderCache::getInstance().init(cacheDir_)) { - E2D_LOG_WARN("Failed to initialize shader cache, caching disabled"); - } + if (!ShaderCache::getInstance().init(cacheDir_)) { + E2D_LOG_WARN("Failed to initialize shader cache, caching disabled"); + } #endif - if (hotReloadSupported_) { - if (!ShaderHotReloader::getInstance().init()) { - E2D_LOG_WARN("Failed to initialize hot reloader"); - } + if (hotReloadSupported_) { + if (!ShaderHotReloader::getInstance().init()) { + E2D_LOG_WARN("Failed to initialize hot reloader"); } + } - loader_.addIncludePath(shaderDir_ + "common"); + loader_.addIncludePath(shaderDir_ + "common"); - initialized_ = true; - E2D_LOG_INFO("ShaderManager initialized"); - E2D_LOG_INFO(" Shader directory: {}", shaderDir_); - E2D_LOG_INFO(" Cache directory: {}", cacheDir_); - E2D_LOG_INFO(" Hot reload: {}", hotReloadSupported_ ? "supported" : "not supported"); + initialized_ = true; + E2D_LOG_INFO("ShaderManager initialized"); + E2D_LOG_INFO(" Shader directory: {}", shaderDir_); + E2D_LOG_INFO(" Cache directory: {}", cacheDir_); + E2D_LOG_INFO(" Hot reload: {}", + hotReloadSupported_ ? "supported" : "not supported"); - return true; + return true; } /** * @brief 关闭Shader系统 */ void ShaderManager::shutdown() { - if (!initialized_) { - return; - } + if (!initialized_) { + return; + } - if (hotReloadSupported_) { - ShaderHotReloader::getInstance().shutdown(); - } - ShaderCache::getInstance().shutdown(); + if (hotReloadSupported_) { + ShaderHotReloader::getInstance().shutdown(); + } + ShaderCache::getInstance().shutdown(); - shaders_.clear(); - factory_.reset(); - initialized_ = false; + shaders_.clear(); + factory_.reset(); + initialized_ = false; - E2D_LOG_INFO("ShaderManager shutdown"); + E2D_LOG_INFO("ShaderManager shutdown"); } /** @@ -126,72 +130,79 @@ void ShaderManager::shutdown() { * @param fragPath 片段着色器文件路径 * @return 加载的Shader实例 */ -Ptr ShaderManager::loadFromFiles(const std::string& name, - const std::string& vertPath, - const std::string& fragPath) { - if (!initialized_) { - E2D_LOG_ERROR("ShaderManager not initialized"); - return nullptr; - } +Ptr ShaderManager::loadFromFiles(const std::string &name, + const std::string &vertPath, + const std::string &fragPath) { + if (!initialized_) { + E2D_LOG_ERROR("ShaderManager not initialized"); + return nullptr; + } - auto it = shaders_.find(name); - if (it != shaders_.end()) { - return it->second.shader; - } + auto it = shaders_.find(name); + if (it != shaders_.end()) { + return it->second.shader; + } - ShaderLoadResult result = loader_.loadFromSeparateFiles(name, vertPath, fragPath); - if (!result.success) { - E2D_LOG_ERROR("Failed to load shader files: {} - {}", vertPath, fragPath); - return nullptr; - } + ShaderLoadResult result = + loader_.loadFromSeparateFiles(name, vertPath, fragPath); + if (!result.success) { + E2D_LOG_ERROR("Failed to load shader files: {} - {}", vertPath, fragPath); + return nullptr; + } - std::string sourceHash = ShaderCache::computeHash(result.vertSource, result.fragSource); - Ptr shader = loadFromCache(name, sourceHash, result.vertSource, result.fragSource); + std::string sourceHash = + ShaderCache::computeHash(result.vertSource, result.fragSource); + Ptr shader = + loadFromCache(name, sourceHash, result.vertSource, result.fragSource); + if (!shader) { + E2D_LOG_DEBUG("No valid cache found, compiling shader from source: {}", + name); + shader = + factory_->createFromSource(name, result.vertSource, result.fragSource); if (!shader) { - E2D_LOG_DEBUG("No valid cache found, compiling shader from source: {}", name); - shader = factory_->createFromSource(name, result.vertSource, result.fragSource); - if (!shader) { - E2D_LOG_ERROR("Failed to create shader from source: {}", name); - return nullptr; - } - - std::vector binary; - if (factory_->getShaderBinary(*shader, binary)) { - E2D_LOG_DEBUG("Got shader binary, size: {} bytes", binary.size()); - ShaderCacheEntry entry; - entry.name = name; - entry.sourceHash = sourceHash; - entry.binary = binary; - entry.dependencies = result.dependencies; - ShaderCache::getInstance().saveCache(entry); - } else { - E2D_LOG_WARN("Failed to get shader binary for: {}", name); - } + E2D_LOG_ERROR("Failed to create shader from source: {}", name); + return nullptr; } - ShaderInfo info; - info.shader = shader; - info.vertSource = result.vertSource; - info.fragSource = result.fragSource; - info.filePaths = {vertPath, fragPath}; - info.filePaths.insert(info.filePaths.end(), result.dependencies.begin(), result.dependencies.end()); - - info.metadata.name = name; - info.metadata.vertPath = vertPath; - info.metadata.fragPath = fragPath; - - shaders_[name] = std::move(info); - - if (hotReloadEnabled_ && hotReloadSupported_) { - auto callback = [this, name](const FileChangeEvent& event) { - this->handleFileChange(name, event); - }; - ShaderHotReloader::getInstance().watch(name, shaders_[name].filePaths, callback); + std::vector binary; + if (factory_->getShaderBinary(*shader, binary)) { + E2D_LOG_DEBUG("Got shader binary, size: {} bytes", binary.size()); + ShaderCacheEntry entry; + entry.name = name; + entry.sourceHash = sourceHash; + entry.binary = binary; + entry.dependencies = result.dependencies; + ShaderCache::getInstance().saveCache(entry); + } else { + E2D_LOG_WARN("Failed to get shader binary for: {}", name); } + } - E2D_LOG_DEBUG("Shader loaded: {}", name); - return shader; + ShaderInfo info; + info.shader = shader; + info.vertSource = result.vertSource; + info.fragSource = result.fragSource; + info.filePaths = {vertPath, fragPath}; + info.filePaths.insert(info.filePaths.end(), result.dependencies.begin(), + result.dependencies.end()); + + info.metadata.name = name; + info.metadata.vertPath = vertPath; + info.metadata.fragPath = fragPath; + + shaders_[name] = std::move(info); + + if (hotReloadEnabled_ && hotReloadSupported_) { + auto callback = [this, name](const FileChangeEvent &event) { + this->handleFileChange(name, event); + }; + ShaderHotReloader::getInstance().watch(name, shaders_[name].filePaths, + callback); + } + + E2D_LOG_DEBUG("Shader loaded: {}", name); + return shader; } /** @@ -199,70 +210,76 @@ Ptr ShaderManager::loadFromFiles(const std::string& name, * @param path 组合Shader文件路径 * @return 加载的Shader实例 */ -Ptr ShaderManager::loadFromCombinedFile(const std::string& path) { - if (!initialized_) { - E2D_LOG_ERROR("ShaderManager not initialized"); - return nullptr; - } +Ptr ShaderManager::loadFromCombinedFile(const std::string &path) { + if (!initialized_) { + E2D_LOG_ERROR("ShaderManager not initialized"); + return nullptr; + } - ShaderMetadata metadata = loader_.getMetadata(path); - std::string name = metadata.name.empty() ? path : metadata.name; + ShaderMetadata metadata = loader_.getMetadata(path); + std::string name = metadata.name.empty() ? path : metadata.name; - auto it = shaders_.find(name); - if (it != shaders_.end()) { - return it->second.shader; - } + auto it = shaders_.find(name); + if (it != shaders_.end()) { + return it->second.shader; + } - ShaderLoadResult result = loader_.loadFromCombinedFile(path); - if (!result.success) { - E2D_LOG_ERROR("Failed to load combined shader file: {}", path); - return nullptr; - } + ShaderLoadResult result = loader_.loadFromCombinedFile(path); + if (!result.success) { + E2D_LOG_ERROR("Failed to load combined shader file: {}", path); + return nullptr; + } - std::string sourceHash = ShaderCache::computeHash(result.vertSource, result.fragSource); - Ptr shader = loadFromCache(name, sourceHash, result.vertSource, result.fragSource); + std::string sourceHash = + ShaderCache::computeHash(result.vertSource, result.fragSource); + Ptr shader = + loadFromCache(name, sourceHash, result.vertSource, result.fragSource); + if (!shader) { + E2D_LOG_DEBUG("No valid cache found, compiling shader from source: {}", + name); + shader = + factory_->createFromSource(name, result.vertSource, result.fragSource); if (!shader) { - E2D_LOG_DEBUG("No valid cache found, compiling shader from source: {}", name); - shader = factory_->createFromSource(name, result.vertSource, result.fragSource); - if (!shader) { - E2D_LOG_ERROR("Failed to create shader from source: {}", name); - return nullptr; - } - - std::vector binary; - if (factory_->getShaderBinary(*shader, binary)) { - E2D_LOG_DEBUG("Got shader binary, size: {} bytes", binary.size()); - ShaderCacheEntry entry; - entry.name = name; - entry.sourceHash = sourceHash; - entry.binary = binary; - entry.dependencies = result.dependencies; - ShaderCache::getInstance().saveCache(entry); - } else { - E2D_LOG_WARN("Failed to get shader binary for: {}", name); - } + E2D_LOG_ERROR("Failed to create shader from source: {}", name); + return nullptr; } - ShaderInfo info; - info.shader = shader; - info.vertSource = result.vertSource; - info.fragSource = result.fragSource; - info.filePaths = {path}; - info.filePaths.insert(info.filePaths.end(), result.dependencies.begin(), result.dependencies.end()); - info.metadata = metadata; - - shaders_[name] = std::move(info); - - if (hotReloadEnabled_ && hotReloadSupported_) { - auto callback = [this, name](const FileChangeEvent& event) { - this->handleFileChange(name, event); - }; - ShaderHotReloader::getInstance().watch(name, shaders_[name].filePaths, callback); + std::vector binary; + if (factory_->getShaderBinary(*shader, binary)) { + E2D_LOG_DEBUG("Got shader binary, size: {} bytes", binary.size()); + ShaderCacheEntry entry; + entry.name = name; + entry.sourceHash = sourceHash; + entry.binary = binary; + entry.dependencies = result.dependencies; + ShaderCache::getInstance().saveCache(entry); + } else { + E2D_LOG_WARN("Failed to get shader binary for: {}", name); } + } - E2D_LOG_DEBUG("Shader loaded from combined file: {}", name); - return shader; + ShaderInfo info; + info.shader = shader; + info.vertSource = result.vertSource; + info.fragSource = result.fragSource; + info.filePaths = {path}; + info.filePaths.insert(info.filePaths.end(), result.dependencies.begin(), + result.dependencies.end()); + info.metadata = metadata; + + shaders_[name] = std::move(info); + + if (hotReloadEnabled_ && hotReloadSupported_) { + auto callback = [this, name](const FileChangeEvent &event) { + this->handleFileChange(name, event); + }; + ShaderHotReloader::getInstance().watch(name, shaders_[name].filePaths, + callback); + } + + E2D_LOG_DEBUG("Shader loaded from combined file: {}", name); + return shader; } /** @@ -272,35 +289,36 @@ Ptr ShaderManager::loadFromCombinedFile(const std::string& path) { * @param fragSource 片段着色器源码 * @return 加载的Shader实例 */ -Ptr ShaderManager::loadFromSource(const std::string& name, - const std::string& vertSource, - const std::string& fragSource) { - if (!initialized_) { - E2D_LOG_ERROR("ShaderManager not initialized"); - return nullptr; - } +Ptr ShaderManager::loadFromSource(const std::string &name, + const std::string &vertSource, + const std::string &fragSource) { + if (!initialized_) { + E2D_LOG_ERROR("ShaderManager not initialized"); + return nullptr; + } - auto it = shaders_.find(name); - if (it != shaders_.end()) { - return it->second.shader; - } + auto it = shaders_.find(name); + if (it != shaders_.end()) { + return it->second.shader; + } - Ptr shader = factory_->createFromSource(name, vertSource, fragSource); - if (!shader) { - E2D_LOG_ERROR("Failed to create shader from source: {}", name); - return nullptr; - } + Ptr shader = + factory_->createFromSource(name, vertSource, fragSource); + if (!shader) { + E2D_LOG_ERROR("Failed to create shader from source: {}", name); + return nullptr; + } - ShaderInfo info; - info.shader = shader; - info.vertSource = vertSource; - info.fragSource = fragSource; - info.metadata.name = name; + ShaderInfo info; + info.shader = shader; + info.vertSource = vertSource; + info.fragSource = fragSource; + info.metadata.name = name; - shaders_[name] = std::move(info); + shaders_[name] = std::move(info); - E2D_LOG_DEBUG("Shader loaded from source: {}", name); - return shader; + E2D_LOG_DEBUG("Shader loaded from source: {}", name); + return shader; } /** @@ -308,12 +326,12 @@ Ptr ShaderManager::loadFromSource(const std::string& name, * @param name Shader名称 * @return Shader实例,不存在返回nullptr */ -Ptr ShaderManager::get(const std::string& name) const { - auto it = shaders_.find(name); - if (it != shaders_.end()) { - return it->second.shader; - } - return nullptr; +Ptr ShaderManager::get(const std::string &name) const { + auto it = shaders_.find(name); + if (it != shaders_.end()) { + return it->second.shader; + } + return nullptr; } /** @@ -321,34 +339,34 @@ Ptr ShaderManager::get(const std::string& name) const { * @param name Shader名称 * @return 存在返回true,否则返回false */ -bool ShaderManager::has(const std::string& name) const { - return shaders_.find(name) != shaders_.end(); +bool ShaderManager::has(const std::string &name) const { + return shaders_.find(name) != shaders_.end(); } /** * @brief 移除Shader * @param name Shader名称 */ -void ShaderManager::remove(const std::string& name) { - auto it = shaders_.find(name); - if (it != shaders_.end()) { - ShaderHotReloader::getInstance().unwatch(name); - shaders_.erase(it); - E2D_LOG_DEBUG("Shader removed: {}", name); - } +void ShaderManager::remove(const std::string &name) { + auto it = shaders_.find(name); + if (it != shaders_.end()) { + ShaderHotReloader::getInstance().unwatch(name); + shaders_.erase(it); + E2D_LOG_DEBUG("Shader removed: {}", name); + } } /** * @brief 清除所有Shader */ void ShaderManager::clear() { - if (hotReloadSupported_) { - for (const auto& pair : shaders_) { - ShaderHotReloader::getInstance().unwatch(pair.first); - } + if (hotReloadSupported_) { + for (const auto &pair : shaders_) { + ShaderHotReloader::getInstance().unwatch(pair.first); } - shaders_.clear(); - E2D_LOG_DEBUG("All shaders cleared"); + } + shaders_.clear(); + E2D_LOG_DEBUG("All shaders cleared"); } /** @@ -356,11 +374,12 @@ void ShaderManager::clear() { * @param name Shader名称 * @param callback 重载回调函数 */ -void ShaderManager::setReloadCallback(const std::string& name, ShaderReloadCallback callback) { - auto it = shaders_.find(name); - if (it != shaders_.end()) { - it->second.reloadCallback = callback; - } +void ShaderManager::setReloadCallback(const std::string &name, + ShaderReloadCallback callback) { + auto it = shaders_.find(name); + if (it != shaders_.end()) { + it->second.reloadCallback = callback; + } } /** @@ -368,13 +387,13 @@ void ShaderManager::setReloadCallback(const std::string& name, ShaderReloadCallb * @param enabled 是否启用 */ void ShaderManager::setHotReloadEnabled(bool enabled) { - if (!hotReloadSupported_) { - E2D_LOG_WARN("Hot reload not supported on this platform"); - return; - } - hotReloadEnabled_ = enabled; - ShaderHotReloader::getInstance().setEnabled(enabled); - E2D_LOG_INFO("Hot reload {}", enabled ? "enabled" : "disabled"); + if (!hotReloadSupported_) { + E2D_LOG_WARN("Hot reload not supported on this platform"); + return; + } + hotReloadEnabled_ = enabled; + ShaderHotReloader::getInstance().setEnabled(enabled); + E2D_LOG_INFO("Hot reload {}", enabled ? "enabled" : "disabled"); } /** @@ -382,16 +401,16 @@ void ShaderManager::setHotReloadEnabled(bool enabled) { * @return 启用返回true,否则返回false */ bool ShaderManager::isHotReloadEnabled() const { - return hotReloadEnabled_ && hotReloadSupported_; + return hotReloadEnabled_ && hotReloadSupported_; } /** * @brief 更新热重载系统(主循环调用) */ void ShaderManager::update() { - if (hotReloadEnabled_ && hotReloadSupported_) { - ShaderHotReloader::getInstance().update(); - } + if (hotReloadEnabled_ && hotReloadSupported_) { + ShaderHotReloader::getInstance().update(); + } } /** @@ -399,48 +418,51 @@ void ShaderManager::update() { * @param name Shader名称 * @return 重载成功返回true,失败返回false */ -bool ShaderManager::reload(const std::string& name) { - auto it = shaders_.find(name); - if (it == shaders_.end()) { - E2D_LOG_WARN("Shader not found for reload: {}", name); - return false; +bool ShaderManager::reload(const std::string &name) { + auto it = shaders_.find(name); + if (it == shaders_.end()) { + E2D_LOG_WARN("Shader not found for reload: {}", name); + return false; + } + + ShaderInfo &info = it->second; + + std::string vertSource = info.vertSource; + std::string fragSource = info.fragSource; + + if (!info.metadata.vertPath.empty() && !info.metadata.fragPath.empty()) { + ShaderLoadResult result = loader_.loadFromSeparateFiles( + name, info.metadata.vertPath, info.metadata.fragPath); + if (result.success) { + vertSource = result.vertSource; + fragSource = result.fragSource; } - - ShaderInfo& info = it->second; - - std::string vertSource = info.vertSource; - std::string fragSource = info.fragSource; - - if (!info.metadata.vertPath.empty() && !info.metadata.fragPath.empty()) { - ShaderLoadResult result = loader_.loadFromSeparateFiles(name, info.metadata.vertPath, info.metadata.fragPath); - if (result.success) { - vertSource = result.vertSource; - fragSource = result.fragSource; - } - } else if (!info.metadata.combinedPath.empty()) { - ShaderLoadResult result = loader_.loadFromCombinedFile(info.metadata.combinedPath); - if (result.success) { - vertSource = result.vertSource; - fragSource = result.fragSource; - } + } else if (!info.metadata.combinedPath.empty()) { + ShaderLoadResult result = + loader_.loadFromCombinedFile(info.metadata.combinedPath); + if (result.success) { + vertSource = result.vertSource; + fragSource = result.fragSource; } + } - Ptr newShader = factory_->createFromSource(name, vertSource, fragSource); - if (!newShader) { - E2D_LOG_ERROR("Failed to reload shader: {}", name); - return false; - } + Ptr newShader = + factory_->createFromSource(name, vertSource, fragSource); + if (!newShader) { + E2D_LOG_ERROR("Failed to reload shader: {}", name); + return false; + } - info.shader = newShader; - info.vertSource = vertSource; - info.fragSource = fragSource; + info.shader = newShader; + info.vertSource = vertSource; + info.fragSource = fragSource; - if (info.reloadCallback) { - info.reloadCallback(newShader); - } + if (info.reloadCallback) { + info.reloadCallback(newShader); + } - E2D_LOG_INFO("Shader reloaded: {}", name); - return true; + E2D_LOG_INFO("Shader reloaded: {}", name); + return true; } /** @@ -448,21 +470,21 @@ bool ShaderManager::reload(const std::string& name) { * @param name 内置Shader名称 * @return Shader实例 */ -Ptr ShaderManager::getBuiltin(const std::string& name) { - Ptr shader = get(name); - if (shader) { - return shader; - } +Ptr ShaderManager::getBuiltin(const std::string &name) { + Ptr shader = get(name); + if (shader) { + return shader; + } - // 尝试从新的多后端JSON元数据加载 - std::string jsonPath = shaderDir_ + "shared/builtin/" + name + ".json"; - if (loader_.fileExists(jsonPath)) { - return loadFromMetadata(jsonPath, name); - } + // 尝试从新的多后端JSON元数据加载 + std::string jsonPath = shaderDir_ + "shared/builtin/" + name + ".json"; + if (loader_.fileExists(jsonPath)) { + return loadFromMetadata(jsonPath, name); + } - // 回退到旧的组合文件格式 - std::string path = shaderDir_ + "builtin/" + name + ".shader"; - return loadFromCombinedFile(path); + // 回退到旧的组合文件格式 + std::string path = shaderDir_ + "builtin/" + name + ".shader"; + return loadFromCombinedFile(path); } /** @@ -471,57 +493,60 @@ Ptr ShaderManager::getBuiltin(const std::string& name) { * @param name Shader名称 * @return 加载的Shader实例 */ -Ptr ShaderManager::loadFromMetadata(const std::string& jsonPath, const std::string& name) { - if (!initialized_) { - E2D_LOG_ERROR("ShaderManager not initialized"); - return nullptr; +Ptr ShaderManager::loadFromMetadata(const std::string &jsonPath, + const std::string &name) { + if (!initialized_) { + E2D_LOG_ERROR("ShaderManager not initialized"); + return nullptr; + } + + // 检查是否已加载 + auto it = shaders_.find(name); + if (it != shaders_.end()) { + return it->second.shader; + } + + // 读取JSON文件 + std::string jsonContent = loader_.readFile(jsonPath); + if (jsonContent.empty()) { + E2D_LOG_ERROR("Failed to read shader metadata: {}", jsonPath); + return nullptr; + } + + try { + // 使用nlohmann/json解析 + nl::json j = nl::json::parse(jsonContent); + + // 获取OpenGL后端路径 + if (!j.contains("backends") || !j["backends"].contains("opengl")) { + E2D_LOG_ERROR("No OpenGL backend found in shader metadata: {}", jsonPath); + return nullptr; } - // 检查是否已加载 - auto it = shaders_.find(name); - if (it != shaders_.end()) { - return it->second.shader; + auto &opengl = j["backends"]["opengl"]; + if (!opengl.contains("vertex") || !opengl.contains("fragment")) { + E2D_LOG_ERROR("Missing vertex or fragment path in shader metadata: {}", + jsonPath); + return nullptr; } - // 读取JSON文件 - std::string jsonContent = loader_.readFile(jsonPath); - if (jsonContent.empty()) { - E2D_LOG_ERROR("Failed to read shader metadata: {}", jsonPath); - return nullptr; - } + std::string vertRelativePath = opengl["vertex"].get(); + std::string fragRelativePath = opengl["fragment"].get(); - try { - // 使用nlohmann/json解析 - nl::json j = nl::json::parse(jsonContent); + // 构建完整路径 + std::string vertPath = shaderDir_ + vertRelativePath; + std::string fragPath = shaderDir_ + fragRelativePath; - // 获取OpenGL后端路径 - if (!j.contains("backends") || !j["backends"].contains("opengl")) { - E2D_LOG_ERROR("No OpenGL backend found in shader metadata: {}", jsonPath); - return nullptr; - } + E2D_LOG_DEBUG("Loading shader from metadata: {} -> vert: {}, frag: {}", + name, vertPath, fragPath); - auto& opengl = j["backends"]["opengl"]; - if (!opengl.contains("vertex") || !opengl.contains("fragment")) { - E2D_LOG_ERROR("Missing vertex or fragment path in shader metadata: {}", jsonPath); - return nullptr; - } + // 使用分离文件加载 + return loadFromFiles(name, vertPath, fragPath); - std::string vertRelativePath = opengl["vertex"].get(); - std::string fragRelativePath = opengl["fragment"].get(); - - // 构建完整路径 - std::string vertPath = shaderDir_ + vertRelativePath; - std::string fragPath = shaderDir_ + fragRelativePath; - - E2D_LOG_DEBUG("Loading shader from metadata: {} -> vert: {}, frag: {}", name, vertPath, fragPath); - - // 使用分离文件加载 - return loadFromFiles(name, vertPath, fragPath); - - } catch (const nl::json::exception& e) { - E2D_LOG_ERROR("Failed to parse shader metadata {}: {}", jsonPath, e.what()); - return nullptr; - } + } catch (const nl::json::exception &e) { + E2D_LOG_ERROR("Failed to parse shader metadata {}: {}", jsonPath, e.what()); + return nullptr; + } } /** @@ -529,52 +554,47 @@ Ptr ShaderManager::loadFromMetadata(const std::string& jsonPath, const * @return 加载成功返回true,失败返回false */ bool ShaderManager::loadBuiltinShaders() { - if (!initialized_) { - E2D_LOG_ERROR("ShaderManager not initialized"); - return false; + if (!initialized_) { + E2D_LOG_ERROR("ShaderManager not initialized"); + return false; + } + + bool allSuccess = true; + + const char *builtinNames[] = {"sprite", "particle", "shape", "postprocess", + "font"}; + + for (const char *name : builtinNames) { + // 首先尝试新的多后端JSON格式 + std::string jsonPath = shaderDir_ + "shared/builtin/" + name + ".json"; + std::string shaderName = std::string("builtin_") + name; + + Ptr shader = nullptr; + if (loader_.fileExists(jsonPath)) { + shader = loadFromMetadata(jsonPath, name); + } else { + // 回退到旧的组合文件格式 + std::string path = shaderDir_ + "builtin/" + name + ".shader"; + shader = loadFromCombinedFile(path); } - bool allSuccess = true; - - const char* builtinNames[] = { - "sprite", - "particle", - "shape", - "postprocess", - "font" - }; - - for (const char* name : builtinNames) { - // 首先尝试新的多后端JSON格式 - std::string jsonPath = shaderDir_ + "shared/builtin/" + name + ".json"; - std::string shaderName = std::string("builtin_") + name; - - Ptr shader = nullptr; - if (loader_.fileExists(jsonPath)) { - shader = loadFromMetadata(jsonPath, name); - } else { - // 回退到旧的组合文件格式 - std::string path = shaderDir_ + "builtin/" + name + ".shader"; - shader = loadFromCombinedFile(path); - } - - if (!shader) { - E2D_LOG_ERROR("Failed to load builtin {} shader", name); - allSuccess = false; - } else { - // 同时注册带 builtin_ 前缀的名称 - auto it = shaders_.find(name); - if (it != shaders_.end()) { - shaders_[shaderName] = it->second; - } - } + if (!shader) { + E2D_LOG_ERROR("Failed to load builtin {} shader", name); + allSuccess = false; + } else { + // 同时注册带 builtin_ 前缀的名称 + auto it = shaders_.find(name); + if (it != shaders_.end()) { + shaders_[shaderName] = it->second; + } } + } - if (allSuccess) { - E2D_LOG_INFO("All builtin shaders loaded"); - } + if (allSuccess) { + E2D_LOG_INFO("All builtin shaders loaded"); + } - return allSuccess; + return allSuccess; } /** @@ -585,29 +605,29 @@ bool ShaderManager::loadBuiltinShaders() { * @param fragSource 片段着色器源码 * @return Shader实例 */ -Ptr ShaderManager::loadFromCache(const std::string& name, - const std::string& sourceHash, - const std::string& vertSource, - const std::string& fragSource) { - if (!ShaderCache::getInstance().isInitialized()) { - return nullptr; - } +Ptr ShaderManager::loadFromCache(const std::string &name, + const std::string &sourceHash, + const std::string &vertSource, + const std::string &fragSource) { + if (!ShaderCache::getInstance().isInitialized()) { + return nullptr; + } - if (!ShaderCache::getInstance().hasValidCache(name, sourceHash)) { - return nullptr; - } + if (!ShaderCache::getInstance().hasValidCache(name, sourceHash)) { + return nullptr; + } - Ptr entry = ShaderCache::getInstance().loadCache(name); - if (!entry || entry->binary.empty()) { - return nullptr; - } + Ptr entry = ShaderCache::getInstance().loadCache(name); + if (!entry || entry->binary.empty()) { + return nullptr; + } - Ptr shader = factory_->createFromBinary(name, entry->binary); - if (shader) { - E2D_LOG_DEBUG("Shader loaded from cache: {}", name); - } + Ptr shader = factory_->createFromBinary(name, entry->binary); + if (shader) { + E2D_LOG_DEBUG("Shader loaded from cache: {}", name); + } - return shader; + return shader; } /** @@ -615,9 +635,10 @@ Ptr ShaderManager::loadFromCache(const std::string& name, * @param shaderName Shader名称 * @param event 文件变化事件 */ -void ShaderManager::handleFileChange(const std::string& shaderName, const FileChangeEvent& event) { - E2D_LOG_DEBUG("Shader file changed: {} -> {}", shaderName, event.filepath); - reload(shaderName); +void ShaderManager::handleFileChange(const std::string &shaderName, + const FileChangeEvent &event) { + E2D_LOG_DEBUG("Shader file changed: {} -> {}", shaderName, event.filepath); + reload(shaderName); } } // namespace extra2d diff --git a/Extra2D/src/graphics/shader/shader_preset.cpp b/Extra2D/src/graphics/shader/shader_preset.cpp index 8f3d227..e86cb3a 100644 --- a/Extra2D/src/graphics/shader/shader_preset.cpp +++ b/Extra2D/src/graphics/shader/shader_preset.cpp @@ -1,6 +1,8 @@ +#include #include #include -#include +#include + namespace extra2d { diff --git a/Extra2D/src/graphics/texture/texture_atlas.cpp b/Extra2D/src/graphics/texture/texture_atlas.cpp index 5348c05..5bf5cfa 100644 --- a/Extra2D/src/graphics/texture/texture_atlas.cpp +++ b/Extra2D/src/graphics/texture/texture_atlas.cpp @@ -1,7 +1,6 @@ +#include #include -#include -#include -#include +#include namespace extra2d { @@ -21,10 +20,10 @@ TextureAtlasPage::TextureAtlasPage(int width, int height) // 创建空白纹理 std::vector emptyData(width * height * 4, 0); texture_ = makePtr(width, height, emptyData.data(), 4); - + // 初始化矩形打包根节点 root_ = std::make_unique(0, 0, width, height); - + E2D_LOG_INFO("Created texture atlas page: {}x{}", width, height); } @@ -46,53 +45,56 @@ TextureAtlasPage::~TextureAtlasPage() = default; * * 尝试将纹理添加到图集页面中,使用矩形打包算法找到合适位置 */ -bool TextureAtlasPage::tryAddTexture(const std::string& name, int texWidth, int texHeight, - const uint8_t* pixels, Rect& outUvRect) { +bool TextureAtlasPage::tryAddTexture(const std::string &name, int texWidth, + int texHeight, const uint8_t *pixels, + Rect &outUvRect) { if (isFull_) { return false; } - + // 添加边距 int paddedWidth = texWidth + 2 * PADDING; int paddedHeight = texHeight + 2 * PADDING; - + // 如果纹理太大,无法放入 if (paddedWidth > width_ || paddedHeight > height_) { return false; } - + // 尝试插入 - PackNode* node = insert(root_.get(), paddedWidth, paddedHeight); + PackNode *node = insert(root_.get(), paddedWidth, paddedHeight); if (node == nullptr) { // 无法放入,标记为满 isFull_ = true; return false; } - + // 写入像素数据(跳过边距区域) - writePixels(node->x + PADDING, node->y + PADDING, texWidth, texHeight, pixels); - + writePixels(node->x + PADDING, node->y + PADDING, texWidth, texHeight, + pixels); + // 创建条目 AtlasEntry entry; entry.name = name; - entry.originalSize = Vec2(static_cast(texWidth), static_cast(texHeight)); + entry.originalSize = + Vec2(static_cast(texWidth), static_cast(texHeight)); entry.padding = PADDING; - + // 计算 UV 坐标(考虑边距) float u1 = static_cast(node->x + PADDING) / width_; float v1 = static_cast(node->y + PADDING) / height_; float u2 = static_cast(node->x + PADDING + texWidth) / width_; float v2 = static_cast(node->y + PADDING + texHeight) / height_; - + entry.uvRect = Rect(u1, v1, u2 - u1, v2 - v1); outUvRect = entry.uvRect; - + entries_[name] = std::move(entry); usedArea_ += paddedWidth * paddedHeight; - - E2D_LOG_DEBUG("Added texture '{}' to atlas: {}x{} at ({}, {})", - name, texWidth, texHeight, node->x, node->y); - + + E2D_LOG_DEBUG("Added texture '{}' to atlas: {}x{} at ({}, {})", name, + texWidth, texHeight, node->x, node->y); + return true; } @@ -105,45 +107,50 @@ bool TextureAtlasPage::tryAddTexture(const std::string& name, int texWidth, int * * 使用二叉树算法递归查找合适的空间位置 */ -TextureAtlasPage::PackNode* TextureAtlasPage::insert(PackNode* node, int width, int height) { +TextureAtlasPage::PackNode *TextureAtlasPage::insert(PackNode *node, int width, + int height) { if (node == nullptr) { return nullptr; } - + // 如果节点已被使用,尝试子节点 if (node->used) { - PackNode* result = insert(node->left.get(), width, height); + PackNode *result = insert(node->left.get(), width, height); if (result != nullptr) { return result; } return insert(node->right.get(), width, height); } - + // 检查是否适合 if (width > node->width || height > node->height) { return nullptr; } - + // 如果刚好合适,使用此节点 if (width == node->width && height == node->height) { node->used = true; return node; } - + // 需要分割节点 int dw = node->width - width; int dh = node->height - height; - + if (dw > dh) { // 水平分割 - node->left = std::make_unique(node->x, node->y, width, node->height); - node->right = std::make_unique(node->x + width, node->y, dw, node->height); + node->left = + std::make_unique(node->x, node->y, width, node->height); + node->right = + std::make_unique(node->x + width, node->y, dw, node->height); } else { // 垂直分割 - node->left = std::make_unique(node->x, node->y, node->width, height); - node->right = std::make_unique(node->x, node->y + height, node->width, dh); + node->left = + std::make_unique(node->x, node->y, node->width, height); + node->right = + std::make_unique(node->x, node->y + height, node->width, dh); } - + // 递归插入到左子节点 return insert(node->left.get(), width, height); } @@ -158,17 +165,19 @@ TextureAtlasPage::PackNode* TextureAtlasPage::insert(PackNode* node, int width, * * 使用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) { return; } - + // 使用 glTexSubImage2D 更新纹理数据 GLuint texID = static_cast( reinterpret_cast(texture_->getNativeHandle())); - + glBindTexture(GL_TEXTURE_2D, texID); - glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, + pixels); glBindTexture(GL_TEXTURE_2D, 0); } @@ -177,7 +186,7 @@ void TextureAtlasPage::writePixels(int x, int y, int w, int h, const uint8_t* pi * @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); if (it != entries_.end()) { return &it->second; @@ -205,11 +214,8 @@ float TextureAtlasPage::getUsageRatio() const { * 创建一个使用默认页面大小的纹理图集 */ TextureAtlas::TextureAtlas() - : pageSize_(TextureAtlasPage::DEFAULT_SIZE), - sizeThreshold_(256), - enabled_(true), - initialized_(false) { -} + : pageSize_(TextureAtlasPage::DEFAULT_SIZE), sizeThreshold_(256), + enabled_(true), initialized_(false) {} /** * @brief 析构函数 @@ -240,33 +246,33 @@ void TextureAtlas::init(int pageSize) { * * 尝试将纹理添加到现有页面,如空间不足则创建新页面 */ -bool TextureAtlas::addTexture(const std::string& name, int width, int height, - const uint8_t* pixels) { +bool TextureAtlas::addTexture(const std::string &name, int width, int height, + const uint8_t *pixels) { if (!enabled_ || !initialized_) { return false; } - + // 检查是否已存在 if (contains(name)) { return true; } - + // 检查纹理大小 if (width > sizeThreshold_ || height > sizeThreshold_) { - E2D_LOG_DEBUG("Texture '{}' too large for atlas ({}x{} > {}), skipping", + E2D_LOG_DEBUG("Texture '{}' too large for atlas ({}x{} > {}), skipping", name, width, height, sizeThreshold_); return false; } - + // 尝试添加到现有页面 Rect uvRect; - for (auto& page : pages_) { + for (auto &page : pages_) { if (page->tryAddTexture(name, width, height, pixels, uvRect)) { entryToPage_[name] = page.get(); return true; } } - + // 创建新页面 auto newPage = std::make_unique(pageSize_, pageSize_); if (newPage->tryAddTexture(name, width, height, pixels, uvRect)) { @@ -274,7 +280,7 @@ bool TextureAtlas::addTexture(const std::string& name, int width, int height, pages_.push_back(std::move(newPage)); return true; } - + E2D_LOG_WARN("Failed to add texture '{}' to atlas", name); return false; } @@ -284,7 +290,7 @@ bool TextureAtlas::addTexture(const std::string& name, int width, int height, * @param name 纹理名称 * @return 存在返回true,不存在返回false */ -bool TextureAtlas::contains(const std::string& name) const { +bool TextureAtlas::contains(const std::string &name) const { return entryToPage_.find(name) != entryToPage_.end(); } @@ -293,7 +299,7 @@ bool TextureAtlas::contains(const std::string& name) const { * @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); if (it != entryToPage_.end()) { return it->second->getTexture().get(); @@ -306,10 +312,10 @@ const Texture* TextureAtlas::getAtlasTexture(const std::string& name) const { * @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); if (it != entryToPage_.end()) { - const AtlasEntry* entry = it->second->getEntry(name); + const AtlasEntry *entry = it->second->getEntry(name); if (entry != nullptr) { return entry->uvRect; } @@ -322,10 +328,10 @@ Rect TextureAtlas::getUVRect(const std::string& name) const { * @param name 纹理名称 * @return 原始尺寸,未找到返回零向量 */ -Vec2 TextureAtlas::getOriginalSize(const std::string& name) const { +Vec2 TextureAtlas::getOriginalSize(const std::string &name) const { auto it = entryToPage_.find(name); if (it != entryToPage_.end()) { - const AtlasEntry* entry = it->second->getEntry(name); + const AtlasEntry *entry = it->second->getEntry(name); if (entry != nullptr) { return entry->originalSize; } @@ -343,9 +349,9 @@ float TextureAtlas::getTotalUsageRatio() const { if (pages_.empty()) { return 0.0f; } - + float total = 0.0f; - for (const auto& page : pages_) { + for (const auto &page : pages_) { total += page->getUsageRatio(); } return total / pages_.size(); @@ -372,7 +378,7 @@ void TextureAtlas::clear() { * * 使用静态局部变量实现线程安全的单例模式 */ -TextureAtlasMgr& TextureAtlasMgr::get() { +TextureAtlasMgr &TextureAtlasMgr::get() { static TextureAtlasMgr instance; return instance; } diff --git a/Extra2D/src/platform/backends/glfw/glfw_input.cpp b/Extra2D/src/platform/backends/glfw/glfw_input.cpp index 72605da..33b7da2 100644 --- a/Extra2D/src/platform/backends/glfw/glfw_input.cpp +++ b/Extra2D/src/platform/backends/glfw/glfw_input.cpp @@ -1,426 +1,492 @@ #include "glfw_input.h" -#include #include +#include +#include + namespace extra2d { // GLFW 按键到引擎按键的映射 static Key glfwToKey(int glfwKey) { - switch (glfwKey) { - // 字母键 - case GLFW_KEY_A: return Key::A; - case GLFW_KEY_B: return Key::B; - case GLFW_KEY_C: return Key::C; - case GLFW_KEY_D: return Key::D; - case GLFW_KEY_E: return Key::E; - case GLFW_KEY_F: return Key::F; - case GLFW_KEY_G: return Key::G; - case GLFW_KEY_H: return Key::H; - case GLFW_KEY_I: return Key::I; - case GLFW_KEY_J: return Key::J; - case GLFW_KEY_K: return Key::K; - case GLFW_KEY_L: return Key::L; - case GLFW_KEY_M: return Key::M; - case GLFW_KEY_N: return Key::N; - case GLFW_KEY_O: return Key::O; - case GLFW_KEY_P: return Key::P; - case GLFW_KEY_Q: return Key::Q; - case GLFW_KEY_R: return Key::R; - case GLFW_KEY_S: return Key::S; - case GLFW_KEY_T: return Key::T; - case GLFW_KEY_U: return Key::U; - case GLFW_KEY_V: return Key::V; - case GLFW_KEY_W: return Key::W; - case GLFW_KEY_X: return Key::X; - case GLFW_KEY_Y: return Key::Y; - case GLFW_KEY_Z: return Key::Z; - - // 数字键 - case GLFW_KEY_0: return Key::Num0; - case GLFW_KEY_1: return Key::Num1; - case GLFW_KEY_2: return Key::Num2; - case GLFW_KEY_3: return Key::Num3; - case GLFW_KEY_4: return Key::Num4; - case GLFW_KEY_5: return Key::Num5; - case GLFW_KEY_6: return Key::Num6; - case GLFW_KEY_7: return Key::Num7; - case GLFW_KEY_8: return Key::Num8; - case GLFW_KEY_9: return Key::Num9; - - // 功能键 - case GLFW_KEY_F1: return Key::F1; - case GLFW_KEY_F2: return Key::F2; - case GLFW_KEY_F3: return Key::F3; - case GLFW_KEY_F4: return Key::F4; - case GLFW_KEY_F5: return Key::F5; - case GLFW_KEY_F6: return Key::F6; - case GLFW_KEY_F7: return Key::F7; - case GLFW_KEY_F8: return Key::F8; - case GLFW_KEY_F9: return Key::F9; - case GLFW_KEY_F10: return Key::F10; - case GLFW_KEY_F11: return Key::F11; - case GLFW_KEY_F12: return Key::F12; - - // 特殊键 - case GLFW_KEY_SPACE: return Key::Space; - case GLFW_KEY_ENTER: return Key::Enter; - case GLFW_KEY_ESCAPE: return Key::Escape; - case GLFW_KEY_TAB: return Key::Tab; - case GLFW_KEY_BACKSPACE: return Key::Backspace; - case GLFW_KEY_INSERT: return Key::Insert; - case GLFW_KEY_DELETE: return Key::Delete; - case GLFW_KEY_HOME: return Key::Home; - case GLFW_KEY_END: return Key::End; - case GLFW_KEY_PAGE_UP: return Key::PageUp; - case GLFW_KEY_PAGE_DOWN: return Key::PageDown; - - // 方向键 - case GLFW_KEY_UP: return Key::Up; - case GLFW_KEY_DOWN: return Key::Down; - case GLFW_KEY_LEFT: return Key::Left; - case GLFW_KEY_RIGHT: return Key::Right; - - // 修饰键 - case GLFW_KEY_LEFT_SHIFT: return Key::LShift; - case GLFW_KEY_RIGHT_SHIFT: return Key::RShift; - case GLFW_KEY_LEFT_CONTROL: return Key::LCtrl; - case GLFW_KEY_RIGHT_CONTROL: return Key::RCtrl; - case GLFW_KEY_LEFT_ALT: return Key::LAlt; - case GLFW_KEY_RIGHT_ALT: return Key::RAlt; - - // 锁定键 - case GLFW_KEY_CAPS_LOCK: return Key::CapsLock; - case GLFW_KEY_NUM_LOCK: return Key::NumLock; - case GLFW_KEY_SCROLL_LOCK: return Key::ScrollLock; - - default: return Key::None; - } + switch (glfwKey) { + // 字母键 + case GLFW_KEY_A: + return Key::A; + case GLFW_KEY_B: + return Key::B; + case GLFW_KEY_C: + return Key::C; + case GLFW_KEY_D: + return Key::D; + case GLFW_KEY_E: + return Key::E; + case GLFW_KEY_F: + return Key::F; + case GLFW_KEY_G: + return Key::G; + case GLFW_KEY_H: + return Key::H; + case GLFW_KEY_I: + return Key::I; + case GLFW_KEY_J: + return Key::J; + case GLFW_KEY_K: + return Key::K; + case GLFW_KEY_L: + return Key::L; + case GLFW_KEY_M: + return Key::M; + case GLFW_KEY_N: + return Key::N; + case GLFW_KEY_O: + return Key::O; + case GLFW_KEY_P: + return Key::P; + case GLFW_KEY_Q: + return Key::Q; + case GLFW_KEY_R: + return Key::R; + case GLFW_KEY_S: + return Key::S; + case GLFW_KEY_T: + return Key::T; + case GLFW_KEY_U: + return Key::U; + case GLFW_KEY_V: + return Key::V; + case GLFW_KEY_W: + return Key::W; + case GLFW_KEY_X: + return Key::X; + case GLFW_KEY_Y: + return Key::Y; + case GLFW_KEY_Z: + return Key::Z; + + // 数字键 + case GLFW_KEY_0: + return Key::Num0; + case GLFW_KEY_1: + return Key::Num1; + case GLFW_KEY_2: + return Key::Num2; + case GLFW_KEY_3: + return Key::Num3; + case GLFW_KEY_4: + return Key::Num4; + case GLFW_KEY_5: + return Key::Num5; + case GLFW_KEY_6: + return Key::Num6; + case GLFW_KEY_7: + return Key::Num7; + case GLFW_KEY_8: + return Key::Num8; + case GLFW_KEY_9: + return Key::Num9; + + // 功能键 + case GLFW_KEY_F1: + return Key::F1; + case GLFW_KEY_F2: + return Key::F2; + case GLFW_KEY_F3: + return Key::F3; + case GLFW_KEY_F4: + return Key::F4; + case GLFW_KEY_F5: + return Key::F5; + case GLFW_KEY_F6: + return Key::F6; + case GLFW_KEY_F7: + return Key::F7; + case GLFW_KEY_F8: + return Key::F8; + case GLFW_KEY_F9: + return Key::F9; + case GLFW_KEY_F10: + return Key::F10; + case GLFW_KEY_F11: + return Key::F11; + case GLFW_KEY_F12: + return Key::F12; + + // 特殊键 + case GLFW_KEY_SPACE: + return Key::Space; + case GLFW_KEY_ENTER: + return Key::Enter; + case GLFW_KEY_ESCAPE: + return Key::Escape; + case GLFW_KEY_TAB: + return Key::Tab; + case GLFW_KEY_BACKSPACE: + return Key::Backspace; + case GLFW_KEY_INSERT: + return Key::Insert; + case GLFW_KEY_DELETE: + return Key::Delete; + case GLFW_KEY_HOME: + return Key::Home; + case GLFW_KEY_END: + return Key::End; + case GLFW_KEY_PAGE_UP: + return Key::PageUp; + case GLFW_KEY_PAGE_DOWN: + return Key::PageDown; + + // 方向键 + case GLFW_KEY_UP: + return Key::Up; + case GLFW_KEY_DOWN: + return Key::Down; + case GLFW_KEY_LEFT: + return Key::Left; + case GLFW_KEY_RIGHT: + return Key::Right; + + // 修饰键 + case GLFW_KEY_LEFT_SHIFT: + return Key::LShift; + case GLFW_KEY_RIGHT_SHIFT: + return Key::RShift; + case GLFW_KEY_LEFT_CONTROL: + return Key::LCtrl; + case GLFW_KEY_RIGHT_CONTROL: + return Key::RCtrl; + case GLFW_KEY_LEFT_ALT: + return Key::LAlt; + case GLFW_KEY_RIGHT_ALT: + return Key::RAlt; + + // 锁定键 + case GLFW_KEY_CAPS_LOCK: + return Key::CapsLock; + case GLFW_KEY_NUM_LOCK: + return Key::NumLock; + case GLFW_KEY_SCROLL_LOCK: + return Key::ScrollLock; + + default: + return Key::None; + } } GLFWInput::GLFWInput() { - keyCurrent_.fill(false); - keyPrevious_.fill(false); - mouseCurrent_.fill(false); - mousePrevious_.fill(false); - gamepadCurrent_.fill(false); - gamepadPrevious_.fill(false); + keyCurrent_.fill(false); + keyPrevious_.fill(false); + mouseCurrent_.fill(false); + mousePrevious_.fill(false); + gamepadCurrent_.fill(false); + gamepadPrevious_.fill(false); } -GLFWInput::~GLFWInput() { - shutdown(); -} +GLFWInput::~GLFWInput() { shutdown(); } void GLFWInput::init() { - E2D_LOG_INFO("GLFWInput initialized"); - openGamepad(); + E2D_LOG_INFO("GLFWInput initialized"); + openGamepad(); } void GLFWInput::shutdown() { - closeGamepad(); - E2D_LOG_INFO("GLFWInput shutdown"); + closeGamepad(); + E2D_LOG_INFO("GLFWInput shutdown"); } void GLFWInput::update() { - // 保存上一帧状态 - keyPrevious_ = keyCurrent_; - mousePrevious_ = mouseCurrent_; - gamepadPrevious_ = gamepadCurrent_; - - // 重置增量 - scrollDelta_ = 0.0f; - mouseDelta_ = Vec2{0.0f, 0.0f}; - - // 更新游戏手柄 - updateGamepad(); - - // 更新键盘状态(通过轮询 GLFW) - if (window_) { - for (int i = GLFW_KEY_SPACE; i <= GLFW_KEY_LAST; ++i) { - Key key = glfwToKey(i); - if (key != Key::None) { - int state = glfwGetKey(window_, i); - keyCurrent_[static_cast(key)] = (state == GLFW_PRESS); - } - } - - // 更新鼠标按钮状态 - for (int i = 0; i < static_cast(Mouse::Count); ++i) { - int glfwButton = GLFW_MOUSE_BUTTON_1 + i; - if (glfwButton <= GLFW_MOUSE_BUTTON_LAST) { - int state = glfwGetMouseButton(window_, glfwButton); - mouseCurrent_[i] = (state == GLFW_PRESS); - } - } - - // 获取鼠标位置 - double x, y; - glfwGetCursorPos(window_, &x, &y); - mousePos_ = Vec2{static_cast(x), static_cast(y)}; + // 保存上一帧状态 + keyPrevious_ = keyCurrent_; + mousePrevious_ = mouseCurrent_; + gamepadPrevious_ = gamepadCurrent_; + + // 重置增量 + scrollDelta_ = 0.0f; + mouseDelta_ = Vec2{0.0f, 0.0f}; + + // 更新游戏手柄 + updateGamepad(); + + // 更新键盘状态(通过轮询 GLFW) + if (window_) { + for (int i = GLFW_KEY_SPACE; i <= GLFW_KEY_LAST; ++i) { + Key key = glfwToKey(i); + if (key != Key::None) { + int state = glfwGetKey(window_, i); + keyCurrent_[static_cast(key)] = (state == GLFW_PRESS); + } } + + // 更新鼠标按钮状态 + for (int i = 0; i < static_cast(Mouse::Count); ++i) { + int glfwButton = GLFW_MOUSE_BUTTON_1 + i; + if (glfwButton <= GLFW_MOUSE_BUTTON_LAST) { + int state = glfwGetMouseButton(window_, glfwButton); + mouseCurrent_[i] = (state == GLFW_PRESS); + } + } + + // 获取鼠标位置 + double x, y; + glfwGetCursorPos(window_, &x, &y); + mousePos_ = Vec2{static_cast(x), static_cast(y)}; + } } bool GLFWInput::down(Key key) const { - size_t idx = static_cast(key); - if (idx < keyCurrent_.size()) { - return keyCurrent_[idx]; - } - return false; + size_t idx = static_cast(key); + if (idx < keyCurrent_.size()) { + return keyCurrent_[idx]; + } + return false; } bool GLFWInput::pressed(Key key) const { - size_t idx = static_cast(key); - if (idx < keyCurrent_.size()) { - return keyCurrent_[idx] && !keyPrevious_[idx]; - } - return false; + size_t idx = static_cast(key); + if (idx < keyCurrent_.size()) { + return keyCurrent_[idx] && !keyPrevious_[idx]; + } + return false; } bool GLFWInput::released(Key key) const { - size_t idx = static_cast(key); - if (idx < keyCurrent_.size()) { - return !keyCurrent_[idx] && keyPrevious_[idx]; - } - return false; + size_t idx = static_cast(key); + if (idx < keyCurrent_.size()) { + return !keyCurrent_[idx] && keyPrevious_[idx]; + } + return false; } bool GLFWInput::down(Mouse btn) const { - size_t idx = static_cast(btn); - if (idx < mouseCurrent_.size()) { - return mouseCurrent_[idx]; - } - return false; + size_t idx = static_cast(btn); + if (idx < mouseCurrent_.size()) { + return mouseCurrent_[idx]; + } + return false; } bool GLFWInput::pressed(Mouse btn) const { - size_t idx = static_cast(btn); - if (idx < mouseCurrent_.size()) { - return mouseCurrent_[idx] && !mousePrevious_[idx]; - } - return false; + size_t idx = static_cast(btn); + if (idx < mouseCurrent_.size()) { + return mouseCurrent_[idx] && !mousePrevious_[idx]; + } + return false; } bool GLFWInput::released(Mouse btn) const { - size_t idx = static_cast(btn); - if (idx < mouseCurrent_.size()) { - return !mouseCurrent_[idx] && mousePrevious_[idx]; - } - return false; + size_t idx = static_cast(btn); + if (idx < mouseCurrent_.size()) { + return !mouseCurrent_[idx] && mousePrevious_[idx]; + } + return false; } -Vec2 GLFWInput::mouse() const { - return mousePos_; +Vec2 GLFWInput::mouse() const { return mousePos_; } + +Vec2 GLFWInput::mouseDelta() const { return mouseDelta_; } + +float GLFWInput::scroll() const { return scroll_; } + +float GLFWInput::scrollDelta() const { return scrollDelta_; } + +void GLFWInput::setMouse(const Vec2 &pos) { + if (window_) { + glfwSetCursorPos(window_, pos.x, pos.y); + } } -Vec2 GLFWInput::mouseDelta() const { - return mouseDelta_; -} - -float GLFWInput::scroll() const { - return scroll_; -} - -float GLFWInput::scrollDelta() const { - return scrollDelta_; -} - -void GLFWInput::setMouse(const Vec2& pos) { - if (window_) { - glfwSetCursorPos(window_, pos.x, pos.y); - } -} - -bool GLFWInput::gamepad() const { - return gamepadId_ != -1; -} +bool GLFWInput::gamepad() const { return gamepadId_ != -1; } bool GLFWInput::down(Gamepad btn) const { - size_t idx = static_cast(btn); - if (idx < gamepadCurrent_.size()) { - return gamepadCurrent_[idx]; - } - return false; + size_t idx = static_cast(btn); + if (idx < gamepadCurrent_.size()) { + return gamepadCurrent_[idx]; + } + return false; } bool GLFWInput::pressed(Gamepad btn) const { - size_t idx = static_cast(btn); - if (idx < gamepadCurrent_.size()) { - return gamepadCurrent_[idx] && !gamepadPrevious_[idx]; - } - return false; + size_t idx = static_cast(btn); + if (idx < gamepadCurrent_.size()) { + return gamepadCurrent_[idx] && !gamepadPrevious_[idx]; + } + return false; } bool GLFWInput::released(Gamepad btn) const { - size_t idx = static_cast(btn); - if (idx < gamepadCurrent_.size()) { - return !gamepadCurrent_[idx] && gamepadPrevious_[idx]; - } - return false; + size_t idx = static_cast(btn); + if (idx < gamepadCurrent_.size()) { + return !gamepadCurrent_[idx] && gamepadPrevious_[idx]; + } + return false; } -Vec2 GLFWInput::leftStick() const { - return leftStick_; -} +Vec2 GLFWInput::leftStick() const { return leftStick_; } -Vec2 GLFWInput::rightStick() const { - return rightStick_; -} +Vec2 GLFWInput::rightStick() const { return rightStick_; } -float GLFWInput::leftTrigger() const { - return leftTrigger_; -} +float GLFWInput::leftTrigger() const { return leftTrigger_; } -float GLFWInput::rightTrigger() const { - return rightTrigger_; -} +float GLFWInput::rightTrigger() const { return rightTrigger_; } void GLFWInput::vibrate(float left, float right) { - // GLFW 本身不支持震动,需要平台特定的代码 - // 这里可以扩展为使用平台特定的 API - (void)left; - (void)right; + // GLFW 本身不支持震动,需要平台特定的代码 + // 这里可以扩展为使用平台特定的 API + (void)left; + (void)right; } -bool GLFWInput::touching() const { - return false; -} +bool GLFWInput::touching() const { return false; } -int GLFWInput::touchCount() const { - return 0; -} +int GLFWInput::touchCount() const { return 0; } Vec2 GLFWInput::touch(int index) const { - (void)index; - return Vec2{0.0f, 0.0f}; + (void)index; + return Vec2{0.0f, 0.0f}; } TouchPoint GLFWInput::touchPoint(int index) const { - (void)index; - return TouchPoint{}; + (void)index; + return TouchPoint{}; } // 事件处理函数 void GLFWInput::handleKeyEvent(int key, int scancode, int action, int mods) { - (void)scancode; - (void)mods; - - Key eKey = glfwToKey(key); - if (eKey != Key::None) { - size_t idx = static_cast(eKey); - if (action == GLFW_PRESS) { - keyCurrent_[idx] = true; - } else if (action == GLFW_RELEASE) { - keyCurrent_[idx] = false; - } + (void)scancode; + (void)mods; + + Key eKey = glfwToKey(key); + if (eKey != Key::None) { + size_t idx = static_cast(eKey); + if (action == GLFW_PRESS) { + keyCurrent_[idx] = true; + } else if (action == GLFW_RELEASE) { + keyCurrent_[idx] = false; } + } } void GLFWInput::handleMouseButtonEvent(int button, int action, int mods) { - (void)mods; - - if (button >= GLFW_MOUSE_BUTTON_1 && button <= GLFW_MOUSE_BUTTON_LAST) { - size_t idx = static_cast(button - GLFW_MOUSE_BUTTON_1); - if (idx < mouseCurrent_.size()) { - if (action == GLFW_PRESS) { - mouseCurrent_[idx] = true; - } else if (action == GLFW_RELEASE) { - mouseCurrent_[idx] = false; - } - } + (void)mods; + + if (button >= GLFW_MOUSE_BUTTON_1 && button <= GLFW_MOUSE_BUTTON_LAST) { + size_t idx = static_cast(button - GLFW_MOUSE_BUTTON_1); + if (idx < mouseCurrent_.size()) { + if (action == GLFW_PRESS) { + mouseCurrent_[idx] = true; + } else if (action == GLFW_RELEASE) { + mouseCurrent_[idx] = false; + } } + } } void GLFWInput::handleCursorPosEvent(double xpos, double ypos) { - Vec2 newPos{static_cast(xpos), static_cast(ypos)}; - mouseDelta_ = newPos - mousePos_; - mousePos_ = newPos; + Vec2 newPos{static_cast(xpos), static_cast(ypos)}; + mouseDelta_ = newPos - mousePos_; + mousePos_ = newPos; } void GLFWInput::handleScrollEvent(double xoffset, double yoffset) { - (void)xoffset; - scroll_ += static_cast(yoffset); - scrollDelta_ += static_cast(yoffset); + (void)xoffset; + scroll_ += static_cast(yoffset); + scrollDelta_ += static_cast(yoffset); } void GLFWInput::handleJoystickEvent(int jid, int event) { - if (event == GLFW_CONNECTED) { - E2D_LOG_INFO("Gamepad connected: {}", jid); - if (gamepadId_ == -1) { - openGamepad(); - } - } else if (event == GLFW_DISCONNECTED) { - if (jid == gamepadId_) { - E2D_LOG_INFO("Gamepad disconnected: {}", jid); - closeGamepad(); - } + if (event == GLFW_CONNECTED) { + E2D_LOG_INFO("Gamepad connected: {}", jid); + if (gamepadId_ == -1) { + openGamepad(); } + } else if (event == GLFW_DISCONNECTED) { + if (jid == gamepadId_) { + E2D_LOG_INFO("Gamepad disconnected: {}", jid); + closeGamepad(); + } + } } void GLFWInput::updateGamepad() { - if (gamepadId_ == -1) { - return; - } - - GLFWgamepadstate state; - if (!glfwGetGamepadState(gamepadId_, &state)) { - return; - } - - // 更新按钮状态 - gamepadCurrent_[static_cast(Gamepad::A)] = state.buttons[GLFW_GAMEPAD_BUTTON_A] == GLFW_PRESS; - gamepadCurrent_[static_cast(Gamepad::B)] = state.buttons[GLFW_GAMEPAD_BUTTON_B] == GLFW_PRESS; - gamepadCurrent_[static_cast(Gamepad::X)] = state.buttons[GLFW_GAMEPAD_BUTTON_X] == GLFW_PRESS; - gamepadCurrent_[static_cast(Gamepad::Y)] = state.buttons[GLFW_GAMEPAD_BUTTON_Y] == GLFW_PRESS; - gamepadCurrent_[static_cast(Gamepad::Back)] = state.buttons[GLFW_GAMEPAD_BUTTON_BACK] == GLFW_PRESS; - gamepadCurrent_[static_cast(Gamepad::Start)] = state.buttons[GLFW_GAMEPAD_BUTTON_START] == GLFW_PRESS; - gamepadCurrent_[static_cast(Gamepad::LStick)] = state.buttons[GLFW_GAMEPAD_BUTTON_LEFT_THUMB] == GLFW_PRESS; - gamepadCurrent_[static_cast(Gamepad::RStick)] = state.buttons[GLFW_GAMEPAD_BUTTON_RIGHT_THUMB] == GLFW_PRESS; - gamepadCurrent_[static_cast(Gamepad::LB)] = state.buttons[GLFW_GAMEPAD_BUTTON_LEFT_BUMPER] == GLFW_PRESS; - gamepadCurrent_[static_cast(Gamepad::RB)] = state.buttons[GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER] == GLFW_PRESS; - gamepadCurrent_[static_cast(Gamepad::DUp)] = state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_UP] == GLFW_PRESS; - gamepadCurrent_[static_cast(Gamepad::DDown)] = state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_DOWN] == GLFW_PRESS; - gamepadCurrent_[static_cast(Gamepad::DLeft)] = state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_LEFT] == GLFW_PRESS; - gamepadCurrent_[static_cast(Gamepad::DRight)] = state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_RIGHT] == GLFW_PRESS; - gamepadCurrent_[static_cast(Gamepad::Guide)] = state.buttons[GLFW_GAMEPAD_BUTTON_GUIDE] == GLFW_PRESS; - - // 更新摇杆值(应用死区) - leftStick_.x = applyDeadzone(state.axes[GLFW_GAMEPAD_AXIS_LEFT_X]); - leftStick_.y = applyDeadzone(state.axes[GLFW_GAMEPAD_AXIS_LEFT_Y]); - rightStick_.x = applyDeadzone(state.axes[GLFW_GAMEPAD_AXIS_RIGHT_X]); - rightStick_.y = applyDeadzone(state.axes[GLFW_GAMEPAD_AXIS_RIGHT_Y]); - - // 更新扳机值(范围 [0, 1]) - leftTrigger_ = (state.axes[GLFW_GAMEPAD_AXIS_LEFT_TRIGGER] + 1.0f) * 0.5f; - rightTrigger_ = (state.axes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER] + 1.0f) * 0.5f; + if (gamepadId_ == -1) { + return; + } + + GLFWgamepadstate state; + if (!glfwGetGamepadState(gamepadId_, &state)) { + return; + } + + // 更新按钮状态 + gamepadCurrent_[static_cast(Gamepad::A)] = + state.buttons[GLFW_GAMEPAD_BUTTON_A] == GLFW_PRESS; + gamepadCurrent_[static_cast(Gamepad::B)] = + state.buttons[GLFW_GAMEPAD_BUTTON_B] == GLFW_PRESS; + gamepadCurrent_[static_cast(Gamepad::X)] = + state.buttons[GLFW_GAMEPAD_BUTTON_X] == GLFW_PRESS; + gamepadCurrent_[static_cast(Gamepad::Y)] = + state.buttons[GLFW_GAMEPAD_BUTTON_Y] == GLFW_PRESS; + gamepadCurrent_[static_cast(Gamepad::Back)] = + state.buttons[GLFW_GAMEPAD_BUTTON_BACK] == GLFW_PRESS; + gamepadCurrent_[static_cast(Gamepad::Start)] = + state.buttons[GLFW_GAMEPAD_BUTTON_START] == GLFW_PRESS; + gamepadCurrent_[static_cast(Gamepad::LStick)] = + state.buttons[GLFW_GAMEPAD_BUTTON_LEFT_THUMB] == GLFW_PRESS; + gamepadCurrent_[static_cast(Gamepad::RStick)] = + state.buttons[GLFW_GAMEPAD_BUTTON_RIGHT_THUMB] == GLFW_PRESS; + gamepadCurrent_[static_cast(Gamepad::LB)] = + state.buttons[GLFW_GAMEPAD_BUTTON_LEFT_BUMPER] == GLFW_PRESS; + gamepadCurrent_[static_cast(Gamepad::RB)] = + state.buttons[GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER] == GLFW_PRESS; + gamepadCurrent_[static_cast(Gamepad::DUp)] = + state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_UP] == GLFW_PRESS; + gamepadCurrent_[static_cast(Gamepad::DDown)] = + state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_DOWN] == GLFW_PRESS; + gamepadCurrent_[static_cast(Gamepad::DLeft)] = + state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_LEFT] == GLFW_PRESS; + gamepadCurrent_[static_cast(Gamepad::DRight)] = + state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_RIGHT] == GLFW_PRESS; + gamepadCurrent_[static_cast(Gamepad::Guide)] = + state.buttons[GLFW_GAMEPAD_BUTTON_GUIDE] == GLFW_PRESS; + + // 更新摇杆值(应用死区) + leftStick_.x = applyDeadzone(state.axes[GLFW_GAMEPAD_AXIS_LEFT_X]); + leftStick_.y = applyDeadzone(state.axes[GLFW_GAMEPAD_AXIS_LEFT_Y]); + rightStick_.x = applyDeadzone(state.axes[GLFW_GAMEPAD_AXIS_RIGHT_X]); + rightStick_.y = applyDeadzone(state.axes[GLFW_GAMEPAD_AXIS_RIGHT_Y]); + + // 更新扳机值(范围 [0, 1]) + leftTrigger_ = (state.axes[GLFW_GAMEPAD_AXIS_LEFT_TRIGGER] + 1.0f) * 0.5f; + rightTrigger_ = (state.axes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER] + 1.0f) * 0.5f; } void GLFWInput::openGamepad() { - for (int jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; ++jid) { - if (glfwJoystickPresent(jid) && glfwJoystickIsGamepad(jid)) { - gamepadId_ = jid; - E2D_LOG_INFO("Gamepad opened: {}", glfwGetGamepadName(jid)); - return; - } + for (int jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; ++jid) { + if (glfwJoystickPresent(jid) && glfwJoystickIsGamepad(jid)) { + gamepadId_ = jid; + E2D_LOG_INFO("Gamepad opened: {}", glfwGetGamepadName(jid)); + return; } + } } void GLFWInput::closeGamepad() { - if (gamepadId_ != -1) { - gamepadId_ = -1; - gamepadCurrent_.fill(false); - gamepadPrevious_.fill(false); - leftStick_ = Vec2{0.0f, 0.0f}; - rightStick_ = Vec2{0.0f, 0.0f}; - leftTrigger_ = 0.0f; - rightTrigger_ = 0.0f; - } + if (gamepadId_ != -1) { + gamepadId_ = -1; + gamepadCurrent_.fill(false); + gamepadPrevious_.fill(false); + leftStick_ = Vec2{0.0f, 0.0f}; + rightStick_ = Vec2{0.0f, 0.0f}; + leftTrigger_ = 0.0f; + rightTrigger_ = 0.0f; + } } float GLFWInput::applyDeadzone(float value) const { - if (std::abs(value) < deadzone_) { - return 0.0f; - } - float sign = value >= 0.0f ? 1.0f : -1.0f; - return sign * (std::abs(value) - deadzone_) / (1.0f - deadzone_); + if (std::abs(value) < deadzone_) { + return 0.0f; + } + float sign = value >= 0.0f ? 1.0f : -1.0f; + return sign * (std::abs(value) - deadzone_) / (1.0f - deadzone_); } } // namespace extra2d diff --git a/Extra2D/src/platform/backends/glfw/glfw_window.cpp b/Extra2D/src/platform/backends/glfw/glfw_window.cpp index 32057e8..74939f4 100644 --- a/Extra2D/src/platform/backends/glfw/glfw_window.cpp +++ b/Extra2D/src/platform/backends/glfw/glfw_window.cpp @@ -1,449 +1,441 @@ #include "glfw_window.h" #include "glfw_input.h" -#include +#include +#include #include + namespace extra2d { GLFWWindow::GLFWWindow() {} -GLFWWindow::~GLFWWindow() { - destroy(); -} +GLFWWindow::~GLFWWindow() { destroy(); } -bool GLFWWindow::create(const std::string& title, int width, int height, bool vsync) { - if (!initGLFW()) { - return false; - } +bool GLFWWindow::create(const std::string &title, int width, int height, + bool vsync) { + if (!initGLFW()) { + return false; + } - glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE); - glfwWindowHint(GLFW_DEPTH_BITS, 24); - glfwWindowHint(GLFW_STENCIL_BITS, 8); + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE); + glfwWindowHint(GLFW_DEPTH_BITS, 24); + glfwWindowHint(GLFW_STENCIL_BITS, 8); #ifdef __SWITCH__ - glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); - glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); - fullscreen_ = true; + glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); + fullscreen_ = true; #else - glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); #endif - GLFWmonitor* monitor = nullptr; + GLFWmonitor *monitor = nullptr; #ifdef __SWITCH__ - monitor = glfwGetPrimaryMonitor(); + monitor = glfwGetPrimaryMonitor(); #endif - glfwWindow_ = glfwCreateWindow( - width, height, - title.c_str(), - monitor, - nullptr - ); + glfwWindow_ = + glfwCreateWindow(width, height, title.c_str(), monitor, nullptr); - if (!glfwWindow_) { - E2D_LOG_ERROR("Failed to create GLFW window"); - deinitGLFW(); - return false; - } + if (!glfwWindow_) { + E2D_LOG_ERROR("Failed to create GLFW window"); + deinitGLFW(); + return false; + } #ifndef __SWITCH__ - if (!fullscreen_ && !monitor) { - GLFWmonitor* primaryMonitor = glfwGetPrimaryMonitor(); - if (primaryMonitor) { - const GLFWvidmode* mode = glfwGetVideoMode(primaryMonitor); - if (mode) { - int screenWidth = mode->width; - int screenHeight = mode->height; - int windowX = (screenWidth - width) / 2; - int windowY = (screenHeight - height) / 2; - glfwSetWindowPos(glfwWindow_, windowX, windowY); - } - } + if (!fullscreen_ && !monitor) { + GLFWmonitor *primaryMonitor = glfwGetPrimaryMonitor(); + if (primaryMonitor) { + const GLFWvidmode *mode = glfwGetVideoMode(primaryMonitor); + if (mode) { + int screenWidth = mode->width; + int screenHeight = mode->height; + int windowX = (screenWidth - width) / 2; + int windowY = (screenHeight - height) / 2; + glfwSetWindowPos(glfwWindow_, windowX, windowY); + } } + } #endif - glfwMakeContextCurrent(glfwWindow_); + glfwMakeContextCurrent(glfwWindow_); - if (!gladLoadGLES2Loader((GLADloadproc)glfwGetProcAddress)) { - E2D_LOG_ERROR("Failed to initialize GLAD GLES2"); - glfwDestroyWindow(glfwWindow_); - glfwWindow_ = nullptr; - deinitGLFW(); - return false; - } + if (!gladLoadGLES2Loader((GLADloadproc)glfwGetProcAddress)) { + E2D_LOG_ERROR("Failed to initialize GLAD GLES2"); + glfwDestroyWindow(glfwWindow_); + glfwWindow_ = nullptr; + deinitGLFW(); + return false; + } - glfwSwapInterval(vsync ? 1 : 0); - vsync_ = vsync; + glfwSwapInterval(vsync ? 1 : 0); + vsync_ = vsync; - glfwGetWindowSize(glfwWindow_, &width_, &height_); - updateContentScale(); + glfwGetWindowSize(glfwWindow_, &width_, &height_); + updateContentScale(); - glfwSetWindowUserPointer(glfwWindow_, this); - glfwSetFramebufferSizeCallback(glfwWindow_, framebufferSizeCallback); - glfwSetWindowCloseCallback(glfwWindow_, windowCloseCallback); - glfwSetWindowFocusCallback(glfwWindow_, windowFocusCallback); - glfwSetWindowIconifyCallback(glfwWindow_, windowIconifyCallback); - glfwSetCursorPosCallback(glfwWindow_, cursorPosCallback); - glfwSetMouseButtonCallback(glfwWindow_, mouseButtonCallback); - glfwSetScrollCallback(glfwWindow_, scrollCallback); - glfwSetKeyCallback(glfwWindow_, keyCallback); - glfwSetJoystickCallback(joystickCallback); + glfwSetWindowUserPointer(glfwWindow_, this); + glfwSetFramebufferSizeCallback(glfwWindow_, framebufferSizeCallback); + glfwSetWindowCloseCallback(glfwWindow_, windowCloseCallback); + glfwSetWindowFocusCallback(glfwWindow_, windowFocusCallback); + glfwSetWindowIconifyCallback(glfwWindow_, windowIconifyCallback); + glfwSetCursorPosCallback(glfwWindow_, cursorPosCallback); + glfwSetMouseButtonCallback(glfwWindow_, mouseButtonCallback); + glfwSetScrollCallback(glfwWindow_, scrollCallback); + glfwSetKeyCallback(glfwWindow_, keyCallback); + glfwSetJoystickCallback(joystickCallback); - input_ = makeUnique(); - input_->setWindow(glfwWindow_); - input_->init(); + input_ = makeUnique(); + input_->setWindow(glfwWindow_); + input_->init(); - E2D_LOG_INFO("GLFW window created: {}x{}", width_, height_); - E2D_LOG_INFO(" Platform: OpenGL ES 3.2"); - return true; + E2D_LOG_INFO("GLFW window created: {}x{}", width_, height_); + E2D_LOG_INFO(" Platform: OpenGL ES 3.2"); + return true; } void GLFWWindow::destroy() { - if (input_) { - input_->shutdown(); - input_.reset(); - } + if (input_) { + input_->shutdown(); + input_.reset(); + } - if (glfwWindow_) { - glfwDestroyWindow(glfwWindow_); - glfwWindow_ = nullptr; - } + if (glfwWindow_) { + glfwDestroyWindow(glfwWindow_); + glfwWindow_ = nullptr; + } - deinitGLFW(); + deinitGLFW(); } void GLFWWindow::poll() { - if (!glfwWindow_) return; + if (!glfwWindow_) + return; - if (input_) { - input_->update(); - } + if (input_) { + input_->update(); + } - glfwPollEvents(); + glfwPollEvents(); } void GLFWWindow::swap() { - if (glfwWindow_) { - glfwSwapBuffers(glfwWindow_); - } + if (glfwWindow_) { + glfwSwapBuffers(glfwWindow_); + } } bool GLFWWindow::shouldClose() const { - if (!glfwWindow_) return true; - return shouldClose_ || glfwWindowShouldClose(glfwWindow_); + if (!glfwWindow_) + return true; + return shouldClose_ || glfwWindowShouldClose(glfwWindow_); } void GLFWWindow::close() { - shouldClose_ = true; - if (glfwWindow_) { - glfwSetWindowShouldClose(glfwWindow_, GLFW_TRUE); - } + shouldClose_ = true; + if (glfwWindow_) { + glfwSetWindowShouldClose(glfwWindow_, GLFW_TRUE); + } } -void GLFWWindow::setTitle(const std::string& title) { - if (glfwWindow_) { - glfwSetWindowTitle(glfwWindow_, title.c_str()); - } +void GLFWWindow::setTitle(const std::string &title) { + if (glfwWindow_) { + glfwSetWindowTitle(glfwWindow_, title.c_str()); + } } void GLFWWindow::setSize(int w, int h) { - if (glfwWindow_) { - glfwSetWindowSize(glfwWindow_, w, h); - width_ = w; - height_ = h; - } + if (glfwWindow_) { + glfwSetWindowSize(glfwWindow_, w, h); + width_ = w; + height_ = h; + } } void GLFWWindow::setPos(int x, int y) { #ifndef __SWITCH__ - if (glfwWindow_) { - glfwSetWindowPos(glfwWindow_, x, y); - } + if (glfwWindow_) { + glfwSetWindowPos(glfwWindow_, x, y); + } #else - (void)x; - (void)y; + (void)x; + (void)y; #endif } void GLFWWindow::setFullscreen(bool fs) { #ifndef __SWITCH__ - if (!glfwWindow_) return; - - if (fs == fullscreen_) return; - - if (fs) { - GLFWmonitor* monitor = glfwGetPrimaryMonitor(); - const GLFWvidmode* mode = glfwGetVideoMode(monitor); - glfwSetWindowMonitor(glfwWindow_, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); - } else { - glfwSetWindowMonitor(glfwWindow_, nullptr, 100, 100, 1280, 720, 0); - } - fullscreen_ = fs; - glfwGetWindowSize(glfwWindow_, &width_, &height_); - updateContentScale(); + if (!glfwWindow_) + return; + + if (fs == fullscreen_) + return; + + if (fs) { + GLFWmonitor *monitor = glfwGetPrimaryMonitor(); + const GLFWvidmode *mode = glfwGetVideoMode(monitor); + glfwSetWindowMonitor(glfwWindow_, monitor, 0, 0, mode->width, mode->height, + mode->refreshRate); + } else { + glfwSetWindowMonitor(glfwWindow_, nullptr, 100, 100, 1280, 720, 0); + } + fullscreen_ = fs; + glfwGetWindowSize(glfwWindow_, &width_, &height_); + updateContentScale(); #else - (void)fs; + (void)fs; #endif } void GLFWWindow::setVSync(bool vsync) { - if (glfwWindow_) { - glfwSwapInterval(vsync ? 1 : 0); - vsync_ = vsync; - } + if (glfwWindow_) { + glfwSwapInterval(vsync ? 1 : 0); + vsync_ = vsync; + } } void GLFWWindow::setVisible(bool visible) { #ifndef __SWITCH__ - if (glfwWindow_) { - if (visible) { - glfwShowWindow(glfwWindow_); - } else { - glfwHideWindow(glfwWindow_); - } + if (glfwWindow_) { + if (visible) { + glfwShowWindow(glfwWindow_); + } else { + glfwHideWindow(glfwWindow_); } + } #else - (void)visible; + (void)visible; #endif } -int GLFWWindow::width() const { - return width_; -} +int GLFWWindow::width() const { return width_; } -int GLFWWindow::height() const { - return height_; -} +int GLFWWindow::height() const { return height_; } Size GLFWWindow::size() const { - return Size(static_cast(width_), static_cast(height_)); + return Size(static_cast(width_), static_cast(height_)); } Vec2 GLFWWindow::pos() const { - int x = 0, y = 0; + int x = 0, y = 0; #ifndef __SWITCH__ - if (glfwWindow_) { - glfwGetWindowPos(glfwWindow_, &x, &y); - } + if (glfwWindow_) { + glfwGetWindowPos(glfwWindow_, &x, &y); + } #endif - return Vec2(static_cast(x), static_cast(y)); + return Vec2(static_cast(x), static_cast(y)); } -bool GLFWWindow::fullscreen() const { - return fullscreen_; -} +bool GLFWWindow::fullscreen() const { return fullscreen_; } -bool GLFWWindow::vsync() const { - return vsync_; -} +bool GLFWWindow::vsync() const { return vsync_; } -bool GLFWWindow::focused() const { - return focused_; -} +bool GLFWWindow::focused() const { return focused_; } -bool GLFWWindow::minimized() const { - return minimized_; -} +bool GLFWWindow::minimized() const { return minimized_; } -float GLFWWindow::scaleX() const { - return scaleX_; -} +float GLFWWindow::scaleX() const { return scaleX_; } -float GLFWWindow::scaleY() const { - return scaleY_; -} +float GLFWWindow::scaleY() const { return scaleY_; } void GLFWWindow::setCursor(Cursor cursor) { #ifndef __SWITCH__ - if (!glfwWindow_) return; + if (!glfwWindow_) + return; - if (cursor == Cursor::Hidden) { - glfwSetInputMode(glfwWindow_, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); - return; - } + if (cursor == Cursor::Hidden) { + glfwSetInputMode(glfwWindow_, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + return; + } - glfwSetInputMode(glfwWindow_, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + glfwSetInputMode(glfwWindow_, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - GLFWcursor* glfwCursor = nullptr; - switch (cursor) { - case Cursor::Arrow: - glfwCursor = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); - break; - case Cursor::IBeam: - glfwCursor = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR); - break; - case Cursor::Crosshair: - glfwCursor = glfwCreateStandardCursor(GLFW_CROSSHAIR_CURSOR); - break; - case Cursor::Hand: - glfwCursor = glfwCreateStandardCursor(GLFW_HAND_CURSOR); - break; - case Cursor::HResize: - glfwCursor = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR); - break; - case Cursor::VResize: - glfwCursor = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR); - break; - default: - glfwCursor = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); - break; - } + GLFWcursor *glfwCursor = nullptr; + switch (cursor) { + case Cursor::Arrow: + glfwCursor = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); + break; + case Cursor::IBeam: + glfwCursor = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR); + break; + case Cursor::Crosshair: + glfwCursor = glfwCreateStandardCursor(GLFW_CROSSHAIR_CURSOR); + break; + case Cursor::Hand: + glfwCursor = glfwCreateStandardCursor(GLFW_HAND_CURSOR); + break; + case Cursor::HResize: + glfwCursor = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR); + break; + case Cursor::VResize: + glfwCursor = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR); + break; + default: + glfwCursor = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); + break; + } - if (glfwCursor) { - glfwSetCursor(glfwWindow_, glfwCursor); - } + if (glfwCursor) { + glfwSetCursor(glfwWindow_, glfwCursor); + } #else - (void)cursor; + (void)cursor; #endif } void GLFWWindow::showCursor(bool show) { #ifndef __SWITCH__ - if (glfwWindow_) { - glfwSetInputMode(glfwWindow_, GLFW_CURSOR, show ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_HIDDEN); - cursorVisible_ = show; - } + if (glfwWindow_) { + glfwSetInputMode(glfwWindow_, GLFW_CURSOR, + show ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_HIDDEN); + cursorVisible_ = show; + } #else - (void)show; + (void)show; #endif } void GLFWWindow::lockCursor(bool lock) { #ifndef __SWITCH__ - if (glfwWindow_) { - glfwSetInputMode(glfwWindow_, GLFW_CURSOR, lock ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_NORMAL); - cursorLocked_ = lock; - } + if (glfwWindow_) { + glfwSetInputMode(glfwWindow_, GLFW_CURSOR, + lock ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_NORMAL); + cursorLocked_ = lock; + } #else - (void)lock; + (void)lock; #endif } -IInput* GLFWWindow::input() const { - return input_.get(); -} +IInput *GLFWWindow::input() const { return input_.get(); } -void GLFWWindow::onResize(ResizeCb cb) { - resizeCb_ = cb; -} +void GLFWWindow::onResize(ResizeCb cb) { resizeCb_ = cb; } -void GLFWWindow::onClose(CloseCb cb) { - closeCb_ = cb; -} +void GLFWWindow::onClose(CloseCb cb) { closeCb_ = cb; } -void GLFWWindow::onFocus(FocusCb cb) { - focusCb_ = cb; -} +void GLFWWindow::onFocus(FocusCb cb) { focusCb_ = cb; } -void* GLFWWindow::native() const { - return glfwWindow_; -} +void *GLFWWindow::native() const { return glfwWindow_; } bool GLFWWindow::initGLFW() { - static int glfwInitCount = 0; - if (glfwInitCount == 0) { - if (!glfwInit()) { - E2D_LOG_ERROR("Failed to initialize GLFW"); - return false; - } - glfwInitCount++; + static int glfwInitCount = 0; + if (glfwInitCount == 0) { + if (!glfwInit()) { + E2D_LOG_ERROR("Failed to initialize GLFW"); + return false; } - return true; + glfwInitCount++; + } + return true; } void GLFWWindow::deinitGLFW() { - static int glfwInitCount = 1; - glfwInitCount--; - if (glfwInitCount == 0) { - glfwTerminate(); - } + static int glfwInitCount = 1; + glfwInitCount--; + if (glfwInitCount == 0) { + glfwTerminate(); + } } void GLFWWindow::updateContentScale() { - if (glfwWindow_) { - int fbWidth, fbHeight; - glfwGetFramebufferSize(glfwWindow_, &fbWidth, &fbHeight); - scaleX_ = fbWidth > 0 ? static_cast(fbWidth) / width_ : 1.0f; - scaleY_ = fbHeight > 0 ? static_cast(fbHeight) / height_ : 1.0f; - } + if (glfwWindow_) { + int fbWidth, fbHeight; + glfwGetFramebufferSize(glfwWindow_, &fbWidth, &fbHeight); + scaleX_ = fbWidth > 0 ? static_cast(fbWidth) / width_ : 1.0f; + scaleY_ = fbHeight > 0 ? static_cast(fbHeight) / height_ : 1.0f; + } } // 静态回调函数 -void GLFWWindow::framebufferSizeCallback(GLFWwindow* window, int width, int height) { - GLFWWindow* self = static_cast(glfwGetWindowUserPointer(window)); - if (self) { - self->width_ = width; - self->height_ = height; - self->updateContentScale(); - if (self->resizeCb_) { - self->resizeCb_(width, height); - } +void GLFWWindow::framebufferSizeCallback(GLFWwindow *window, int width, + int height) { + GLFWWindow *self = + static_cast(glfwGetWindowUserPointer(window)); + if (self) { + self->width_ = width; + self->height_ = height; + self->updateContentScale(); + if (self->resizeCb_) { + self->resizeCb_(width, height); } + } } -void GLFWWindow::windowCloseCallback(GLFWwindow* window) { - GLFWWindow* self = static_cast(glfwGetWindowUserPointer(window)); - if (self) { - self->shouldClose_ = true; - if (self->closeCb_) { - self->closeCb_(); - } +void GLFWWindow::windowCloseCallback(GLFWwindow *window) { + GLFWWindow *self = + static_cast(glfwGetWindowUserPointer(window)); + if (self) { + self->shouldClose_ = true; + if (self->closeCb_) { + self->closeCb_(); } + } } -void GLFWWindow::windowFocusCallback(GLFWwindow* window, int focused) { - GLFWWindow* self = static_cast(glfwGetWindowUserPointer(window)); - if (self) { - self->focused_ = (focused == GLFW_TRUE); - if (self->focusCb_) { - self->focusCb_(self->focused_); - } +void GLFWWindow::windowFocusCallback(GLFWwindow *window, int focused) { + GLFWWindow *self = + static_cast(glfwGetWindowUserPointer(window)); + if (self) { + self->focused_ = (focused == GLFW_TRUE); + if (self->focusCb_) { + self->focusCb_(self->focused_); } + } } -void GLFWWindow::windowIconifyCallback(GLFWwindow* window, int iconified) { - GLFWWindow* self = static_cast(glfwGetWindowUserPointer(window)); - if (self) { - self->minimized_ = (iconified == GLFW_TRUE); - } +void GLFWWindow::windowIconifyCallback(GLFWwindow *window, int iconified) { + GLFWWindow *self = + static_cast(glfwGetWindowUserPointer(window)); + if (self) { + self->minimized_ = (iconified == GLFW_TRUE); + } } -void GLFWWindow::cursorPosCallback(GLFWwindow* window, double xpos, double ypos) { - GLFWWindow* self = static_cast(glfwGetWindowUserPointer(window)); - if (self && self->input_) { - self->input_->handleCursorPosEvent(xpos, ypos); - } +void GLFWWindow::cursorPosCallback(GLFWwindow *window, double xpos, + double ypos) { + GLFWWindow *self = + static_cast(glfwGetWindowUserPointer(window)); + if (self && self->input_) { + self->input_->handleCursorPosEvent(xpos, ypos); + } } -void GLFWWindow::mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) { - GLFWWindow* self = static_cast(glfwGetWindowUserPointer(window)); - if (self && self->input_) { - self->input_->handleMouseButtonEvent(button, action, mods); - } +void GLFWWindow::mouseButtonCallback(GLFWwindow *window, int button, int action, + int mods) { + GLFWWindow *self = + static_cast(glfwGetWindowUserPointer(window)); + if (self && self->input_) { + self->input_->handleMouseButtonEvent(button, action, mods); + } } -void GLFWWindow::scrollCallback(GLFWwindow* window, double xoffset, double yoffset) { - GLFWWindow* self = static_cast(glfwGetWindowUserPointer(window)); - if (self && self->input_) { - self->input_->handleScrollEvent(xoffset, yoffset); - } +void GLFWWindow::scrollCallback(GLFWwindow *window, double xoffset, + double yoffset) { + GLFWWindow *self = + static_cast(glfwGetWindowUserPointer(window)); + if (self && self->input_) { + self->input_->handleScrollEvent(xoffset, yoffset); + } } -void GLFWWindow::keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { - GLFWWindow* self = static_cast(glfwGetWindowUserPointer(window)); - if (self && self->input_) { - self->input_->handleKeyEvent(key, scancode, action, mods); - } +void GLFWWindow::keyCallback(GLFWwindow *window, int key, int scancode, + int action, int mods) { + GLFWWindow *self = + static_cast(glfwGetWindowUserPointer(window)); + if (self && self->input_) { + self->input_->handleKeyEvent(key, scancode, action, mods); + } } void GLFWWindow::joystickCallback(int jid, int event) { - // 通过全局回调找到对应的窗口实例 - // 由于 GLFW 的 joystick 回调没有窗口参数,我们需要其他方式处理 - // 这里简化处理,让输入系统在 update() 中轮询 + // 通过全局回调找到对应的窗口实例 + // 由于 GLFW 的 joystick 回调没有窗口参数,我们需要其他方式处理 + // 这里简化处理,让输入系统在 update() 中轮询 } } // namespace extra2d diff --git a/Extra2D/src/platform/backends/sdl2/sdl2_input.cpp b/Extra2D/src/platform/backends/sdl2/sdl2_input.cpp index 6a73715..608bc31 100644 --- a/Extra2D/src/platform/backends/sdl2/sdl2_input.cpp +++ b/Extra2D/src/platform/backends/sdl2/sdl2_input.cpp @@ -1,451 +1,454 @@ #include "sdl2_input.h" -#include #include +#include +#include + namespace extra2d { SDL2Input::SDL2Input() { - keyCurrent_.fill(false); - keyPrevious_.fill(false); - mouseCurrent_.fill(false); - mousePrevious_.fill(false); - gamepadCurrent_.fill(false); - gamepadPrevious_.fill(false); + keyCurrent_.fill(false); + keyPrevious_.fill(false); + mouseCurrent_.fill(false); + mousePrevious_.fill(false); + gamepadCurrent_.fill(false); + gamepadPrevious_.fill(false); } -SDL2Input::~SDL2Input() { - shutdown(); -} +SDL2Input::~SDL2Input() { shutdown(); } void SDL2Input::init() { - E2D_LOG_INFO("SDL2Input initialized"); - - if (SDL_Init(SDL_INIT_GAMECONTROLLER) != 0) { - E2D_LOG_WARN("Failed to init gamecontroller subsystem: {}", SDL_GetError()); - } - - openGamepad(); + E2D_LOG_INFO("SDL2Input initialized"); + + if (SDL_Init(SDL_INIT_GAMECONTROLLER) != 0) { + E2D_LOG_WARN("Failed to init gamecontroller subsystem: {}", SDL_GetError()); + } + + openGamepad(); } void SDL2Input::shutdown() { - closeGamepad(); - E2D_LOG_INFO("SDL2Input shutdown"); + closeGamepad(); + E2D_LOG_INFO("SDL2Input shutdown"); } void SDL2Input::update() { - keyPrevious_ = keyCurrent_; - mousePrevious_ = mouseCurrent_; - gamepadPrevious_ = gamepadCurrent_; - - scrollDelta_ = 0.0f; - mouseDelta_ = Vec2{0.0f, 0.0f}; - - updateGamepad(); + keyPrevious_ = keyCurrent_; + mousePrevious_ = mouseCurrent_; + gamepadPrevious_ = gamepadCurrent_; + + scrollDelta_ = 0.0f; + mouseDelta_ = Vec2{0.0f, 0.0f}; + + updateGamepad(); } void SDL2Input::setEventCallback(EventCallback callback) { - eventCallback_ = std::move(callback); + eventCallback_ = std::move(callback); } -void SDL2Input::handleSDLEvent(const SDL_Event& event) { - switch (event.type) { - case SDL_KEYDOWN: { - int key = event.key.keysym.scancode; - if (key >= 0 && key < static_cast(Key::Count)) { - if (!keyCurrent_[key]) { - keyCurrent_[key] = true; - - Event e = Event::createKeyPress( - event.key.keysym.sym, - event.key.keysym.scancode, - event.key.keysym.mod - ); - dispatchEvent(e); - } - } - break; - } - - case SDL_KEYUP: { - int key = event.key.keysym.scancode; - if (key >= 0 && key < static_cast(Key::Count)) { - keyCurrent_[key] = false; - - Event e = Event::createKeyRelease( - event.key.keysym.sym, - event.key.keysym.scancode, - event.key.keysym.mod - ); - dispatchEvent(e); - } - break; - } - - case SDL_MOUSEBUTTONDOWN: { - int btn = event.button.button - 1; - if (btn >= 0 && btn < static_cast(Mouse::Count)) { - mouseCurrent_[btn] = true; - - Vec2 pos{static_cast(event.button.x), - static_cast(event.button.y)}; - Event e = Event::createMouseButtonPress(btn, 0, pos); - dispatchEvent(e); - } - break; - } - - case SDL_MOUSEBUTTONUP: { - int btn = event.button.button - 1; - if (btn >= 0 && btn < static_cast(Mouse::Count)) { - mouseCurrent_[btn] = false; - - Vec2 pos{static_cast(event.button.x), - static_cast(event.button.y)}; - Event e = Event::createMouseButtonRelease(btn, 0, pos); - dispatchEvent(e); - } - break; - } - - case SDL_MOUSEMOTION: { - Vec2 newPos{static_cast(event.motion.x), - static_cast(event.motion.y)}; - Vec2 delta{static_cast(event.motion.xrel), - static_cast(event.motion.yrel)}; - - mouseDelta_ = mouseDelta_ + delta; - mousePos_ = newPos; - - Event e = Event::createMouseMove(newPos, delta); - dispatchEvent(e); - break; - } - - case SDL_MOUSEWHEEL: { - Vec2 offset{static_cast(event.wheel.x), - static_cast(event.wheel.y)}; - Vec2 pos = mousePos_; - - scroll_ += event.wheel.y; - scrollDelta_ += event.wheel.y; - - Event e = Event::createMouseScroll(offset, pos); - dispatchEvent(e); - break; - } - - case SDL_CONTROLLERDEVICEADDED: - E2D_LOG_INFO("Gamepad connected: index {}", event.cdevice.which); - openGamepad(); - break; - - case SDL_CONTROLLERDEVICEREMOVED: - if (gamepad_ && event.cdevice.which == SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(gamepad_))) { - E2D_LOG_INFO("Gamepad disconnected"); - closeGamepad(); - } - break; - - case SDL_CONTROLLERBUTTONDOWN: - if (gamepad_) { - int btn = event.cbutton.button; - if (btn >= 0 && btn < static_cast(Gamepad::Count)) { - gamepadCurrent_[btn] = true; - - GamepadButtonEvent btnEvent; - btnEvent.gamepadId = gamepadIndex_; - btnEvent.button = btn; - - Event e; - e.type = EventType::GamepadButtonPressed; - e.data = btnEvent; - dispatchEvent(e); - } - } - break; - - case SDL_CONTROLLERBUTTONUP: - if (gamepad_) { - int btn = event.cbutton.button; - if (btn >= 0 && btn < static_cast(Gamepad::Count)) { - gamepadCurrent_[btn] = false; - - GamepadButtonEvent btnEvent; - btnEvent.gamepadId = gamepadIndex_; - btnEvent.button = btn; - - Event e; - e.type = EventType::GamepadButtonReleased; - e.data = btnEvent; - dispatchEvent(e); - } - } - break; - - default: - break; +void SDL2Input::handleSDLEvent(const SDL_Event &event) { + switch (event.type) { + case SDL_KEYDOWN: { + int key = event.key.keysym.scancode; + if (key >= 0 && key < static_cast(Key::Count)) { + if (!keyCurrent_[key]) { + keyCurrent_[key] = true; + + Event e = Event::createKeyPress(event.key.keysym.sym, + event.key.keysym.scancode, + event.key.keysym.mod); + dispatchEvent(e); + } } + break; + } + + case SDL_KEYUP: { + int key = event.key.keysym.scancode; + if (key >= 0 && key < static_cast(Key::Count)) { + keyCurrent_[key] = false; + + Event e = Event::createKeyRelease(event.key.keysym.sym, + event.key.keysym.scancode, + event.key.keysym.mod); + dispatchEvent(e); + } + break; + } + + case SDL_MOUSEBUTTONDOWN: { + int btn = event.button.button - 1; + if (btn >= 0 && btn < static_cast(Mouse::Count)) { + mouseCurrent_[btn] = true; + + Vec2 pos{static_cast(event.button.x), + static_cast(event.button.y)}; + Event e = Event::createMouseButtonPress(btn, 0, pos); + dispatchEvent(e); + } + break; + } + + case SDL_MOUSEBUTTONUP: { + int btn = event.button.button - 1; + if (btn >= 0 && btn < static_cast(Mouse::Count)) { + mouseCurrent_[btn] = false; + + Vec2 pos{static_cast(event.button.x), + static_cast(event.button.y)}; + Event e = Event::createMouseButtonRelease(btn, 0, pos); + dispatchEvent(e); + } + break; + } + + case SDL_MOUSEMOTION: { + Vec2 newPos{static_cast(event.motion.x), + static_cast(event.motion.y)}; + Vec2 delta{static_cast(event.motion.xrel), + static_cast(event.motion.yrel)}; + + mouseDelta_ = mouseDelta_ + delta; + mousePos_ = newPos; + + Event e = Event::createMouseMove(newPos, delta); + dispatchEvent(e); + break; + } + + case SDL_MOUSEWHEEL: { + Vec2 offset{static_cast(event.wheel.x), + static_cast(event.wheel.y)}; + Vec2 pos = mousePos_; + + scroll_ += event.wheel.y; + scrollDelta_ += event.wheel.y; + + Event e = Event::createMouseScroll(offset, pos); + dispatchEvent(e); + break; + } + + case SDL_CONTROLLERDEVICEADDED: + E2D_LOG_INFO("Gamepad connected: index {}", event.cdevice.which); + openGamepad(); + break; + + case SDL_CONTROLLERDEVICEREMOVED: + if (gamepad_ && + event.cdevice.which == + SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(gamepad_))) { + E2D_LOG_INFO("Gamepad disconnected"); + closeGamepad(); + } + break; + + case SDL_CONTROLLERBUTTONDOWN: + if (gamepad_) { + int btn = event.cbutton.button; + if (btn >= 0 && btn < static_cast(Gamepad::Count)) { + gamepadCurrent_[btn] = true; + + GamepadButtonEvent btnEvent; + btnEvent.gamepadId = gamepadIndex_; + btnEvent.button = btn; + + Event e; + e.type = EventType::GamepadButtonPressed; + e.data = btnEvent; + dispatchEvent(e); + } + } + break; + + case SDL_CONTROLLERBUTTONUP: + if (gamepad_) { + int btn = event.cbutton.button; + if (btn >= 0 && btn < static_cast(Gamepad::Count)) { + gamepadCurrent_[btn] = false; + + GamepadButtonEvent btnEvent; + btnEvent.gamepadId = gamepadIndex_; + btnEvent.button = btn; + + Event e; + e.type = EventType::GamepadButtonReleased; + e.data = btnEvent; + dispatchEvent(e); + } + } + break; + + default: + break; + } } -void SDL2Input::dispatchEvent(const Event& event) { - if (eventCallback_) { - eventCallback_(event); - } +void SDL2Input::dispatchEvent(const Event &event) { + if (eventCallback_) { + eventCallback_(event); + } } bool SDL2Input::down(Key key) const { - size_t idx = static_cast(key); - if (idx < keyCurrent_.size()) { - return keyCurrent_[idx]; - } - return false; + size_t idx = static_cast(key); + if (idx < keyCurrent_.size()) { + return keyCurrent_[idx]; + } + return false; } bool SDL2Input::pressed(Key key) const { - size_t idx = static_cast(key); - if (idx < keyCurrent_.size()) { - return keyCurrent_[idx] && !keyPrevious_[idx]; - } - return false; + size_t idx = static_cast(key); + if (idx < keyCurrent_.size()) { + return keyCurrent_[idx] && !keyPrevious_[idx]; + } + return false; } bool SDL2Input::released(Key key) const { - size_t idx = static_cast(key); - if (idx < keyCurrent_.size()) { - return !keyCurrent_[idx] && keyPrevious_[idx]; - } - return false; + size_t idx = static_cast(key); + if (idx < keyCurrent_.size()) { + return !keyCurrent_[idx] && keyPrevious_[idx]; + } + return false; } bool SDL2Input::down(Mouse btn) const { - size_t idx = static_cast(btn); - if (idx < mouseCurrent_.size()) { - return mouseCurrent_[idx]; - } - return false; + size_t idx = static_cast(btn); + if (idx < mouseCurrent_.size()) { + return mouseCurrent_[idx]; + } + return false; } bool SDL2Input::pressed(Mouse btn) const { - size_t idx = static_cast(btn); - if (idx < mouseCurrent_.size()) { - return mouseCurrent_[idx] && !mousePrevious_[idx]; - } - return false; + size_t idx = static_cast(btn); + if (idx < mouseCurrent_.size()) { + return mouseCurrent_[idx] && !mousePrevious_[idx]; + } + return false; } bool SDL2Input::released(Mouse btn) const { - size_t idx = static_cast(btn); - if (idx < mouseCurrent_.size()) { - return !mouseCurrent_[idx] && mousePrevious_[idx]; - } - return false; + size_t idx = static_cast(btn); + if (idx < mouseCurrent_.size()) { + return !mouseCurrent_[idx] && mousePrevious_[idx]; + } + return false; } -Vec2 SDL2Input::mouse() const { - return mousePos_; +Vec2 SDL2Input::mouse() const { return mousePos_; } + +Vec2 SDL2Input::mouseDelta() const { return mouseDelta_; } + +float SDL2Input::scroll() const { return scroll_; } + +float SDL2Input::scrollDelta() const { return scrollDelta_; } + +void SDL2Input::setMouse(const Vec2 &pos) { + SDL_WarpMouseInWindow(nullptr, static_cast(pos.x), + static_cast(pos.y)); } -Vec2 SDL2Input::mouseDelta() const { - return mouseDelta_; -} - -float SDL2Input::scroll() const { - return scroll_; -} - -float SDL2Input::scrollDelta() const { - return scrollDelta_; -} - -void SDL2Input::setMouse(const Vec2& pos) { - SDL_WarpMouseInWindow(nullptr, static_cast(pos.x), static_cast(pos.y)); -} - -bool SDL2Input::gamepad() const { - return gamepad_ != nullptr; -} +bool SDL2Input::gamepad() const { return gamepad_ != nullptr; } bool SDL2Input::down(Gamepad btn) const { - size_t idx = static_cast(btn); - if (idx < gamepadCurrent_.size()) { - return gamepadCurrent_[idx]; - } - return false; + size_t idx = static_cast(btn); + if (idx < gamepadCurrent_.size()) { + return gamepadCurrent_[idx]; + } + return false; } bool SDL2Input::pressed(Gamepad btn) const { - size_t idx = static_cast(btn); - if (idx < gamepadCurrent_.size()) { - return gamepadCurrent_[idx] && !gamepadPrevious_[idx]; - } - return false; + size_t idx = static_cast(btn); + if (idx < gamepadCurrent_.size()) { + return gamepadCurrent_[idx] && !gamepadPrevious_[idx]; + } + return false; } bool SDL2Input::released(Gamepad btn) const { - size_t idx = static_cast(btn); - if (idx < gamepadCurrent_.size()) { - return !gamepadCurrent_[idx] && gamepadPrevious_[idx]; - } - return false; + size_t idx = static_cast(btn); + if (idx < gamepadCurrent_.size()) { + return !gamepadCurrent_[idx] && gamepadPrevious_[idx]; + } + return false; } -Vec2 SDL2Input::leftStick() const { - return leftStick_; -} +Vec2 SDL2Input::leftStick() const { return leftStick_; } -Vec2 SDL2Input::rightStick() const { - return rightStick_; -} +Vec2 SDL2Input::rightStick() const { return rightStick_; } -float SDL2Input::leftTrigger() const { - return leftTrigger_; -} +float SDL2Input::leftTrigger() const { return leftTrigger_; } -float SDL2Input::rightTrigger() const { - return rightTrigger_; -} +float SDL2Input::rightTrigger() const { return rightTrigger_; } void SDL2Input::vibrate(float left, float right) { - if (gamepad_) { - Uint16 lowFreq = static_cast(left * 65535.0f); - Uint16 highFreq = static_cast(right * 65535.0f); - SDL_GameControllerRumble(gamepad_, lowFreq, highFreq, 500); - } + if (gamepad_) { + Uint16 lowFreq = static_cast(left * 65535.0f); + Uint16 highFreq = static_cast(right * 65535.0f); + SDL_GameControllerRumble(gamepad_, lowFreq, highFreq, 500); + } } -bool SDL2Input::touching() const { - return false; -} +bool SDL2Input::touching() const { return false; } -int SDL2Input::touchCount() const { - return 0; -} +int SDL2Input::touchCount() const { return 0; } Vec2 SDL2Input::touch(int index) const { - (void)index; - return Vec2{0.0f, 0.0f}; + (void)index; + return Vec2{0.0f, 0.0f}; } TouchPoint SDL2Input::touchPoint(int index) const { - (void)index; - return TouchPoint{}; + (void)index; + return TouchPoint{}; } -void SDL2Input::updateKeyboard() { -} +void SDL2Input::updateKeyboard() {} void SDL2Input::updateMouse() { - int x = 0, y = 0; - SDL_GetMouseState(&x, &y); - mousePos_ = Vec2{static_cast(x), static_cast(y)}; + int x = 0, y = 0; + SDL_GetMouseState(&x, &y); + mousePos_ = Vec2{static_cast(x), static_cast(y)}; } void SDL2Input::updateGamepad() { - if (!gamepad_) { - return; + if (!gamepad_) { + return; + } + + auto applyDeadzone = [this](float value) -> float { + if (std::abs(value) < deadzone_) { + return 0.0f; } - - auto applyDeadzone = [this](float value) -> float { - if (std::abs(value) < deadzone_) { - return 0.0f; - } - float sign = value >= 0.0f ? 1.0f : -1.0f; - return sign * (std::abs(value) - deadzone_) / (1.0f - deadzone_); - }; - - int lx = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_LEFTX); - int ly = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_LEFTY); - int rx = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_RIGHTX); - int ry = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_RIGHTY); - - leftStick_.x = applyDeadzone(lx / 32767.0f); - leftStick_.y = applyDeadzone(ly / 32767.0f); - rightStick_.x = applyDeadzone(rx / 32767.0f); - rightStick_.y = applyDeadzone(ry / 32767.0f); - - int lt = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_TRIGGERLEFT); - int rt = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_TRIGGERRIGHT); - - leftTrigger_ = lt / 32767.0f; - rightTrigger_ = rt / 32767.0f; + float sign = value >= 0.0f ? 1.0f : -1.0f; + return sign * (std::abs(value) - deadzone_) / (1.0f - deadzone_); + }; + + int lx = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_LEFTX); + int ly = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_LEFTY); + int rx = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_RIGHTX); + int ry = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_RIGHTY); + + leftStick_.x = applyDeadzone(lx / 32767.0f); + leftStick_.y = applyDeadzone(ly / 32767.0f); + rightStick_.x = applyDeadzone(rx / 32767.0f); + rightStick_.y = applyDeadzone(ry / 32767.0f); + + int lt = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_TRIGGERLEFT); + int rt = + SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_TRIGGERRIGHT); + + leftTrigger_ = lt / 32767.0f; + rightTrigger_ = rt / 32767.0f; } void SDL2Input::openGamepad() { - int numJoysticks = SDL_NumJoysticks(); - for (int i = 0; i < numJoysticks; ++i) { - if (SDL_IsGameController(i)) { - gamepad_ = SDL_GameControllerOpen(i); - if (gamepad_) { - gamepadIndex_ = i; - E2D_LOG_INFO("Gamepad opened: {}", SDL_GameControllerName(gamepad_)); - return; - } - } + int numJoysticks = SDL_NumJoysticks(); + for (int i = 0; i < numJoysticks; ++i) { + if (SDL_IsGameController(i)) { + gamepad_ = SDL_GameControllerOpen(i); + if (gamepad_) { + gamepadIndex_ = i; + E2D_LOG_INFO("Gamepad opened: {}", SDL_GameControllerName(gamepad_)); + return; + } } + } } void SDL2Input::closeGamepad() { - if (gamepad_) { - SDL_GameControllerClose(gamepad_); - gamepad_ = nullptr; - gamepadIndex_ = -1; - gamepadCurrent_.fill(false); - gamepadPrevious_.fill(false); - } + if (gamepad_) { + SDL_GameControllerClose(gamepad_); + gamepad_ = nullptr; + gamepadIndex_ = -1; + gamepadCurrent_.fill(false); + gamepadPrevious_.fill(false); + } } -int SDL2Input::keyToSDL(Key key) { - return static_cast(key); -} +int SDL2Input::keyToSDL(Key key) { return static_cast(key); } int SDL2Input::mouseToSDL(Mouse btn) { - switch (btn) { - case Mouse::Left: return SDL_BUTTON_LEFT; - case Mouse::Middle: return SDL_BUTTON_MIDDLE; - case Mouse::Right: return SDL_BUTTON_RIGHT; - case Mouse::X1: return SDL_BUTTON_X1; - case Mouse::X2: return SDL_BUTTON_X2; - default: return 0; - } + switch (btn) { + case Mouse::Left: + return SDL_BUTTON_LEFT; + case Mouse::Middle: + return SDL_BUTTON_MIDDLE; + case Mouse::Right: + return SDL_BUTTON_RIGHT; + case Mouse::X1: + return SDL_BUTTON_X1; + case Mouse::X2: + return SDL_BUTTON_X2; + default: + return 0; + } } int SDL2Input::gamepadToSDL(Gamepad btn) { - switch (btn) { - case Gamepad::A: return SDL_CONTROLLER_BUTTON_A; - case Gamepad::B: return SDL_CONTROLLER_BUTTON_B; - case Gamepad::X: return SDL_CONTROLLER_BUTTON_X; - case Gamepad::Y: return SDL_CONTROLLER_BUTTON_Y; - case Gamepad::Back: return SDL_CONTROLLER_BUTTON_BACK; - case Gamepad::Start: return SDL_CONTROLLER_BUTTON_START; - case Gamepad::LStick: return SDL_CONTROLLER_BUTTON_LEFTSTICK; - case Gamepad::RStick: return SDL_CONTROLLER_BUTTON_RIGHTSTICK; - case Gamepad::LB: return SDL_CONTROLLER_BUTTON_LEFTSHOULDER; - case Gamepad::RB: return SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; - case Gamepad::DUp: return SDL_CONTROLLER_BUTTON_DPAD_UP; - case Gamepad::DDown: return SDL_CONTROLLER_BUTTON_DPAD_DOWN; - case Gamepad::DLeft: return SDL_CONTROLLER_BUTTON_DPAD_LEFT; - case Gamepad::DRight: return SDL_CONTROLLER_BUTTON_DPAD_RIGHT; - case Gamepad::Guide: return SDL_CONTROLLER_BUTTON_GUIDE; - default: return 0; - } + switch (btn) { + case Gamepad::A: + return SDL_CONTROLLER_BUTTON_A; + case Gamepad::B: + return SDL_CONTROLLER_BUTTON_B; + case Gamepad::X: + return SDL_CONTROLLER_BUTTON_X; + case Gamepad::Y: + return SDL_CONTROLLER_BUTTON_Y; + case Gamepad::Back: + return SDL_CONTROLLER_BUTTON_BACK; + case Gamepad::Start: + return SDL_CONTROLLER_BUTTON_START; + case Gamepad::LStick: + return SDL_CONTROLLER_BUTTON_LEFTSTICK; + case Gamepad::RStick: + return SDL_CONTROLLER_BUTTON_RIGHTSTICK; + case Gamepad::LB: + return SDL_CONTROLLER_BUTTON_LEFTSHOULDER; + case Gamepad::RB: + return SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; + case Gamepad::DUp: + return SDL_CONTROLLER_BUTTON_DPAD_UP; + case Gamepad::DDown: + return SDL_CONTROLLER_BUTTON_DPAD_DOWN; + case Gamepad::DLeft: + return SDL_CONTROLLER_BUTTON_DPAD_LEFT; + case Gamepad::DRight: + return SDL_CONTROLLER_BUTTON_DPAD_RIGHT; + case Gamepad::Guide: + return SDL_CONTROLLER_BUTTON_GUIDE; + default: + return 0; + } } Key SDL2Input::sdlToKey(int sdlKey) { - if (sdlKey >= 0 && sdlKey < static_cast(Key::Count)) { - return static_cast(sdlKey); - } - return Key::None; + if (sdlKey >= 0 && sdlKey < static_cast(Key::Count)) { + return static_cast(sdlKey); + } + return Key::None; } Mouse SDL2Input::sdlToMouse(int sdlButton) { - switch (sdlButton) { - case SDL_BUTTON_LEFT: return Mouse::Left; - case SDL_BUTTON_MIDDLE: return Mouse::Middle; - case SDL_BUTTON_RIGHT: return Mouse::Right; - case SDL_BUTTON_X1: return Mouse::X1; - case SDL_BUTTON_X2: return Mouse::X2; - default: return Mouse::Count; - } + switch (sdlButton) { + case SDL_BUTTON_LEFT: + return Mouse::Left; + case SDL_BUTTON_MIDDLE: + return Mouse::Middle; + case SDL_BUTTON_RIGHT: + return Mouse::Right; + case SDL_BUTTON_X1: + return Mouse::X1; + case SDL_BUTTON_X2: + return Mouse::X2; + default: + return Mouse::Count; + } } -} +} // namespace extra2d diff --git a/Extra2D/src/platform/backends/sdl2/sdl2_window.cpp b/Extra2D/src/platform/backends/sdl2/sdl2_window.cpp index c4239b4..1131d76 100644 --- a/Extra2D/src/platform/backends/sdl2/sdl2_window.cpp +++ b/Extra2D/src/platform/backends/sdl2/sdl2_window.cpp @@ -1,400 +1,373 @@ #include "sdl2_window.h" #include "sdl2_input.h" -#include +#include +#include #include + namespace extra2d { SDL2Window::SDL2Window() { - for (int i = 0; i < 7; ++i) { - sdlCursors_[i] = nullptr; - } + for (int i = 0; i < 7; ++i) { + sdlCursors_[i] = nullptr; + } } -SDL2Window::~SDL2Window() { - destroy(); -} +SDL2Window::~SDL2Window() { destroy(); } -bool SDL2Window::create(const std::string& title, int width, int height, bool vsync) { - if (!initSDL()) { - return false; - } +bool SDL2Window::create(const std::string &title, int width, int height, + bool vsync) { + if (!initSDL()) { + return false; + } + + Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE; - Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE; - #ifdef __SWITCH__ - flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; #endif - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - sdlWindow_ = SDL_CreateWindow( - title.c_str(), - SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - width, height, - flags - ); + sdlWindow_ = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, width, height, flags); - if (!sdlWindow_) { - E2D_LOG_ERROR("Failed to create SDL window: {}", SDL_GetError()); - deinitSDL(); - return false; - } + if (!sdlWindow_) { + E2D_LOG_ERROR("Failed to create SDL window: {}", SDL_GetError()); + deinitSDL(); + return false; + } - glContext_ = SDL_GL_CreateContext(sdlWindow_); - if (!glContext_) { - E2D_LOG_ERROR("Failed to create OpenGL context: {}", SDL_GetError()); - SDL_DestroyWindow(sdlWindow_); - sdlWindow_ = nullptr; - deinitSDL(); - return false; - } + glContext_ = SDL_GL_CreateContext(sdlWindow_); + if (!glContext_) { + E2D_LOG_ERROR("Failed to create OpenGL context: {}", SDL_GetError()); + SDL_DestroyWindow(sdlWindow_); + sdlWindow_ = nullptr; + deinitSDL(); + return false; + } - if (!gladLoadGLES2Loader((GLADloadproc)SDL_GL_GetProcAddress)) { - E2D_LOG_ERROR("Failed to initialize GLAD GLES2"); - SDL_GL_DeleteContext(glContext_); - glContext_ = nullptr; - SDL_DestroyWindow(sdlWindow_); - sdlWindow_ = nullptr; - deinitSDL(); - return false; - } + if (!gladLoadGLES2Loader((GLADloadproc)SDL_GL_GetProcAddress)) { + E2D_LOG_ERROR("Failed to initialize GLAD GLES2"); + SDL_GL_DeleteContext(glContext_); + glContext_ = nullptr; + SDL_DestroyWindow(sdlWindow_); + sdlWindow_ = nullptr; + deinitSDL(); + return false; + } - SDL_GL_SetSwapInterval(vsync ? 1 : 0); + SDL_GL_SetSwapInterval(vsync ? 1 : 0); - SDL_GetWindowSize(sdlWindow_, &width_, &height_); - fullscreen_ = (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0; - vsync_ = vsync; + SDL_GetWindowSize(sdlWindow_, &width_, &height_); + fullscreen_ = (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0; + vsync_ = vsync; #ifndef __SWITCH__ - initCursors(); + initCursors(); #endif - updateContentScale(); + updateContentScale(); - input_ = makeUnique(); - input_->init(); + input_ = makeUnique(); + input_->init(); - E2D_LOG_INFO("SDL2 window created: {}x{}", width_, height_); - E2D_LOG_INFO(" Platform: OpenGL ES 3.2"); - return true; + E2D_LOG_INFO("SDL2 window created: {}x{}", width_, height_); + E2D_LOG_INFO(" Platform: OpenGL ES 3.2"); + return true; } void SDL2Window::destroy() { - if (input_) { - input_->shutdown(); - input_.reset(); - } + if (input_) { + input_->shutdown(); + input_.reset(); + } #ifndef __SWITCH__ - deinitCursors(); + deinitCursors(); #endif - if (glContext_) { - SDL_GL_DeleteContext(glContext_); - glContext_ = nullptr; - } + if (glContext_) { + SDL_GL_DeleteContext(glContext_); + glContext_ = nullptr; + } - if (sdlWindow_) { - SDL_DestroyWindow(sdlWindow_); - sdlWindow_ = nullptr; - } + if (sdlWindow_) { + SDL_DestroyWindow(sdlWindow_); + sdlWindow_ = nullptr; + } - deinitSDL(); + deinitSDL(); } void SDL2Window::poll() { - if (!sdlWindow_) return; + if (!sdlWindow_) + return; - if (input_) { - input_->update(); - } + if (input_) { + input_->update(); + } - SDL_Event event; - while (SDL_PollEvent(&event)) { - handleEvent(event); - } + SDL_Event event; + while (SDL_PollEvent(&event)) { + handleEvent(event); + } } void SDL2Window::swap() { - if (sdlWindow_ && glContext_) { - SDL_GL_SwapWindow(sdlWindow_); - } + if (sdlWindow_ && glContext_) { + SDL_GL_SwapWindow(sdlWindow_); + } } -bool SDL2Window::shouldClose() const { - return shouldClose_; -} +bool SDL2Window::shouldClose() const { return shouldClose_; } -void SDL2Window::close() { - shouldClose_ = true; -} +void SDL2Window::close() { shouldClose_ = true; } -void SDL2Window::setTitle(const std::string& title) { - if (sdlWindow_) { - SDL_SetWindowTitle(sdlWindow_, title.c_str()); - } +void SDL2Window::setTitle(const std::string &title) { + if (sdlWindow_) { + SDL_SetWindowTitle(sdlWindow_, title.c_str()); + } } void SDL2Window::setSize(int w, int h) { - if (sdlWindow_) { - SDL_SetWindowSize(sdlWindow_, w, h); - width_ = w; - height_ = h; - } + if (sdlWindow_) { + SDL_SetWindowSize(sdlWindow_, w, h); + width_ = w; + height_ = h; + } } void SDL2Window::setPos(int x, int y) { #ifndef __SWITCH__ - if (sdlWindow_) { - SDL_SetWindowPosition(sdlWindow_, x, y); - } + if (sdlWindow_) { + SDL_SetWindowPosition(sdlWindow_, x, y); + } #else - (void)x; - (void)y; + (void)x; + (void)y; #endif } void SDL2Window::setFullscreen(bool fs) { #ifndef __SWITCH__ - if (sdlWindow_) { - SDL_SetWindowFullscreen(sdlWindow_, fs ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); - fullscreen_ = fs; - } + if (sdlWindow_) { + SDL_SetWindowFullscreen(sdlWindow_, fs ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); + fullscreen_ = fs; + } #else - (void)fs; + (void)fs; #endif } void SDL2Window::setVSync(bool vsync) { - if (glContext_) { - SDL_GL_SetSwapInterval(vsync ? 1 : 0); - vsync_ = vsync; - } + if (glContext_) { + SDL_GL_SetSwapInterval(vsync ? 1 : 0); + vsync_ = vsync; + } } void SDL2Window::setVisible(bool visible) { #ifndef __SWITCH__ - if (sdlWindow_) { - if (visible) { - SDL_ShowWindow(sdlWindow_); - } else { - SDL_HideWindow(sdlWindow_); - } + if (sdlWindow_) { + if (visible) { + SDL_ShowWindow(sdlWindow_); + } else { + SDL_HideWindow(sdlWindow_); } + } #else - (void)visible; + (void)visible; #endif } -int SDL2Window::width() const { - return width_; -} +int SDL2Window::width() const { return width_; } -int SDL2Window::height() const { - return height_; -} +int SDL2Window::height() const { return height_; } Size SDL2Window::size() const { - return Size(static_cast(width_), static_cast(height_)); + return Size(static_cast(width_), static_cast(height_)); } Vec2 SDL2Window::pos() const { - int x = 0, y = 0; + int x = 0, y = 0; #ifndef __SWITCH__ - if (sdlWindow_) { - SDL_GetWindowPosition(sdlWindow_, &x, &y); - } + if (sdlWindow_) { + SDL_GetWindowPosition(sdlWindow_, &x, &y); + } #endif - return Vec2(static_cast(x), static_cast(y)); + return Vec2(static_cast(x), static_cast(y)); } -bool SDL2Window::fullscreen() const { - return fullscreen_; -} +bool SDL2Window::fullscreen() const { return fullscreen_; } -bool SDL2Window::vsync() const { - return vsync_; -} +bool SDL2Window::vsync() const { return vsync_; } -bool SDL2Window::focused() const { - return focused_; -} +bool SDL2Window::focused() const { return focused_; } -bool SDL2Window::minimized() const { - return minimized_; -} +bool SDL2Window::minimized() const { return minimized_; } -float SDL2Window::scaleX() const { - return scaleX_; -} +float SDL2Window::scaleX() const { return scaleX_; } -float SDL2Window::scaleY() const { - return scaleY_; -} +float SDL2Window::scaleY() const { return scaleY_; } void SDL2Window::setCursor(Cursor cursor) { #ifndef __SWITCH__ - if (cursor == Cursor::Hidden) { - SDL_ShowCursor(SDL_DISABLE); - return; - } + if (cursor == Cursor::Hidden) { + SDL_ShowCursor(SDL_DISABLE); + return; + } - SDL_ShowCursor(SDL_ENABLE); + SDL_ShowCursor(SDL_ENABLE); - int idx = static_cast(cursor); - if (idx >= 0 && idx < 7 && sdlCursors_[idx]) { - SDL_SetCursor(sdlCursors_[idx]); - currentCursor_ = idx; - } + int idx = static_cast(cursor); + if (idx >= 0 && idx < 7 && sdlCursors_[idx]) { + SDL_SetCursor(sdlCursors_[idx]); + currentCursor_ = idx; + } #else - (void)cursor; + (void)cursor; #endif } void SDL2Window::showCursor(bool show) { #ifndef __SWITCH__ - SDL_ShowCursor(show ? SDL_ENABLE : SDL_DISABLE); - cursorVisible_ = show; + SDL_ShowCursor(show ? SDL_ENABLE : SDL_DISABLE); + cursorVisible_ = show; #else - (void)show; + (void)show; #endif } void SDL2Window::lockCursor(bool lock) { #ifndef __SWITCH__ - if (sdlWindow_) { - SDL_SetRelativeMouseMode(lock ? SDL_TRUE : SDL_FALSE); - cursorLocked_ = lock; - } + if (sdlWindow_) { + SDL_SetRelativeMouseMode(lock ? SDL_TRUE : SDL_FALSE); + cursorLocked_ = lock; + } #else - (void)lock; + (void)lock; #endif } -IInput* SDL2Window::input() const { - return input_.get(); -} +IInput *SDL2Window::input() const { return input_.get(); } -void SDL2Window::onResize(ResizeCb cb) { - resizeCb_ = cb; -} +void SDL2Window::onResize(ResizeCb cb) { resizeCb_ = cb; } -void SDL2Window::onClose(CloseCb cb) { - closeCb_ = cb; -} +void SDL2Window::onClose(CloseCb cb) { closeCb_ = cb; } -void SDL2Window::onFocus(FocusCb cb) { - focusCb_ = cb; -} +void SDL2Window::onFocus(FocusCb cb) { focusCb_ = cb; } -void* SDL2Window::native() const { - return sdlWindow_; -} +void *SDL2Window::native() const { return sdlWindow_; } bool SDL2Window::initSDL() { - static int sdlInitCount = 0; - if (sdlInitCount == 0) { - Uint32 initFlags = SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER; - if (SDL_Init(initFlags) != 0) { - E2D_LOG_ERROR("Failed to initialize SDL: {}", SDL_GetError()); - return false; - } - sdlInitCount++; + static int sdlInitCount = 0; + if (sdlInitCount == 0) { + Uint32 initFlags = SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER; + if (SDL_Init(initFlags) != 0) { + E2D_LOG_ERROR("Failed to initialize SDL: {}", SDL_GetError()); + return false; } - return true; + sdlInitCount++; + } + return true; } void SDL2Window::deinitSDL() { - static int sdlInitCount = 1; - sdlInitCount--; - if (sdlInitCount == 0) { - SDL_Quit(); - } + static int sdlInitCount = 1; + sdlInitCount--; + if (sdlInitCount == 0) { + SDL_Quit(); + } } #ifndef __SWITCH__ void SDL2Window::initCursors() { - sdlCursors_[0] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); - sdlCursors_[1] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); - sdlCursors_[2] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR); - sdlCursors_[3] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND); - sdlCursors_[4] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS); - sdlCursors_[5] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); - sdlCursors_[6] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL); + sdlCursors_[0] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); + sdlCursors_[1] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); + sdlCursors_[2] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR); + sdlCursors_[3] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND); + sdlCursors_[4] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS); + sdlCursors_[5] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); + sdlCursors_[6] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL); } void SDL2Window::deinitCursors() { - for (int i = 0; i < 7; ++i) { - if (sdlCursors_[i]) { - SDL_FreeCursor(sdlCursors_[i]); - sdlCursors_[i] = nullptr; - } + for (int i = 0; i < 7; ++i) { + if (sdlCursors_[i]) { + SDL_FreeCursor(sdlCursors_[i]); + sdlCursors_[i] = nullptr; } + } } #endif void SDL2Window::updateContentScale() { - if (sdlWindow_) { - SDL_GetWindowSize(sdlWindow_, &width_, &height_); - int dw, dh; - SDL_GL_GetDrawableSize(sdlWindow_, &dw, &dh); - scaleX_ = dw > 0 ? static_cast(dw) / width_ : 1.0f; - scaleY_ = dh > 0 ? static_cast(dh) / height_ : 1.0f; - } + if (sdlWindow_) { + SDL_GetWindowSize(sdlWindow_, &width_, &height_); + int dw, dh; + SDL_GL_GetDrawableSize(sdlWindow_, &dw, &dh); + scaleX_ = dw > 0 ? static_cast(dw) / width_ : 1.0f; + scaleY_ = dh > 0 ? static_cast(dh) / height_ : 1.0f; + } } -void SDL2Window::handleEvent(const SDL_Event& event) { - if (input_) { - input_->handleSDLEvent(event); - } - - switch (event.type) { - case SDL_QUIT: - shouldClose_ = true; - if (closeCb_) closeCb_(); - break; - - case SDL_WINDOWEVENT: - switch (event.window.event) { - case SDL_WINDOWEVENT_RESIZED: - case SDL_WINDOWEVENT_SIZE_CHANGED: - width_ = event.window.data1; - height_ = event.window.data2; - updateContentScale(); - if (resizeCb_) resizeCb_(width_, height_); - break; - - case SDL_WINDOWEVENT_FOCUS_GAINED: - focused_ = true; - if (focusCb_) focusCb_(true); - break; - - case SDL_WINDOWEVENT_FOCUS_LOST: - focused_ = false; - if (focusCb_) focusCb_(false); - break; - - case SDL_WINDOWEVENT_MINIMIZED: - minimized_ = true; - break; - - case SDL_WINDOWEVENT_RESTORED: - minimized_ = false; - break; - - case SDL_WINDOWEVENT_CLOSE: - shouldClose_ = true; - if (closeCb_) closeCb_(); - break; - } - break; +void SDL2Window::handleEvent(const SDL_Event &event) { + if (input_) { + input_->handleSDLEvent(event); + } + + switch (event.type) { + case SDL_QUIT: + shouldClose_ = true; + if (closeCb_) + closeCb_(); + break; + + case SDL_WINDOWEVENT: + switch (event.window.event) { + case SDL_WINDOWEVENT_RESIZED: + case SDL_WINDOWEVENT_SIZE_CHANGED: + width_ = event.window.data1; + height_ = event.window.data2; + updateContentScale(); + if (resizeCb_) + resizeCb_(width_, height_); + break; + + case SDL_WINDOWEVENT_FOCUS_GAINED: + focused_ = true; + if (focusCb_) + focusCb_(true); + break; + + case SDL_WINDOWEVENT_FOCUS_LOST: + focused_ = false; + if (focusCb_) + focusCb_(false); + break; + + case SDL_WINDOWEVENT_MINIMIZED: + minimized_ = true; + break; + + case SDL_WINDOWEVENT_RESTORED: + minimized_ = false; + break; + + case SDL_WINDOWEVENT_CLOSE: + shouldClose_ = true; + if (closeCb_) + closeCb_(); + break; } + break; + } } -} +} // namespace extra2d diff --git a/Extra2D/src/platform/window_module.cpp b/Extra2D/src/platform/window_module.cpp index 04a274d..15b3e78 100644 --- a/Extra2D/src/platform/window_module.cpp +++ b/Extra2D/src/platform/window_module.cpp @@ -1,7 +1,7 @@ -#include -#include #include -#include +#include +#include +#include #ifdef __SWITCH__ #include @@ -16,61 +16,63 @@ void initSDL2Backend(); #elif defined(E2D_BACKEND_GLFW) void initGLFWBackend(); #endif -} +} // namespace platform -WindowModule::WindowModule(std::function configFn) { - configFn(cfg_); +WindowModule::WindowModule(std::function configFn) { + configFn(cfg_); } WindowModule::~WindowModule() { - if (initialized_) { - shutdown(); - } + if (initialized_) { + shutdown(); + } } bool WindowModule::init() { - if (initialized_) return true; + if (initialized_) + return true; - // 初始化后端(注册到工厂) + // 初始化后端(注册到工厂) #if defined(E2D_BACKEND_SDL2) - platform::initSDL2Backend(); + platform::initSDL2Backend(); #elif defined(E2D_BACKEND_GLFW) - platform::initGLFWBackend(); + platform::initGLFWBackend(); #else - #error "No window backend defined" +#error "No window backend defined" #endif - E2D_LOG_INFO("Window backend initialized"); + E2D_LOG_INFO("Window backend initialized"); - E2D_LOG_INFO("Creating window with size {}x{}", cfg_.w, cfg_.h); + E2D_LOG_INFO("Creating window with size {}x{}", cfg_.w, cfg_.h); - // 创建窗口(使用配置的后端) - win_ = platform::BackendFactory::createWindow(cfg_.backend); - if (!win_) { - E2D_LOG_ERROR("Failed to create window backend: {}", cfg_.backend); - return false; - } + // 创建窗口(使用配置的后端) + win_ = platform::BackendFactory::createWindow(cfg_.backend); + if (!win_) { + E2D_LOG_ERROR("Failed to create window backend: {}", cfg_.backend); + return false; + } - if (!win_->create(cfg_.title, cfg_.w, cfg_.h, cfg_.vsync)) { - E2D_LOG_ERROR("Failed to create window"); - shutdown(); - return false; - } + if (!win_->create(cfg_.title, cfg_.w, cfg_.h, cfg_.vsync)) { + E2D_LOG_ERROR("Failed to create window"); + shutdown(); + return false; + } - E2D_LOG_INFO("Window created successfully"); - initialized_ = true; - return true; + E2D_LOG_INFO("Window created successfully"); + initialized_ = true; + return true; } void WindowModule::shutdown() { - if (!initialized_) return; - - if (win_) { - win_->destroy(); - win_.reset(); - } - - initialized_ = false; + if (!initialized_) + return; + + if (win_) { + win_->destroy(); + win_.reset(); + } + + initialized_ = false; } } // namespace extra2d diff --git a/Extra2D/src/scene/node.cpp b/Extra2D/src/scene/node.cpp index 94752cf..c216a15 100644 --- a/Extra2D/src/scene/node.cpp +++ b/Extra2D/src/scene/node.cpp @@ -1,9 +1,11 @@ #include #include +#include #include #include #include -#include +#include + namespace extra2d { @@ -521,13 +523,13 @@ void Node::onRender(RenderBackend &renderer) { return; renderer.pushTransform(getLocalTransform()); - + onDraw(renderer); for (auto &child : children_) { child->onRender(renderer); } - + renderer.popTransform(); } diff --git a/Extra2D/src/scene/scene.cpp b/Extra2D/src/scene/scene.cpp index 126eb6e..db7572a 100644 --- a/Extra2D/src/scene/scene.cpp +++ b/Extra2D/src/scene/scene.cpp @@ -1,7 +1,9 @@ +#include #include #include #include -#include +#include + namespace extra2d { diff --git a/Extra2D/src/scene/scene_manager.cpp b/Extra2D/src/scene/scene_manager.cpp index a7dab1b..56077d8 100644 --- a/Extra2D/src/scene/scene_manager.cpp +++ b/Extra2D/src/scene/scene_manager.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -10,7 +11,8 @@ #include #include #include -#include +#include + namespace extra2d { @@ -748,7 +750,8 @@ void SceneManager::finishTransition() { */ void SceneManager::dispatchPointerEvents(Scene &scene) { auto *input = Application::get().input(); - if (!input) return; + if (!input) + return; Vec2 screenPos = input->mouse(); Vec2 worldPos = screenPos; @@ -832,7 +835,6 @@ void SceneManager::dispatchPointerEvents(Scene &scene) { lastPointerWorld_ = worldPos; } -void SceneManager::doSceneSwitch() { -} +void SceneManager::doSceneSwitch() {} } // namespace extra2d diff --git a/Extra2D/src/scene/transition_fade_scene.cpp b/Extra2D/src/scene/transition_fade_scene.cpp index 9767dbb..ef26fec 100644 --- a/Extra2D/src/scene/transition_fade_scene.cpp +++ b/Extra2D/src/scene/transition_fade_scene.cpp @@ -1,9 +1,9 @@ -#include #include +#include #include #include -#include -#include +#include +#include #include namespace extra2d { diff --git a/Extra2D/src/scene/transition_scene.cpp b/Extra2D/src/scene/transition_scene.cpp index c6975ea..a5b6df2 100644 --- a/Extra2D/src/scene/transition_scene.cpp +++ b/Extra2D/src/scene/transition_scene.cpp @@ -1,6 +1,7 @@ -#include +#include #include -#include +#include +#include namespace extra2d {