refactor: 移除logger.h头文件并统一使用logger_service.h

将项目中所有对logger.h的引用替换为logger_service.h,并删除logger.h文件。同时调整了部分文件的include顺序和格式,保持代码风格一致。
This commit is contained in:
ChestnutYueyue 2026-02-18 19:10:31 +08:00
parent 6008331fc5
commit 65b143573c
35 changed files with 3781 additions and 3666 deletions

View File

@ -1,18 +1,19 @@
#pragma once #pragma once
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/texture/texture.h>
#include <extra2d/utils/logger.h>
#include <atomic> #include <atomic>
#include <chrono> #include <chrono>
#include <cstdint> #include <cstdint>
#include <extra2d/core/math_types.h>
#include <extra2d/core/service_locator.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/texture/texture.h>
#include <extra2d/services/logger_service.h>
#include <functional> #include <functional>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
namespace extra2d { namespace extra2d {
// 前向声明 // 前向声明

View File

@ -3,7 +3,6 @@
#include <extra2d/core/service_interface.h> #include <extra2d/core/service_interface.h>
#include <extra2d/core/service_locator.h> #include <extra2d/core/service_locator.h>
#include <extra2d/core/types.h> #include <extra2d/core/types.h>
#include <cstdarg>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
@ -47,42 +46,42 @@ public:
/** /**
* @brief * @brief
*/ */
virtual void log(LogLevel level, const char* fmt, ...) = 0; virtual void log(LogLevel level, const char *fmt, ...) = 0;
/** /**
* @brief * @brief
*/ */
virtual void log(LogLevel level, const std::string& msg) = 0; virtual void log(LogLevel level, const std::string &msg) = 0;
/** /**
* @brief Trace级别日志 * @brief Trace级别日志
*/ */
virtual void trace(const char* fmt, ...) = 0; virtual void trace(const char *fmt, ...) = 0;
/** /**
* @brief Debug级别日志 * @brief Debug级别日志
*/ */
virtual void debug(const char* fmt, ...) = 0; virtual void debug(const char *fmt, ...) = 0;
/** /**
* @brief Info级别日志 * @brief Info级别日志
*/ */
virtual void info(const char* fmt, ...) = 0; virtual void info(const char *fmt, ...) = 0;
/** /**
* @brief Warn级别日志 * @brief Warn级别日志
*/ */
virtual void warn(const char* fmt, ...) = 0; virtual void warn(const char *fmt, ...) = 0;
/** /**
* @brief Error级别日志 * @brief Error级别日志
*/ */
virtual void error(const char* fmt, ...) = 0; virtual void error(const char *fmt, ...) = 0;
/** /**
* @brief Fatal级别日志 * @brief Fatal级别日志
*/ */
virtual void fatal(const char* fmt, ...) = 0; virtual void fatal(const char *fmt, ...) = 0;
ServiceInfo getServiceInfo() const override { ServiceInfo getServiceInfo() const override {
ServiceInfo info; ServiceInfo info;
@ -108,19 +107,19 @@ public:
LogLevel getLevel() const override; LogLevel getLevel() const override;
bool isEnabled(LogLevel level) const override; bool isEnabled(LogLevel level) const override;
void log(LogLevel level, const char* fmt, ...) override; void log(LogLevel level, const char *fmt, ...) override;
void log(LogLevel level, const std::string& msg) override; void log(LogLevel level, const std::string &msg) override;
void trace(const char* fmt, ...) override; void trace(const char *fmt, ...) override;
void debug(const char* fmt, ...) override; void debug(const char *fmt, ...) override;
void info(const char* fmt, ...) override; void info(const char *fmt, ...) override;
void warn(const char* fmt, ...) override; void warn(const char *fmt, ...) override;
void error(const char* fmt, ...) override; void error(const char *fmt, ...) override;
void fatal(const char* fmt, ...) override; void fatal(const char *fmt, ...) override;
private: private:
void output(LogLevel level, const char* msg); void output(LogLevel level, const char *msg);
const char* getLevelString(LogLevel level); const char *getLevelString(LogLevel level);
LogLevel level_; LogLevel level_;
class Impl; class Impl;
@ -135,12 +134,11 @@ private:
// 格式化辅助函数 - 将参数转换为字符串 // 格式化辅助函数 - 将参数转换为字符串
namespace extra2d { namespace extra2d {
namespace detail { namespace detail {
template<typename T> template <typename T> std::string to_string(T &&value) {
std::string to_string(T&& value) {
using Decayed = std::decay_t<T>; using Decayed = std::decay_t<T>;
if constexpr (std::is_same_v<Decayed, std::string>) { if constexpr (std::is_same_v<Decayed, std::string>) {
return value; return value;
} else if constexpr (std::is_same_v<Decayed, const char*>) { } else if constexpr (std::is_same_v<Decayed, const char *>) {
return value ? value : "(null)"; return value ? value : "(null)";
} else if constexpr (std::is_arithmetic_v<Decayed>) { } else if constexpr (std::is_arithmetic_v<Decayed>) {
if constexpr (std::is_same_v<Decayed, bool>) { if constexpr (std::is_same_v<Decayed, bool>) {
@ -153,15 +151,14 @@ namespace detail {
} else { } else {
return "<?>"; return "<?>";
} }
} }
inline void format_impl(std::string& result, const char* fmt) { inline void format_impl(std::string &result, const char *fmt) { result += fmt; }
result += fmt;
}
template<typename T, typename... Args> template <typename T, typename... Args>
void format_impl(std::string& result, const char* fmt, T&& value, Args&&... args) { void format_impl(std::string &result, const char *fmt, T &&value,
const char* p = fmt; Args &&...args) {
const char *p = fmt;
while (*p) { while (*p) {
if (*p == '{' && *(p + 1) == '}') { if (*p == '{' && *(p + 1) == '}') {
result += to_string(std::forward<T>(value)); result += to_string(std::forward<T>(value));
@ -174,11 +171,11 @@ namespace detail {
result += " "; result += " ";
result += to_string(std::forward<T>(value)); result += to_string(std::forward<T>(value));
format_impl(result, p, std::forward<Args>(args)...); format_impl(result, p, std::forward<Args>(args)...);
}
} }
} // namespace detail
template<typename... Args> template <typename... Args>
std::string format_str(const char* fmt, Args&&... args) { std::string format_str(const char *fmt, Args &&...args) {
if constexpr (sizeof...(args) == 0) { if constexpr (sizeof...(args) == 0) {
return std::string(fmt); return std::string(fmt);
} else { } else {
@ -187,35 +184,30 @@ std::string format_str(const char* fmt, Args&&... args) {
return result; return result;
} }
} }
} } // namespace extra2d
// 便捷宏 - 自动获取日志服务 // 便捷宏 - 自动获取日志服务
#define E2D_LOG(level, ...) \ #define E2D_LOG(level, ...) \
do { \ do { \
if (auto logService = ::extra2d::ServiceLocator::instance().tryGetService<::extra2d::ILogger>()) { \ if (auto logService = ::extra2d::ServiceLocator::instance() \
.tryGetService<::extra2d::ILogger>()) { \
if (logService->isEnabled(level)) { \ if (logService->isEnabled(level)) { \
logService->log(level, ::extra2d::format_str(__VA_ARGS__)); \ logService->log(level, ::extra2d::format_str(__VA_ARGS__)); \
} \ } \
} \ } \
} while(0) } while (0)
#define E2D_LOG_TRACE(...) \ #define E2D_LOG_TRACE(...) E2D_LOG(::extra2d::LogLevel::Trace, __VA_ARGS__)
E2D_LOG(::extra2d::LogLevel::Trace, __VA_ARGS__)
#define E2D_LOG_DEBUG(...) \ #define E2D_LOG_DEBUG(...) E2D_LOG(::extra2d::LogLevel::Debug, __VA_ARGS__)
E2D_LOG(::extra2d::LogLevel::Debug, __VA_ARGS__)
#define E2D_LOG_INFO(...) \ #define E2D_LOG_INFO(...) E2D_LOG(::extra2d::LogLevel::Info, __VA_ARGS__)
E2D_LOG(::extra2d::LogLevel::Info, __VA_ARGS__)
#define E2D_LOG_WARN(...) \ #define E2D_LOG_WARN(...) E2D_LOG(::extra2d::LogLevel::Warn, __VA_ARGS__)
E2D_LOG(::extra2d::LogLevel::Warn, __VA_ARGS__)
#define E2D_LOG_ERROR(...) \ #define E2D_LOG_ERROR(...) E2D_LOG(::extra2d::LogLevel::Error, __VA_ARGS__)
E2D_LOG(::extra2d::LogLevel::Error, __VA_ARGS__)
#define E2D_LOG_FATAL(...) \ #define E2D_LOG_FATAL(...) E2D_LOG(::extra2d::LogLevel::Fatal, __VA_ARGS__)
E2D_LOG(::extra2d::LogLevel::Fatal, __VA_ARGS__)
// 简写宏 // 简写宏
#define E2D_INFO(...) E2D_LOG_INFO(__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__) #define E2D_FATAL(...) E2D_LOG_FATAL(__VA_ARGS__)
#ifdef E2D_DEBUG #ifdef E2D_DEBUG
#define E2D_DEBUG_LOG(...) E2D_LOG_DEBUG(__VA_ARGS__) #define E2D_DEBUG_LOG(...) E2D_LOG_DEBUG(__VA_ARGS__)
#define E2D_TRACE(...) E2D_LOG_TRACE(__VA_ARGS__) #define E2D_TRACE(...) E2D_LOG_TRACE(__VA_ARGS__)
#else #else
#define E2D_DEBUG_LOG(...) #define E2D_DEBUG_LOG(...)
#define E2D_TRACE(...) #define E2D_TRACE(...)
#endif #endif

View File

@ -1,12 +0,0 @@
#pragma once
/**
* @file logger.h
* @brief
*
* 便 logger_service.h
*/
#include <extra2d/services/logger_service.h>
#include <extra2d/core/service_locator.h>

View File

@ -1,13 +1,12 @@
#include <extra2d/core/registry.h> #include <extra2d/core/registry.h>
#include <extra2d/utils/logger.h> #include <extra2d/core/service_locator.h>
#include <algorithm> #include <extra2d/services/logger_service.h>
#include <queue>
#include <unordered_set>
#include <iostream> #include <iostream>
#include <queue>
namespace extra2d { namespace extra2d {
Registry& Registry::instance() { Registry &Registry::instance() {
static Registry instance; static Registry instance;
return instance; return instance;
} }
@ -15,15 +14,19 @@ Registry& Registry::instance() {
bool Registry::init() { 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) { for (auto *module : sorted) {
std::cout << "[Registry] Initializing module: " << module->name() << std::endl; std::cout << "[Registry] Initializing module: " << module->name()
<< std::endl;
if (!module->init()) { if (!module->init()) {
std::cerr << "[Registry] Failed to initialize module: " << module->name() << std::endl; std::cerr << "[Registry] Failed to initialize module: " << module->name()
<< std::endl;
return false; return false;
} }
std::cout << "[Registry] Module " << module->name() << " initialized successfully" << std::endl; std::cout << "[Registry] Module " << module->name()
<< " initialized successfully" << std::endl;
} }
std::cout << "[Registry] All modules initialized" << std::endl; std::cout << "[Registry] All modules initialized" << std::endl;
@ -44,19 +47,19 @@ void Registry::clear() {
modules_.clear(); modules_.clear();
} }
std::vector<Module*> Registry::topologicalSort() { std::vector<Module *> Registry::topologicalSort() {
std::vector<Module*> result; std::vector<Module *> result;
std::unordered_map<Module*, int> inDegree; std::unordered_map<Module *, int> inDegree;
std::unordered_map<Module*, std::vector<Module*>> adj; std::unordered_map<Module *, std::vector<Module *>> adj;
// 构建图 // 构建图
for (auto& [typeIdx, module] : modules_) { for (auto &[typeIdx, module] : modules_) {
inDegree[module.get()] = 0; inDegree[module.get()] = 0;
} }
for (auto& [typeIdx, module] : modules_) { for (auto &[typeIdx, module] : modules_) {
for (auto& depType : module->deps()) { for (auto &depType : module->deps()) {
Module* dep = get(depType); Module *dep = get(depType);
if (dep) { if (dep) {
adj[dep].push_back(module.get()); adj[dep].push_back(module.get());
inDegree[module.get()]++; inDegree[module.get()]++;
@ -65,12 +68,10 @@ std::vector<Module*> Registry::topologicalSort() {
} }
// 优先级队列(优先级小的先处理) // 优先级队列(优先级小的先处理)
auto cmp = [](Module* a, Module* b) { auto cmp = [](Module *a, Module *b) { return a->priority() > b->priority(); };
return a->priority() > b->priority(); std::priority_queue<Module *, std::vector<Module *>, decltype(cmp)> pq(cmp);
};
std::priority_queue<Module*, std::vector<Module*>, decltype(cmp)> pq(cmp);
for (auto& [mod, degree] : inDegree) { for (auto &[mod, degree] : inDegree) {
if (degree == 0) { if (degree == 0) {
pq.push(mod); pq.push(mod);
} }
@ -78,11 +79,11 @@ std::vector<Module*> Registry::topologicalSort() {
// 拓扑排序 // 拓扑排序
while (!pq.empty()) { while (!pq.empty()) {
Module* curr = pq.top(); Module *curr = pq.top();
pq.pop(); pq.pop();
result.push_back(curr); result.push_back(curr);
for (Module* next : adj[curr]) { for (Module *next : adj[curr]) {
inDegree[next]--; inDegree[next]--;
if (inDegree[next] == 0) { if (inDegree[next] == 0) {
pq.push(next); pq.push(next);

View File

@ -1,23 +1,26 @@
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/backends/backend_factory.h> #include <extra2d/graphics/backends/backend_factory.h>
#include <extra2d/utils/logger.h> #include <extra2d/services/logger_service.h>
namespace extra2d { namespace extra2d {
namespace graphics { namespace graphics {
std::unordered_map<std::string, BackendFactory::BackendEntry>& BackendFactory::registry() { std::unordered_map<std::string, BackendFactory::BackendEntry> &
BackendFactory::registry() {
static std::unordered_map<std::string, BackendEntry> reg; static std::unordered_map<std::string, BackendEntry> reg;
return reg; return reg;
} }
void BackendFactory::reg(const std::string& name, BackendFn backend, void BackendFactory::reg(const std::string &name, BackendFn backend,
const std::vector<std::string>& windowBackends) { const std::vector<std::string> &windowBackends) {
registry()[name] = {backend, windowBackends}; registry()[name] = {backend, windowBackends};
E2D_LOG_DEBUG("Registered graphics backend: {} (window backends: {})", E2D_LOG_DEBUG("Registered graphics backend: {} (window backends: {})", name,
name, windowBackends.size()); windowBackends.size());
} }
UniquePtr<RenderBackend> BackendFactory::createBackend(const std::string& name) { UniquePtr<RenderBackend>
auto& reg = registry(); BackendFactory::createBackend(const std::string &name) {
auto &reg = registry();
auto it = reg.find(name); auto it = reg.find(name);
if (it != reg.end() && it->second.createFn) { if (it != reg.end() && it->second.createFn) {
E2D_LOG_INFO("Creating graphics backend: {}", name); E2D_LOG_INFO("Creating graphics backend: {}", name);
@ -36,10 +39,12 @@ UniquePtr<RenderBackend> BackendFactory::createDefaultBackend() {
return createBackend(recommended); return createBackend(recommended);
} }
UniquePtr<RenderBackend> BackendFactory::createBackendForWindow(const std::string& windowBackend) { UniquePtr<RenderBackend>
BackendFactory::createBackendForWindow(const std::string &windowBackend) {
std::string recommended = getRecommendedBackendForWindow(windowBackend); std::string recommended = getRecommendedBackendForWindow(windowBackend);
if (recommended.empty()) { if (recommended.empty()) {
E2D_LOG_ERROR("No compatible graphics backend for window backend: {}", windowBackend); E2D_LOG_ERROR("No compatible graphics backend for window backend: {}",
windowBackend);
return nullptr; return nullptr;
} }
return createBackend(recommended); return createBackend(recommended);
@ -47,24 +52,23 @@ UniquePtr<RenderBackend> BackendFactory::createBackendForWindow(const std::strin
std::vector<std::string> BackendFactory::backends() { std::vector<std::string> BackendFactory::backends() {
std::vector<std::string> result; std::vector<std::string> result;
for (const auto& pair : registry()) { for (const auto &pair : registry()) {
result.push_back(pair.first); result.push_back(pair.first);
} }
return result; return result;
} }
bool BackendFactory::has(const std::string& name) { bool BackendFactory::has(const std::string &name) {
return registry().find(name) != registry().end(); return registry().find(name) != registry().end();
} }
std::string BackendFactory::getRecommendedBackend() { std::string BackendFactory::getRecommendedBackend() {
auto& reg = registry(); auto &reg = registry();
static const std::vector<std::string> priority = { static const std::vector<std::string> priority = {
"vulkan", "opengl", "d3d12", "d3d11", "metal", "opengles" "vulkan", "opengl", "d3d12", "d3d11", "metal", "opengles"};
};
for (const auto& name : priority) { for (const auto &name : priority) {
if (reg.find(name) != reg.end()) { if (reg.find(name) != reg.end()) {
return name; return name;
} }
@ -78,43 +82,45 @@ std::string BackendFactory::getRecommendedBackend() {
return ""; return "";
} }
std::string BackendFactory::getRecommendedBackendForWindow(const std::string& windowBackend) { std::string BackendFactory::getRecommendedBackendForWindow(
auto& reg = registry(); const std::string &windowBackend) {
auto &reg = registry();
static const std::vector<std::string> priority = { static const std::vector<std::string> priority = {
"vulkan", "opengl", "d3d12", "d3d11", "metal", "opengles" "vulkan", "opengl", "d3d12", "d3d11", "metal", "opengles"};
};
for (const auto& name : priority) { for (const auto &name : priority) {
auto it = reg.find(name); auto it = reg.find(name);
if (it != reg.end() && isCompatible(name, windowBackend)) { if (it != reg.end() && isCompatible(name, windowBackend)) {
return name; return name;
} }
} }
for (const auto& pair : reg) { for (const auto &pair : reg) {
if (isCompatible(pair.first, windowBackend)) { if (isCompatible(pair.first, windowBackend)) {
return pair.first; return pair.first;
} }
} }
E2D_LOG_WARN("No compatible graphics backend for window backend: {}", windowBackend); E2D_LOG_WARN("No compatible graphics backend for window backend: {}",
windowBackend);
return ""; return "";
} }
bool BackendFactory::isCompatible(const std::string& graphicsBackend, const std::string& windowBackend) { bool BackendFactory::isCompatible(const std::string &graphicsBackend,
auto& reg = registry(); const std::string &windowBackend) {
auto &reg = registry();
auto it = reg.find(graphicsBackend); auto it = reg.find(graphicsBackend);
if (it == reg.end()) { if (it == reg.end()) {
return false; return false;
} }
const auto& windowBackends = it->second.windowBackends; const auto &windowBackends = it->second.windowBackends;
if (windowBackends.empty()) { if (windowBackends.empty()) {
return true; return true;
} }
for (const auto& wb : windowBackends) { for (const auto &wb : windowBackends) {
if (wb == windowBackend) { if (wb == windowBackend) {
return true; return true;
} }
@ -123,8 +129,9 @@ bool BackendFactory::isCompatible(const std::string& graphicsBackend, const std:
return false; return false;
} }
std::vector<std::string> BackendFactory::getSupportedWindowBackends(const std::string& graphicsBackend) { std::vector<std::string>
auto& reg = registry(); BackendFactory::getSupportedWindowBackends(const std::string &graphicsBackend) {
auto &reg = registry();
auto it = reg.find(graphicsBackend); auto it = reg.find(graphicsBackend);
if (it != reg.end()) { if (it != reg.end()) {
return it->second.windowBackends; return it->second.windowBackends;

View File

@ -1,7 +1,9 @@
#include <cstring>
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/backends/opengl/gl_buffer.h> #include <extra2d/graphics/backends/opengl/gl_buffer.h>
#include <extra2d/graphics/memory/vram_manager.h> #include <extra2d/graphics/memory/vram_manager.h>
#include <extra2d/utils/logger.h> #include <extra2d/services/logger_service.h>
#include <cstring>
namespace extra2d { namespace extra2d {
@ -11,11 +13,9 @@ namespace extra2d {
GLBuffer::GLBuffer() = default; GLBuffer::GLBuffer() = default;
GLBuffer::~GLBuffer() { GLBuffer::~GLBuffer() { shutdown(); }
shutdown();
}
bool GLBuffer::init(const BufferDesc& desc) { bool GLBuffer::init(const BufferDesc &desc) {
if (bufferID_ != 0) { if (bufferID_ != 0) {
shutdown(); shutdown();
} }
@ -35,14 +35,16 @@ bool GLBuffer::init(const BufferDesc& desc) {
// 绑定并分配缓冲区 // 绑定并分配缓冲区
glBindBuffer(target_, bufferID_); glBindBuffer(target_, bufferID_);
glBufferData(target_, static_cast<GLsizeiptr>(size_), desc.initialData, glUsage_); glBufferData(target_, static_cast<GLsizeiptr>(size_), desc.initialData,
glUsage_);
glBindBuffer(target_, 0); glBindBuffer(target_, 0);
// 追踪显存使用 // 追踪显存使用
VRAMMgr::get().allocBuffer(size_); VRAMMgr::get().allocBuffer(size_);
E2D_LOG_DEBUG("GLBuffer created: ID={}, Size={}, Type={}, Usage={}", E2D_LOG_DEBUG("GLBuffer created: ID={}, Size={}, Type={}, Usage={}",
bufferID_, size_, static_cast<int>(type_), static_cast<int>(usage_)); bufferID_, size_, static_cast<int>(type_),
static_cast<int>(usage_));
return true; return true;
} }
@ -69,11 +71,9 @@ void GLBuffer::bind() {
} }
} }
void GLBuffer::unbind() { void GLBuffer::unbind() { glBindBuffer(target_, 0); }
glBindBuffer(target_, 0);
}
void GLBuffer::setData(const void* data, size_t size) { void GLBuffer::setData(const void *data, size_t size) {
if (bufferID_ == 0) { if (bufferID_ == 0) {
return; return;
} }
@ -92,23 +92,25 @@ void GLBuffer::setData(const void* data, size_t size) {
unbind(); unbind();
} }
void GLBuffer::updateData(const void* data, size_t offset, size_t size) { void GLBuffer::updateData(const void *data, size_t offset, size_t size) {
if (bufferID_ == 0 || data == nullptr || size == 0) { if (bufferID_ == 0 || data == nullptr || size == 0) {
return; return;
} }
if (offset + size > size_) { if (offset + size > size_) {
E2D_LOG_WARN("GLBuffer updateData out of bounds: offset={}, size={}, bufferSize={}", E2D_LOG_WARN(
"GLBuffer updateData out of bounds: offset={}, size={}, bufferSize={}",
offset, size, size_); offset, size, size_);
return; return;
} }
bind(); bind();
glBufferSubData(target_, static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(size), data); glBufferSubData(target_, static_cast<GLintptr>(offset),
static_cast<GLsizeiptr>(size), data);
unbind(); unbind();
} }
void* GLBuffer::map() { void *GLBuffer::map() {
if (bufferID_ == 0 || mapped_) { if (bufferID_ == 0 || mapped_) {
return nullptr; return nullptr;
} }
@ -121,7 +123,8 @@ void* GLBuffer::map() {
access |= GL_MAP_INVALIDATE_BUFFER_BIT; // 暗示驱动可以丢弃旧数据 access |= GL_MAP_INVALIDATE_BUFFER_BIT; // 暗示驱动可以丢弃旧数据
} }
mappedPtr_ = glMapBufferRange(target_, 0, static_cast<GLsizeiptr>(size_), access); mappedPtr_ =
glMapBufferRange(target_, 0, static_cast<GLsizeiptr>(size_), access);
if (mappedPtr_) { if (mappedPtr_) {
mapped_ = true; mapped_ = true;
} else { } else {

View File

@ -1,8 +1,7 @@
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/backends/opengl/gl_context.h> #include <extra2d/graphics/backends/opengl/gl_context.h>
#include <extra2d/graphics/memory/gpu_context.h> #include <extra2d/graphics/memory/gpu_context.h>
#include <extra2d/utils/logger.h> #include <extra2d/services/logger_service.h>
#include <cstring>
#include <sstream>
namespace extra2d { namespace extra2d {
@ -10,7 +9,7 @@ namespace extra2d {
// GLContext 实现 // GLContext 实现
// ============================================================================ // ============================================================================
GLContext& GLContext::get() { GLContext &GLContext::get() {
static GLContext instance; static GLContext instance;
return instance; return instance;
} }
@ -57,26 +56,28 @@ void GLContext::shutdown() {
} }
std::string GLContext::getVersionString() const { std::string GLContext::getVersionString() const {
const char* version = reinterpret_cast<const char*>(glGetString(GL_VERSION)); const char *version = reinterpret_cast<const char *>(glGetString(GL_VERSION));
return version ? version : "Unknown"; return version ? version : "Unknown";
} }
std::string GLContext::getVendor() const { std::string GLContext::getVendor() const {
const char* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR)); const char *vendor = reinterpret_cast<const char *>(glGetString(GL_VENDOR));
return vendor ? vendor : "Unknown"; return vendor ? vendor : "Unknown";
} }
std::string GLContext::getRenderer() const { std::string GLContext::getRenderer() const {
const char* renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER)); const char *renderer =
reinterpret_cast<const char *>(glGetString(GL_RENDERER));
return renderer ? renderer : "Unknown"; return renderer ? renderer : "Unknown";
} }
bool GLContext::hasExtension(const std::string& extension) const { bool GLContext::hasExtension(const std::string &extension) const {
GLint numExtensions = 0; GLint numExtensions = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
for (GLint i = 0; i < numExtensions; ++i) { for (GLint i = 0; i < numExtensions; ++i) {
const char* ext = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i)); const char *ext =
reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i));
if (ext && extension == ext) { if (ext && extension == ext) {
return true; return true;
} }
@ -138,7 +139,8 @@ bool GLContext::hasShader() const {
} }
void GLContext::parseVersion() { void GLContext::parseVersion() {
const char* versionStr = reinterpret_cast<const char*>(glGetString(GL_VERSION)); const char *versionStr =
reinterpret_cast<const char *>(glGetString(GL_VERSION));
if (!versionStr) { if (!versionStr) {
version_ = GLVersion{0, 0, false}; version_ = GLVersion{0, 0, false};
return; return;
@ -150,7 +152,8 @@ void GLContext::parseVersion() {
if (version.find("OpenGL ES") != std::string::npos) { if (version.find("OpenGL ES") != std::string::npos) {
version_.es = true; version_.es = true;
// 解析 ES 版本号,格式如 "OpenGL ES 3.0" // 解析 ES 版本号,格式如 "OpenGL ES 3.0"
std::sscanf(version.c_str(), "OpenGL ES %d.%d", &version_.major, &version_.minor); std::sscanf(version.c_str(), "OpenGL ES %d.%d", &version_.major,
&version_.minor);
} else { } else {
version_.es = false; version_.es = false;
// 解析桌面版本号,格式如 "3.3.0 NVIDIA" // 解析桌面版本号,格式如 "3.3.0 NVIDIA"

View File

@ -1,8 +1,8 @@
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/backends/opengl/gl_font_atlas.h> #include <extra2d/graphics/backends/opengl/gl_font_atlas.h>
#include <extra2d/utils/logger.h> #include <extra2d/services/logger_service.h>
#include <algorithm> #include <algorithm>
#include <cmath>
#include <cstring> #include <cstring>
#include <fstream> #include <fstream>

View File

@ -1,6 +1,8 @@
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/backends/opengl/gl_framebuffer.h> #include <extra2d/graphics/backends/opengl/gl_framebuffer.h>
#include <extra2d/graphics/backends/opengl/gl_texture.h> #include <extra2d/graphics/backends/opengl/gl_texture.h>
#include <extra2d/utils/logger.h> #include <extra2d/services/logger_service.h>
namespace extra2d { namespace extra2d {
@ -10,11 +12,9 @@ namespace extra2d {
GLFramebuffer::GLFramebuffer() = default; GLFramebuffer::GLFramebuffer() = default;
GLFramebuffer::~GLFramebuffer() { GLFramebuffer::~GLFramebuffer() { shutdown(); }
shutdown();
}
bool GLFramebuffer::init(const FramebufferDesc& desc) { bool GLFramebuffer::init(const FramebufferDesc &desc) {
if (fboID_ != 0) { if (fboID_ != 0) {
shutdown(); shutdown();
} }
@ -51,7 +51,7 @@ void GLFramebuffer::shutdown() {
} }
// 清理纹理引用 // 清理纹理引用
for (auto& tex : colorTextures_) { for (auto &tex : colorTextures_) {
tex.reset(); tex.reset();
} }
depthTexture_.reset(); depthTexture_.reset();
@ -66,19 +66,19 @@ void GLFramebuffer::bind() {
} }
} }
void GLFramebuffer::unbind() { void GLFramebuffer::unbind() { glBindFramebuffer(GL_FRAMEBUFFER, 0); }
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void GLFramebuffer::attachColorTexture(Ptr<Texture> texture, int attachment) { void GLFramebuffer::attachColorTexture(Ptr<Texture> texture, int attachment) {
if (fboID_ == 0 || !texture || attachment < 0 || attachment >= MAX_COLOR_ATTACHMENTS) { if (fboID_ == 0 || !texture || attachment < 0 ||
attachment >= MAX_COLOR_ATTACHMENTS) {
return; return;
} }
bind(); bind();
// 获取 OpenGL 纹理 ID // 获取 OpenGL 纹理 ID
GLuint texID = static_cast<GLuint>(reinterpret_cast<uintptr_t>(texture->getNativeHandle())); GLuint texID = static_cast<GLuint>(
reinterpret_cast<uintptr_t>(texture->getNativeHandle()));
glFramebufferTexture2D(GL_FRAMEBUFFER, getColorAttachment(attachment), glFramebufferTexture2D(GL_FRAMEBUFFER, getColorAttachment(attachment),
GL_TEXTURE_2D, texID, 0); GL_TEXTURE_2D, texID, 0);
@ -96,10 +96,11 @@ void GLFramebuffer::attachDepthTexture(Ptr<Texture> texture) {
bind(); bind();
// 获取 OpenGL 纹理 ID // 获取 OpenGL 纹理 ID
GLuint texID = static_cast<GLuint>(reinterpret_cast<uintptr_t>(texture->getNativeHandle())); GLuint texID = static_cast<GLuint>(
reinterpret_cast<uintptr_t>(texture->getNativeHandle()));
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
GL_TEXTURE_2D, texID, 0); texID, 0);
depthTexture_ = texture; depthTexture_ = texture;
hasDepth_ = true; hasDepth_ = true;
@ -116,7 +117,8 @@ void GLFramebuffer::attachDepthStencilTexture(Ptr<Texture> texture) {
bind(); bind();
// 获取 OpenGL 纹理 ID // 获取 OpenGL 纹理 ID
GLuint texID = static_cast<GLuint>(reinterpret_cast<uintptr_t>(texture->getNativeHandle())); GLuint texID = static_cast<GLuint>(
reinterpret_cast<uintptr_t>(texture->getNativeHandle()));
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
GL_TEXTURE_2D, texID, 0); GL_TEXTURE_2D, texID, 0);
@ -147,12 +149,10 @@ Ptr<Texture> GLFramebuffer::getColorTexture(int attachment) const {
return nullptr; return nullptr;
} }
Ptr<Texture> GLFramebuffer::getDepthTexture() const { Ptr<Texture> GLFramebuffer::getDepthTexture() const { return depthTexture_; }
return depthTexture_;
}
void GLFramebuffer::clear(const Color& color, bool clearColor, void GLFramebuffer::clear(const Color &color, bool clearColor, bool clearDepth,
bool clearDepth, bool clearStencil) { bool clearStencil) {
if (fboID_ == 0) { if (fboID_ == 0) {
return; return;
} }
@ -188,7 +188,7 @@ void GLFramebuffer::setViewport(int x, int y, int width, int height) {
} }
bool GLFramebuffer::readPixels(int x, int y, int width, int height, bool GLFramebuffer::readPixels(int x, int y, int width, int height,
std::vector<uint8_t>& outData) { std::vector<uint8_t> &outData) {
if (fboID_ == 0 || width <= 0 || height <= 0) { if (fboID_ == 0 || width <= 0 || height <= 0) {
return false; return false;
} }
@ -237,17 +237,21 @@ bool GLFramebuffer::checkStatus() {
E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_UNDEFINED"); E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_UNDEFINED");
break; break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); E2D_LOG_ERROR(
"Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
break; break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"); E2D_LOG_ERROR(
"Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
break; break;
#ifndef GL_ES_VERSION_2_0 #ifndef GL_ES_VERSION_2_0
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"); E2D_LOG_ERROR(
"Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER");
break; break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"); E2D_LOG_ERROR(
"Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER");
break; break;
#endif #endif
case GL_FRAMEBUFFER_UNSUPPORTED: case GL_FRAMEBUFFER_UNSUPPORTED:

View File

@ -1,5 +1,7 @@
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/backends/opengl/gl_pipeline.h> #include <extra2d/graphics/backends/opengl/gl_pipeline.h>
#include <extra2d/utils/logger.h> #include <extra2d/services/logger_service.h>
namespace extra2d { namespace extra2d {
@ -9,11 +11,9 @@ namespace extra2d {
GLPipeline::GLPipeline() = default; GLPipeline::GLPipeline() = default;
GLPipeline::~GLPipeline() { GLPipeline::~GLPipeline() { shutdown(); }
shutdown();
}
bool GLPipeline::init(const PipelineDesc& desc) { bool GLPipeline::init(const PipelineDesc &desc) {
if (initialized_) { if (initialized_) {
shutdown(); shutdown();
} }
@ -27,15 +27,14 @@ bool GLPipeline::init(const PipelineDesc& desc) {
initialized_ = true; initialized_ = true;
E2D_LOG_DEBUG("GLPipeline initialized: blendMode={}, depthTest={}, cullMode={}", E2D_LOG_DEBUG(
"GLPipeline initialized: blendMode={}, depthTest={}, cullMode={}",
static_cast<int>(blendMode_), depthTest_, static_cast<int>(cullMode_)); static_cast<int>(blendMode_), depthTest_, static_cast<int>(cullMode_));
return true; return true;
} }
void GLPipeline::shutdown() { void GLPipeline::shutdown() { initialized_ = false; }
initialized_ = false;
}
void GLPipeline::bind() { void GLPipeline::bind() {
if (!initialized_) { if (!initialized_) {
@ -91,7 +90,7 @@ void GLPipeline::setViewport(int x, int y, int width, int height) {
} }
} }
void GLPipeline::getViewport(int& x, int& y, int& width, int& height) const { void GLPipeline::getViewport(int &x, int &y, int &width, int &height) const {
x = viewportX_; x = viewportX_;
y = viewportY_; y = viewportY_;
width = viewportWidth_; width = viewportWidth_;
@ -171,7 +170,8 @@ void GLPipeline::applyCullState() {
} }
} }
void GLPipeline::getBlendFactors(BlendMode mode, GLenum& srcFactor, GLenum& dstFactor) { void GLPipeline::getBlendFactors(BlendMode mode, GLenum &srcFactor,
GLenum &dstFactor) {
switch (mode) { switch (mode) {
case BlendMode::None: case BlendMode::None:
srcFactor = GL_ONE; srcFactor = GL_ONE;
@ -198,24 +198,37 @@ void GLPipeline::getBlendFactors(BlendMode mode, GLenum& srcFactor, GLenum& dstF
GLenum GLPipeline::convertDepthFunc(DepthFunc func) { GLenum GLPipeline::convertDepthFunc(DepthFunc func) {
switch (func) { switch (func) {
case DepthFunc::Never: return GL_NEVER; case DepthFunc::Never:
case DepthFunc::Less: return GL_LESS; return GL_NEVER;
case DepthFunc::Equal: return GL_EQUAL; case DepthFunc::Less:
case DepthFunc::LessEqual: return GL_LEQUAL; return GL_LESS;
case DepthFunc::Greater: return GL_GREATER; case DepthFunc::Equal:
case DepthFunc::NotEqual: return GL_NOTEQUAL; return GL_EQUAL;
case DepthFunc::GreaterEqual: return GL_GEQUAL; case DepthFunc::LessEqual:
case DepthFunc::Always: return GL_ALWAYS; return GL_LEQUAL;
default: return GL_LESS; 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) { GLenum GLPipeline::convertCullMode(CullMode mode) {
switch (mode) { switch (mode) {
case CullMode::Front: return GL_FRONT; case CullMode::Front:
case CullMode::Back: return GL_BACK; return GL_FRONT;
case CullMode::Both: return GL_FRONT_AND_BACK; case CullMode::Back:
default: return GL_BACK; return GL_BACK;
case CullMode::Both:
return GL_FRONT_AND_BACK;
default:
return GL_BACK;
} }
} }

View File

@ -1,6 +1,6 @@
#include <algorithm>
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/backends/opengl/gl_context.h> #include <extra2d/graphics/backends/opengl/gl_context.h>
#include <extra2d/graphics/backends/opengl/gl_font_atlas.h> #include <extra2d/graphics/backends/opengl/gl_font_atlas.h>
#include <extra2d/graphics/backends/opengl/gl_framebuffer.h> #include <extra2d/graphics/backends/opengl/gl_framebuffer.h>
@ -11,7 +11,7 @@
#include <extra2d/graphics/memory/vram_manager.h> #include <extra2d/graphics/memory/vram_manager.h>
#include <extra2d/graphics/shader/shader_manager.h> #include <extra2d/graphics/shader/shader_manager.h>
#include <extra2d/platform/iwindow.h> #include <extra2d/platform/iwindow.h>
#include <extra2d/utils/logger.h> #include <extra2d/services/logger_service.h>
#include <vector> #include <vector>
namespace extra2d { namespace extra2d {
@ -23,8 +23,8 @@ static constexpr size_t SHAPE_VBO_SIZE = 1024 * sizeof(float);
* @brief OpenGL渲染器成员变量 * @brief OpenGL渲染器成员变量
*/ */
GLRenderer::GLRenderer() GLRenderer::GLRenderer()
: window_(nullptr), shapeVao_(0), lineVao_(0), : window_(nullptr), shapeVao_(0), lineVao_(0), vsync_(true),
vsync_(true), shapeVertexCount_(0), currentShapeMode_(GL_TRIANGLES), shapeVertexCount_(0), currentShapeMode_(GL_TRIANGLES),
lineVertexCount_(0), currentLineWidth_(1.0f) { lineVertexCount_(0), currentLineWidth_(1.0f) {
resetStats(); resetStats();
for (auto &v : shapeVertexCache_) { for (auto &v : shapeVertexCache_) {
@ -48,7 +48,8 @@ GLRenderer::~GLRenderer() { shutdown(); }
bool GLRenderer::init(IWindow *window) { bool GLRenderer::init(IWindow *window) {
window_ = window; window_ = window;
// 初始化 OpenGL 上下文Switch 平台已通过 SDL2 + EGL 初始化GLContext 会处理兼容性) // 初始化 OpenGL 上下文Switch 平台已通过 SDL2 + EGL 初始化GLContext
// 会处理兼容性)
if (!GLContext::get().init()) { if (!GLContext::get().init()) {
E2D_LOG_ERROR("Failed to initialize OpenGL context"); E2D_LOG_ERROR("Failed to initialize OpenGL context");
return false; return false;
@ -937,7 +938,7 @@ void GLRenderer::flushLineBatch() {
* @param desc * @param desc
* @return * @return
*/ */
Ptr<GLFramebuffer> GLRenderer::createFramebuffer(const FramebufferDesc& desc) { Ptr<GLFramebuffer> GLRenderer::createFramebuffer(const FramebufferDesc &desc) {
auto framebuffer = makePtr<GLFramebuffer>(); auto framebuffer = makePtr<GLFramebuffer>();
if (!framebuffer->init(desc)) { if (!framebuffer->init(desc)) {
E2D_LOG_ERROR("Failed to create framebuffer"); E2D_LOG_ERROR("Failed to create framebuffer");
@ -950,7 +951,7 @@ Ptr<GLFramebuffer> GLRenderer::createFramebuffer(const FramebufferDesc& desc) {
* @brief * @brief
* @param framebuffer nullptr * @param framebuffer nullptr
*/ */
void GLRenderer::bindFramebuffer(GLFramebuffer* framebuffer) { void GLRenderer::bindFramebuffer(GLFramebuffer *framebuffer) {
// 先刷新所有待处理的渲染批次 // 先刷新所有待处理的渲染批次
flush(); flush();
flushShapeBatch(); flushShapeBatch();
@ -972,9 +973,7 @@ void GLRenderer::bindFramebuffer(GLFramebuffer* framebuffer) {
/** /**
* @brief * @brief
*/ */
void GLRenderer::unbindFramebuffer() { void GLRenderer::unbindFramebuffer() { bindFramebuffer(nullptr); }
bindFramebuffer(nullptr);
}
/** /**
* @brief * @brief
@ -996,7 +995,7 @@ Ptr<GLFramebuffer> GLRenderer::getDefaultFramebuffer() const {
* @param clearDepth * @param clearDepth
* @param clearStencil * @param clearStencil
*/ */
void GLRenderer::clearFramebuffer(const Color& color, bool clearColor, void GLRenderer::clearFramebuffer(const Color &color, bool clearColor,
bool clearDepth, bool clearStencil) { bool clearDepth, bool clearStencil) {
GLbitfield mask = 0; GLbitfield mask = 0;

View File

@ -1,13 +1,14 @@
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/backends/opengl/gl_shader.h> #include <extra2d/graphics/backends/opengl/gl_shader.h>
#include <extra2d/utils/logger.h> #include <extra2d/services/logger_service.h>
namespace extra2d { namespace extra2d {
/** /**
* @brief ID为0 * @brief ID为0
*/ */
GLShader::GLShader() : programID_(0) { GLShader::GLShader() : programID_(0) {}
}
/** /**
* @brief OpenGL着色器程序 * @brief OpenGL着色器程序
@ -22,23 +23,19 @@ GLShader::~GLShader() {
/** /**
* @brief Shader程序 * @brief Shader程序
*/ */
void GLShader::bind() const { void GLShader::bind() const { glUseProgram(programID_); }
glUseProgram(programID_);
}
/** /**
* @brief Shader程序 * @brief Shader程序
*/ */
void GLShader::unbind() const { void GLShader::unbind() const { glUseProgram(0); }
glUseProgram(0);
}
/** /**
* @brief uniform变量 * @brief uniform变量
* @param name uniform变量名 * @param name uniform变量名
* @param value * @param value
*/ */
void GLShader::setBool(const std::string& name, bool value) { void GLShader::setBool(const std::string &name, bool value) {
glUniform1i(getUniformLocation(name), value ? 1 : 0); glUniform1i(getUniformLocation(name), value ? 1 : 0);
} }
@ -47,7 +44,7 @@ void GLShader::setBool(const std::string& name, bool value) {
* @param name uniform变量名 * @param name uniform变量名
* @param value * @param value
*/ */
void GLShader::setInt(const std::string& name, int value) { void GLShader::setInt(const std::string &name, int value) {
glUniform1i(getUniformLocation(name), value); glUniform1i(getUniformLocation(name), value);
} }
@ -56,7 +53,7 @@ void GLShader::setInt(const std::string& name, int value) {
* @param name uniform变量名 * @param name uniform变量名
* @param value * @param value
*/ */
void GLShader::setFloat(const std::string& name, float value) { void GLShader::setFloat(const std::string &name, float value) {
glUniform1f(getUniformLocation(name), value); glUniform1f(getUniformLocation(name), value);
} }
@ -65,7 +62,7 @@ void GLShader::setFloat(const std::string& name, float value) {
* @param name uniform变量名 * @param name uniform变量名
* @param value * @param value
*/ */
void GLShader::setVec2(const std::string& name, const glm::vec2& value) { void GLShader::setVec2(const std::string &name, const glm::vec2 &value) {
glUniform2fv(getUniformLocation(name), 1, &value[0]); glUniform2fv(getUniformLocation(name), 1, &value[0]);
} }
@ -74,7 +71,7 @@ void GLShader::setVec2(const std::string& name, const glm::vec2& value) {
* @param name uniform变量名 * @param name uniform变量名
* @param value * @param value
*/ */
void GLShader::setVec3(const std::string& name, const glm::vec3& value) { void GLShader::setVec3(const std::string &name, const glm::vec3 &value) {
glUniform3fv(getUniformLocation(name), 1, &value[0]); glUniform3fv(getUniformLocation(name), 1, &value[0]);
} }
@ -83,7 +80,7 @@ void GLShader::setVec3(const std::string& name, const glm::vec3& value) {
* @param name uniform变量名 * @param name uniform变量名
* @param value * @param value
*/ */
void GLShader::setVec4(const std::string& name, const glm::vec4& value) { void GLShader::setVec4(const std::string &name, const glm::vec4 &value) {
glUniform4fv(getUniformLocation(name), 1, &value[0]); glUniform4fv(getUniformLocation(name), 1, &value[0]);
} }
@ -92,7 +89,7 @@ void GLShader::setVec4(const std::string& name, const glm::vec4& value) {
* @param name uniform变量名 * @param name uniform变量名
* @param value 4x4矩阵值 * @param value 4x4矩阵值
*/ */
void GLShader::setMat4(const std::string& name, const glm::mat4& value) { void GLShader::setMat4(const std::string &name, const glm::mat4 &value) {
glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, &value[0][0]); glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, &value[0][0]);
} }
@ -101,7 +98,7 @@ void GLShader::setMat4(const std::string& name, const glm::mat4& value) {
* @param name uniform变量名 * @param name uniform变量名
* @param color * @param color
*/ */
void GLShader::setColor(const std::string& name, const Color& color) { void GLShader::setColor(const std::string &name, const Color &color) {
glUniform4f(getUniformLocation(name), color.r, color.g, color.b, color.a); glUniform4f(getUniformLocation(name), color.r, color.g, color.b, color.a);
} }
@ -111,7 +108,8 @@ void GLShader::setColor(const std::string& name, const Color& color) {
* @param fragmentSource * @param fragmentSource
* @return truefalse * @return truefalse
*/ */
bool GLShader::compileFromSource(const char* vertexSource, const char* fragmentSource) { bool GLShader::compileFromSource(const char *vertexSource,
const char *fragmentSource) {
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexSource); GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexSource);
if (vertexShader == 0) { if (vertexShader == 0) {
return false; return false;
@ -154,7 +152,7 @@ bool GLShader::compileFromSource(const char* vertexSource, const char* fragmentS
* @param binary * @param binary
* @return truefalse * @return truefalse
*/ */
bool GLShader::compileFromBinary(const std::vector<uint8_t>& binary) { bool GLShader::compileFromBinary(const std::vector<uint8_t> &binary) {
if (binary.empty()) { if (binary.empty()) {
E2D_LOG_ERROR("Binary data is empty"); E2D_LOG_ERROR("Binary data is empty");
return false; return false;
@ -175,9 +173,11 @@ bool GLShader::compileFromBinary(const std::vector<uint8_t>& binary) {
programID_ = glCreateProgram(); programID_ = glCreateProgram();
GLenum binaryFormat = 0; GLenum binaryFormat = 0;
glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, reinterpret_cast<GLint*>(&binaryFormat)); glGetIntegerv(GL_PROGRAM_BINARY_FORMATS,
reinterpret_cast<GLint *>(&binaryFormat));
glProgramBinary(programID_, binaryFormat, binary.data(), static_cast<GLsizei>(binary.size())); glProgramBinary(programID_, binaryFormat, binary.data(),
static_cast<GLsizei>(binary.size()));
GLint success = 0; GLint success = 0;
glGetProgramiv(programID_, GL_LINK_STATUS, &success); glGetProgramiv(programID_, GL_LINK_STATUS, &success);
@ -198,7 +198,7 @@ bool GLShader::compileFromBinary(const std::vector<uint8_t>& binary) {
* @param outBinary * @param outBinary
* @return truefalse * @return truefalse
*/ */
bool GLShader::getBinary(std::vector<uint8_t>& outBinary) { bool GLShader::getBinary(std::vector<uint8_t> &outBinary) {
if (programID_ == 0) { if (programID_ == 0) {
E2D_LOG_WARN("Cannot get binary: shader program is 0"); E2D_LOG_WARN("Cannot get binary: shader program is 0");
return false; return false;
@ -218,7 +218,8 @@ bool GLShader::getBinary(std::vector<uint8_t>& outBinary) {
GLenum binaryFormat = 0; GLenum binaryFormat = 0;
GLsizei actualLength = 0; GLsizei actualLength = 0;
glGetProgramBinary(programID_, binaryLength, &actualLength, &binaryFormat, outBinary.data()); glGetProgramBinary(programID_, binaryLength, &actualLength, &binaryFormat,
outBinary.data());
GLenum err = glGetError(); GLenum err = glGetError();
if (err != GL_NO_ERROR) { if (err != GL_NO_ERROR) {
@ -237,7 +238,8 @@ bool GLShader::getBinary(std::vector<uint8_t>& outBinary) {
outBinary.resize(actualLength); outBinary.resize(actualLength);
} }
E2D_LOG_DEBUG("Shader binary retrieved: {} bytes, format: {}", actualLength, binaryFormat); E2D_LOG_DEBUG("Shader binary retrieved: {} bytes, format: {}", actualLength,
binaryFormat);
return true; return true;
} }
@ -247,7 +249,7 @@ bool GLShader::getBinary(std::vector<uint8_t>& outBinary) {
* @param source * @param source
* @return ID0 * @return ID0
*/ */
GLuint GLShader::compileShader(GLenum type, const char* source) { GLuint GLShader::compileShader(GLenum type, const char *source) {
GLuint shader = glCreateShader(type); GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, nullptr); glShaderSource(shader, 1, &source, nullptr);
glCompileShader(shader); glCompileShader(shader);
@ -270,7 +272,7 @@ GLuint GLShader::compileShader(GLenum type, const char* source) {
* @param name uniform变量名 * @param name uniform变量名
* @return uniform位置 * @return uniform位置
*/ */
GLint GLShader::getUniformLocation(const std::string& name) { GLint GLShader::getUniformLocation(const std::string &name) {
auto it = uniformCache_.find(name); auto it = uniformCache_.find(name);
if (it != uniformCache_.end()) { if (it != uniformCache_.end()) {
return it->second; return it->second;
@ -292,10 +294,9 @@ GLint GLShader::getUniformLocation(const std::string& name) {
* @param fragSource * @param fragSource
* @return Shader实例 * @return Shader实例
*/ */
Ptr<IShader> GLShaderFactory::createFromSource( Ptr<IShader> GLShaderFactory::createFromSource(const std::string &name,
const std::string& name, const std::string &vertSource,
const std::string& vertSource, const std::string &fragSource) {
const std::string& fragSource) {
auto shader = std::make_shared<GLShader>(); auto shader = std::make_shared<GLShader>();
shader->setName(name); shader->setName(name);
@ -314,9 +315,9 @@ Ptr<IShader> GLShaderFactory::createFromSource(
* @param binary * @param binary
* @return Shader实例 * @return Shader实例
*/ */
Ptr<IShader> GLShaderFactory::createFromBinary( Ptr<IShader>
const std::string& name, GLShaderFactory::createFromBinary(const std::string &name,
const std::vector<uint8_t>& binary) { const std::vector<uint8_t> &binary) {
auto shader = std::make_shared<GLShader>(); auto shader = std::make_shared<GLShader>();
shader->setName(name); shader->setName(name);
@ -335,14 +336,15 @@ Ptr<IShader> GLShaderFactory::createFromBinary(
* @param outBinary * @param outBinary
* @return truefalse * @return truefalse
*/ */
bool GLShaderFactory::getShaderBinary(const IShader& shader, std::vector<uint8_t>& outBinary) { bool GLShaderFactory::getShaderBinary(const IShader &shader,
const GLShader* glShader = dynamic_cast<const GLShader*>(&shader); std::vector<uint8_t> &outBinary) {
const GLShader *glShader = dynamic_cast<const GLShader *>(&shader);
if (!glShader) { if (!glShader) {
E2D_LOG_ERROR("Shader is not a GLShader instance"); E2D_LOG_ERROR("Shader is not a GLShader instance");
return false; return false;
} }
return const_cast<GLShader*>(glShader)->getBinary(outBinary); return const_cast<GLShader *>(glShader)->getBinary(outBinary);
} }
} // namespace extra2d } // namespace extra2d

View File

@ -1,7 +1,9 @@
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/backends/opengl/gl_sprite_batch.h> #include <extra2d/graphics/backends/opengl/gl_sprite_batch.h>
#include <extra2d/graphics/backends/opengl/gl_texture.h> #include <extra2d/graphics/backends/opengl/gl_texture.h>
#include <extra2d/graphics/shader/shader_manager.h> #include <extra2d/graphics/shader/shader_manager.h>
#include <extra2d/utils/logger.h> #include <extra2d/services/logger_service.h>
namespace extra2d { namespace extra2d {
@ -36,15 +38,18 @@ bool GLSpriteBatch::init() {
// 设置顶点属性 // 设置顶点属性
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(SpriteVertex), glVertexAttribPointer(
0, 2, GL_FLOAT, GL_FALSE, sizeof(SpriteVertex),
reinterpret_cast<void *>(offsetof(SpriteVertex, position))); reinterpret_cast<void *>(offsetof(SpriteVertex, position)));
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(SpriteVertex), glVertexAttribPointer(
1, 2, GL_FLOAT, GL_FALSE, sizeof(SpriteVertex),
reinterpret_cast<void *>(offsetof(SpriteVertex, texCoord))); reinterpret_cast<void *>(offsetof(SpriteVertex, texCoord)));
glEnableVertexAttribArray(2); glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(SpriteVertex), glVertexAttribPointer(
2, 4, GL_FLOAT, GL_FALSE, sizeof(SpriteVertex),
reinterpret_cast<void *>(offsetof(SpriteVertex, color))); reinterpret_cast<void *>(offsetof(SpriteVertex, color)));
// 初始化 EBO索引缓冲区- 静态使用模式 // 初始化 EBO索引缓冲区- 静态使用模式

View File

@ -3,10 +3,12 @@
#include <extra2d/graphics/memory/vram_manager.h> #include <extra2d/graphics/memory/vram_manager.h>
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include <cstring> #include <cstring>
#include <extra2d/utils/logger.h> #include <extra2d/core/service_locator.h>
#include <extra2d/services/logger_service.h>
#include <fstream> #include <fstream>
#include <stb/stb_image.h> #include <stb/stb_image.h>
namespace extra2d { namespace extra2d {
// ============================================================================ // ============================================================================

View File

@ -1,23 +1,21 @@
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/backends/vulkan/vk_renderer.h> #include <extra2d/graphics/backends/vulkan/vk_renderer.h>
#include <extra2d/utils/logger.h> #include <extra2d/services/logger_service.h>
namespace extra2d { namespace extra2d {
VulkanRenderer::VulkanRenderer() = default; VulkanRenderer::VulkanRenderer() = default;
VulkanRenderer::~VulkanRenderer() { VulkanRenderer::~VulkanRenderer() { shutdown(); }
shutdown();
}
bool VulkanRenderer::init(IWindow* window) { bool VulkanRenderer::init(IWindow *window) {
E2D_LOG_WARN("Vulkan renderer is not fully implemented yet"); E2D_LOG_WARN("Vulkan renderer is not fully implemented yet");
initialized_ = true; initialized_ = true;
return true; return true;
} }
void VulkanRenderer::shutdown() { void VulkanRenderer::shutdown() { initialized_ = false; }
initialized_ = false;
}
void VulkanRenderer::beginFrame(const Color &clearColor) { void VulkanRenderer::beginFrame(const Color &clearColor) {
// TODO: 实现Vulkan帧开始 // TODO: 实现Vulkan帧开始
@ -55,7 +53,9 @@ glm::mat4 VulkanRenderer::getCurrentTransform() const {
return glm::mat4(1.0f); return glm::mat4(1.0f);
} }
Ptr<Texture> VulkanRenderer::createTexture(int width, int height, const uint8_t *pixels, int channels) { Ptr<Texture> VulkanRenderer::createTexture(int width, int height,
const uint8_t *pixels,
int channels) {
// TODO: 实现Vulkan纹理创建 // TODO: 实现Vulkan纹理创建
return nullptr; return nullptr;
} }
@ -70,8 +70,8 @@ void VulkanRenderer::beginSpriteBatch() {
} }
void VulkanRenderer::drawSprite(const Texture &texture, const Rect &destRect, void VulkanRenderer::drawSprite(const Texture &texture, const Rect &destRect,
const Rect &srcRect, const Color &tint, float rotation, const Rect &srcRect, const Color &tint,
const Vec2 &anchor) { float rotation, const Vec2 &anchor) {
// TODO: 实现精灵绘制 // TODO: 实现精灵绘制
} }
@ -84,12 +84,13 @@ void VulkanRenderer::endSpriteBatch() {
// TODO: 实现精灵批处理结束 // TODO: 实现精灵批处理结束
} }
void VulkanRenderer::drawLine(const Vec2 &start, const Vec2 &end, const Color &color, void VulkanRenderer::drawLine(const Vec2 &start, const Vec2 &end,
float width) { const Color &color, float width) {
// TODO: 实现线条绘制 // TODO: 实现线条绘制
} }
void VulkanRenderer::drawRect(const Rect &rect, const Color &color, float width) { void VulkanRenderer::drawRect(const Rect &rect, const Color &color,
float width) {
// TODO: 实现矩形边框绘制 // TODO: 实现矩形边框绘制
} }
@ -97,28 +98,29 @@ void VulkanRenderer::fillRect(const Rect &rect, const Color &color) {
// TODO: 实现矩形填充 // TODO: 实现矩形填充
} }
void VulkanRenderer::drawCircle(const Vec2 &center, float radius, const Color &color, void VulkanRenderer::drawCircle(const Vec2 &center, float radius,
int segments, float width) { const Color &color, int segments, float width) {
// TODO: 实现圆形边框绘制 // TODO: 实现圆形边框绘制
} }
void VulkanRenderer::fillCircle(const Vec2 &center, float radius, const Color &color, void VulkanRenderer::fillCircle(const Vec2 &center, float radius,
int segments) { const Color &color, int segments) {
// TODO: 实现圆形填充 // TODO: 实现圆形填充
} }
void VulkanRenderer::drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3, void VulkanRenderer::drawTriangle(const Vec2 &p1, const Vec2 &p2,
const Color &color, float width) { const Vec2 &p3, const Color &color,
float width) {
// TODO: 实现三角形边框绘制 // TODO: 实现三角形边框绘制
} }
void VulkanRenderer::fillTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3, void VulkanRenderer::fillTriangle(const Vec2 &p1, const Vec2 &p2,
const Color &color) { const Vec2 &p3, const Color &color) {
// TODO: 实现三角形填充 // TODO: 实现三角形填充
} }
void VulkanRenderer::drawPolygon(const std::vector<Vec2> &points, const Color &color, void VulkanRenderer::drawPolygon(const std::vector<Vec2> &points,
float width) { const Color &color, float width) {
// TODO: 实现多边形边框绘制 // TODO: 实现多边形边框绘制
} }
@ -127,8 +129,8 @@ void VulkanRenderer::fillPolygon(const std::vector<Vec2> &points,
// TODO: 实现多边形填充 // TODO: 实现多边形填充
} }
Ptr<FontAtlas> VulkanRenderer::createFontAtlas(const std::string &filepath, int fontSize, Ptr<FontAtlas> VulkanRenderer::createFontAtlas(const std::string &filepath,
bool useSDF) { int fontSize, bool useSDF) {
// TODO: 实现字体图集创建 // TODO: 实现字体图集创建
return nullptr; return nullptr;
} }
@ -138,13 +140,11 @@ void VulkanRenderer::drawText(const FontAtlas &font, const std::string &text,
// TODO: 实现文本绘制 // TODO: 实现文本绘制
} }
void VulkanRenderer::drawText(const FontAtlas &font, const std::string &text, float x, void VulkanRenderer::drawText(const FontAtlas &font, const std::string &text,
float y, const Color &color) { float x, float y, const Color &color) {
// TODO: 实现文本绘制 // TODO: 实现文本绘制
} }
void VulkanRenderer::resetStats() { void VulkanRenderer::resetStats() { stats_ = Stats{}; }
stats_ = Stats{};
}
} // namespace extra2d } // namespace extra2d

View File

@ -1,5 +1,7 @@
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/batch/sprite_batch.h> #include <extra2d/graphics/batch/sprite_batch.h>
#include <extra2d/utils/logger.h> #include <extra2d/services/logger_service.h>
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
@ -47,9 +49,7 @@ float TrigLookup::cosRad(float rad) const {
// ============================================================================ // ============================================================================
// SpriteBatch 实现 // SpriteBatch 实现
// ============================================================================ // ============================================================================
SpriteBatch::SpriteBatch() SpriteBatch::SpriteBatch() : spriteCount_(0), vpDirty_(true) {
: spriteCount_(0)
, vpDirty_(true) {
// 预分配顶点缓冲区 // 预分配顶点缓冲区
vertices_.reserve(MAX_VERTICES); vertices_.reserve(MAX_VERTICES);
indices_.reserve(MAX_INDICES); indices_.reserve(MAX_INDICES);
@ -72,7 +72,7 @@ void SpriteBatch::generateIndices() {
} }
} }
void SpriteBatch::begin(const glm::mat4& viewProjection) { void SpriteBatch::begin(const glm::mat4 &viewProjection) {
viewProjection_ = viewProjection; viewProjection_ = viewProjection;
vpDirty_ = true; vpDirty_ = true;
spriteCount_ = 0; spriteCount_ = 0;
@ -83,7 +83,7 @@ void SpriteBatch::end() {
// 批次结束,数据已准备好供后端使用 // 批次结束,数据已准备好供后端使用
} }
void SpriteBatch::draw(const SpriteData& sprite) { void SpriteBatch::draw(const SpriteData &sprite) {
if (spriteCount_ >= MAX_SPRITES) { if (spriteCount_ >= MAX_SPRITES) {
// 缓冲区已满,需要刷新 // 缓冲区已满,需要刷新
flush(); flush();
@ -93,7 +93,7 @@ void SpriteBatch::draw(const SpriteData& sprite) {
spriteCount_++; spriteCount_++;
} }
void SpriteBatch::drawBatch(const std::vector<SpriteData>& sprites) { void SpriteBatch::drawBatch(const std::vector<SpriteData> &sprites) {
size_t index = 0; size_t index = 0;
while (index < sprites.size()) { while (index < sprites.size()) {
// 计算剩余空间 // 计算剩余空间
@ -117,13 +117,14 @@ void SpriteBatch::drawBatch(const std::vector<SpriteData>& sprites) {
} }
} }
void SpriteBatch::drawImmediate(const SpriteData& sprite) { void SpriteBatch::drawImmediate(const SpriteData &sprite) {
// 立即绘制模式:清空当前批次,只绘制这一个精灵 // 立即绘制模式:清空当前批次,只绘制这一个精灵
clear(); clear();
draw(sprite); draw(sprite);
} }
void SpriteBatch::generateVertices(const SpriteData& sprite, size_t vertexOffset) { void SpriteBatch::generateVertices(const SpriteData &sprite,
size_t vertexOffset) {
// 确保顶点缓冲区足够 // 确保顶点缓冲区足够
if (vertices_.size() < vertexOffset + VERTICES_PER_SPRITE) { if (vertices_.size() < vertexOffset + VERTICES_PER_SPRITE) {
vertices_.resize(vertexOffset + VERTICES_PER_SPRITE); vertices_.resize(vertexOffset + VERTICES_PER_SPRITE);
@ -148,8 +149,8 @@ void SpriteBatch::generateVertices(const SpriteData& sprite, size_t vertexOffset
// 四个角的本地坐标 // 四个角的本地坐标
Vec2 localCorners[4] = { Vec2 localCorners[4] = {
Vec2(-halfWidth - pivotOffsetX, -halfHeight - pivotOffsetY), // 左下 Vec2(-halfWidth - pivotOffsetX, -halfHeight - pivotOffsetY), // 左下
Vec2( halfWidth - pivotOffsetX, -halfHeight - pivotOffsetY), // 右下 Vec2(halfWidth - pivotOffsetX, -halfHeight - pivotOffsetY), // 右下
Vec2( halfWidth - pivotOffsetX, halfHeight - pivotOffsetY), // 右上 Vec2(halfWidth - pivotOffsetX, halfHeight - pivotOffsetY), // 右上
Vec2(-halfWidth - pivotOffsetX, halfHeight - pivotOffsetY) // 左上 Vec2(-halfWidth - pivotOffsetX, halfHeight - pivotOffsetY) // 左上
}; };

View File

@ -1,12 +1,12 @@
#include <extra2d/graphics/core/render_module.h> #include <extra2d/app/application.h>
#include <extra2d/graphics/backends/backend_factory.h>
#include <extra2d/graphics/backends/opengl/gl_shader.h>
#include <extra2d/graphics/shader/shader_manager.h>
#include <extra2d/core/registry.h> #include <extra2d/core/registry.h>
#include <extra2d/core/service_locator.h> #include <extra2d/core/service_locator.h>
#include <extra2d/app/application.h> #include <extra2d/graphics/backends/backend_factory.h>
#include <extra2d/graphics/backends/opengl/gl_shader.h>
#include <extra2d/graphics/core/render_module.h>
#include <extra2d/graphics/shader/shader_manager.h>
#include <extra2d/platform/window_module.h> #include <extra2d/platform/window_module.h>
#include <extra2d/utils/logger.h> #include <extra2d/services/logger_service.h>
#include <filesystem> #include <filesystem>
namespace extra2d { namespace extra2d {
@ -19,9 +19,9 @@ void initOpenGLBackend();
#ifdef E2D_BACKEND_VULKAN #ifdef E2D_BACKEND_VULKAN
void initVulkanBackend(); void initVulkanBackend();
#endif #endif
} } // namespace graphics
RenderModule::RenderModule(std::function<void(RenderCfg&)> configFn) { RenderModule::RenderModule(std::function<void(RenderCfg &)> configFn) {
configFn(cfg_); configFn(cfg_);
} }
@ -41,9 +41,10 @@ static std::string getExecutableDir() {
} }
bool RenderModule::init() { bool RenderModule::init() {
if (initialized_) return true; if (initialized_)
return true;
auto* winMod = Registry::instance().get<WindowModule>(); auto *winMod = Registry::instance().get<WindowModule>();
if (!winMod || !winMod->win()) { if (!winMod || !winMod->win()) {
E2D_LOG_ERROR("WindowModule not available"); E2D_LOG_ERROR("WindowModule not available");
return false; return false;
@ -62,18 +63,22 @@ bool RenderModule::init() {
std::string shaderDir = getExecutableDir() + "shaders/"; std::string shaderDir = getExecutableDir() + "shaders/";
std::string cacheDir = getExecutableDir() + "shader_cache/"; std::string cacheDir = getExecutableDir() + "shader_cache/";
if (!ShaderManager::getInstance().init(shaderDir, cacheDir, factory)) { if (!ShaderManager::getInstance().init(shaderDir, cacheDir, factory)) {
E2D_LOG_WARN("Failed to initialize ShaderManager with dir: {}", shaderDir); E2D_LOG_WARN("Failed to initialize ShaderManager with dir: {}",
shaderDir);
} }
} }
std::string windowBackend = winMod->getWindowBackend(); std::string windowBackend = winMod->getWindowBackend();
if (cfg_.backend.empty()) { if (cfg_.backend.empty()) {
E2D_LOG_INFO("No graphics backend specified, auto-selecting for window backend: {}", windowBackend); E2D_LOG_INFO(
"No graphics backend specified, auto-selecting for window backend: {}",
windowBackend);
renderer_ = graphics::BackendFactory::createBackendForWindow(windowBackend); renderer_ = graphics::BackendFactory::createBackendForWindow(windowBackend);
} else { } else {
if (!graphics::BackendFactory::isCompatible(cfg_.backend, windowBackend)) { if (!graphics::BackendFactory::isCompatible(cfg_.backend, windowBackend)) {
E2D_LOG_WARN("Graphics backend '{}' is not compatible with window backend '{}'", E2D_LOG_WARN(
"Graphics backend '{}' is not compatible with window backend '{}'",
cfg_.backend, windowBackend); cfg_.backend, windowBackend);
} }
renderer_ = graphics::BackendFactory::createBackend(cfg_.backend); renderer_ = graphics::BackendFactory::createBackend(cfg_.backend);
@ -96,7 +101,8 @@ bool RenderModule::init() {
} }
void RenderModule::shutdown() { void RenderModule::shutdown() {
if (!initialized_) return; if (!initialized_)
return;
if (renderer_) { if (renderer_) {
renderer_->shutdown(); renderer_->shutdown();

View File

@ -1,7 +1,9 @@
#include <glad/glad.h> #include <extra2d/core/service_locator.h>
#include <extra2d/graphics/backends/opengl/gl_texture.h> #include <extra2d/graphics/backends/opengl/gl_texture.h>
#include <extra2d/graphics/core/render_target.h> #include <extra2d/graphics/core/render_target.h>
#include <extra2d/utils/logger.h> #include <extra2d/services/logger_service.h>
#include <glad/glad.h>
#define STB_IMAGE_WRITE_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb/stb_image_write.h> #include <stb/stb_image_write.h>

View File

@ -1,6 +1,8 @@
#include <algorithm> #include <algorithm>
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/memory/vram_manager.h> #include <extra2d/graphics/memory/vram_manager.h>
#include <extra2d/utils/logger.h> #include <extra2d/services/logger_service.h>
namespace extra2d { namespace extra2d {

View File

@ -1,10 +1,12 @@
#include <extra2d/graphics/shader/shader_cache.h>
#include <extra2d/utils/logger.h>
#include <chrono> #include <chrono>
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/shader/shader_cache.h>
#include <extra2d/services/logger_service.h>
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
namespace extra2d { namespace extra2d {
namespace fs = std::filesystem; namespace fs = std::filesystem;
@ -13,7 +15,7 @@ namespace fs = std::filesystem;
* @brief * @brief
* @return * @return
*/ */
ShaderCache& ShaderCache::getInstance() { ShaderCache &ShaderCache::getInstance() {
static ShaderCache instance; static ShaderCache instance;
return instance; return instance;
} }
@ -23,7 +25,7 @@ ShaderCache& ShaderCache::getInstance() {
* @param cacheDir * @param cacheDir
* @return truefalse * @return truefalse
*/ */
bool ShaderCache::init(const std::string& cacheDir) { bool ShaderCache::init(const std::string &cacheDir) {
cacheDir_ = cacheDir; cacheDir_ = cacheDir;
if (!ensureCacheDirectory()) { if (!ensureCacheDirectory()) {
@ -60,7 +62,8 @@ void ShaderCache::shutdown() {
* @param sourceHash * @param sourceHash
* @return truefalse * @return truefalse
*/ */
bool ShaderCache::hasValidCache(const std::string& name, const std::string& sourceHash) { bool ShaderCache::hasValidCache(const std::string &name,
const std::string &sourceHash) {
auto it = cacheMap_.find(name); auto it = cacheMap_.find(name);
if (it == cacheMap_.end()) { if (it == cacheMap_.end()) {
return false; return false;
@ -74,7 +77,7 @@ bool ShaderCache::hasValidCache(const std::string& name, const std::string& sour
* @param name Shader名称 * @param name Shader名称
* @return nullptr * @return nullptr
*/ */
Ptr<ShaderCacheEntry> ShaderCache::loadCache(const std::string& name) { Ptr<ShaderCacheEntry> ShaderCache::loadCache(const std::string &name) {
auto it = cacheMap_.find(name); auto it = cacheMap_.find(name);
if (it == cacheMap_.end()) { if (it == cacheMap_.end()) {
return nullptr; return nullptr;
@ -95,7 +98,7 @@ Ptr<ShaderCacheEntry> ShaderCache::loadCache(const std::string& name) {
file.seekg(0, std::ios::beg); file.seekg(0, std::ios::beg);
entry->binary.resize(fileSize); entry->binary.resize(fileSize);
file.read(reinterpret_cast<char*>(entry->binary.data()), fileSize); file.read(reinterpret_cast<char *>(entry->binary.data()), fileSize);
return entry; return entry;
} }
@ -105,19 +108,21 @@ Ptr<ShaderCacheEntry> ShaderCache::loadCache(const std::string& name) {
* @param entry * @param entry
* @return truefalse * @return truefalse
*/ */
bool ShaderCache::saveCache(const ShaderCacheEntry& entry) { bool ShaderCache::saveCache(const ShaderCacheEntry &entry) {
if (!initialized_) { if (!initialized_) {
E2D_LOG_WARN("ShaderCache not initialized, cannot save cache"); E2D_LOG_WARN("ShaderCache not initialized, cannot save cache");
return false; return false;
} }
if (entry.binary.empty()) { if (entry.binary.empty()) {
E2D_LOG_WARN("Shader binary is empty, skipping cache save for: {}", entry.name); E2D_LOG_WARN("Shader binary is empty, skipping cache save for: {}",
entry.name);
return false; return false;
} }
std::string cachePath = getCachePath(entry.name); std::string cachePath = getCachePath(entry.name);
E2D_LOG_DEBUG("Saving shader cache to: {} ({} bytes)", cachePath, entry.binary.size()); E2D_LOG_DEBUG("Saving shader cache to: {} ({} bytes)", cachePath,
entry.binary.size());
std::ofstream file(cachePath, std::ios::binary); std::ofstream file(cachePath, std::ios::binary);
if (!file.is_open()) { if (!file.is_open()) {
@ -125,13 +130,15 @@ bool ShaderCache::saveCache(const ShaderCacheEntry& entry) {
return false; return false;
} }
file.write(reinterpret_cast<const char*>(entry.binary.data()), entry.binary.size()); file.write(reinterpret_cast<const char *>(entry.binary.data()),
entry.binary.size());
file.close(); file.close();
cacheMap_[entry.name] = entry; cacheMap_[entry.name] = entry;
saveCacheIndex(); saveCacheIndex();
E2D_LOG_INFO("Shader cache saved: {} ({} bytes)", entry.name, entry.binary.size()); E2D_LOG_INFO("Shader cache saved: {} ({} bytes)", entry.name,
entry.binary.size());
return true; return true;
} }
@ -139,7 +146,7 @@ bool ShaderCache::saveCache(const ShaderCacheEntry& entry) {
* @brief 使 * @brief 使
* @param name Shader名称 * @param name Shader名称
*/ */
void ShaderCache::invalidate(const std::string& name) { void ShaderCache::invalidate(const std::string &name) {
auto it = cacheMap_.find(name); auto it = cacheMap_.find(name);
if (it == cacheMap_.end()) { if (it == cacheMap_.end()) {
return; return;
@ -158,7 +165,7 @@ void ShaderCache::invalidate(const std::string& name) {
* @brief * @brief
*/ */
void ShaderCache::clearAll() { void ShaderCache::clearAll() {
for (const auto& pair : cacheMap_) { for (const auto &pair : cacheMap_) {
std::string cachePath = getCachePath(pair.first); std::string cachePath = getCachePath(pair.first);
fs::remove(cachePath); fs::remove(cachePath);
} }
@ -175,8 +182,8 @@ void ShaderCache::clearAll() {
* @param fragSource * @param fragSource
* @return * @return
*/ */
std::string ShaderCache::computeHash(const std::string& vertSource, std::string ShaderCache::computeHash(const std::string &vertSource,
const std::string& fragSource) { const std::string &fragSource) {
std::string combined = vertSource + fragSource; std::string combined = vertSource + fragSource;
uint32_t hash = 5381; uint32_t hash = 5381;
@ -248,7 +255,7 @@ bool ShaderCache::saveCacheIndex() {
file << "# Extra2D Shader Cache Index\n"; file << "# Extra2D Shader Cache Index\n";
file << "# Format: name=hash\n"; file << "# Format: name=hash\n";
for (const auto& pair : cacheMap_) { for (const auto &pair : cacheMap_) {
file << pair.first << "=" << pair.second.sourceHash << "\n"; file << pair.first << "=" << pair.second.sourceHash << "\n";
} }
@ -260,7 +267,7 @@ bool ShaderCache::saveCacheIndex() {
* @param name Shader名称 * @param name Shader名称
* @return * @return
*/ */
std::string ShaderCache::getCachePath(const std::string& name) const { std::string ShaderCache::getCachePath(const std::string &name) const {
return cacheDir_ + "/" + name + ".cache"; return cacheDir_ + "/" + name + ".cache";
} }

View File

@ -1,8 +1,10 @@
#include <extra2d/graphics/shader/shader_hot_reloader.h>
#include <extra2d/utils/logger.h>
#include <chrono> #include <chrono>
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/shader/shader_hot_reloader.h>
#include <extra2d/services/logger_service.h>
#include <filesystem> #include <filesystem>
namespace extra2d { namespace extra2d {
namespace fs = std::filesystem; namespace fs = std::filesystem;
@ -11,7 +13,7 @@ namespace fs = std::filesystem;
* @brief * @brief
* @return * @return
*/ */
ShaderHotReloader& ShaderHotReloader::getInstance() { ShaderHotReloader &ShaderHotReloader::getInstance() {
static ShaderHotReloader instance; static ShaderHotReloader instance;
return instance; return instance;
} }
@ -61,8 +63,8 @@ void ShaderHotReloader::shutdown() {
* @param filePaths * @param filePaths
* @param callback * @param callback
*/ */
void ShaderHotReloader::watch(const std::string& shaderName, void ShaderHotReloader::watch(const std::string &shaderName,
const std::vector<std::string>& filePaths, const std::vector<std::string> &filePaths,
FileChangeCallback callback) { FileChangeCallback callback) {
if (!initialized_) { if (!initialized_) {
E2D_LOG_WARN("Hot reloader not initialized"); E2D_LOG_WARN("Hot reloader not initialized");
@ -73,7 +75,7 @@ void ShaderHotReloader::watch(const std::string& shaderName,
info.filePaths = filePaths; info.filePaths = filePaths;
info.callback = callback; info.callback = callback;
for (const auto& path : filePaths) { for (const auto &path : filePaths) {
info.modifiedTimes[path] = getFileModifiedTime(path); info.modifiedTimes[path] = getFileModifiedTime(path);
} }
@ -85,7 +87,7 @@ void ShaderHotReloader::watch(const std::string& shaderName,
* @brief * @brief
* @param shaderName Shader名称 * @param shaderName Shader名称
*/ */
void ShaderHotReloader::unwatch(const std::string& shaderName) { void ShaderHotReloader::unwatch(const std::string &shaderName) {
auto it = watchMap_.find(shaderName); auto it = watchMap_.find(shaderName);
if (it != watchMap_.end()) { if (it != watchMap_.end()) {
watchMap_.erase(it); watchMap_.erase(it);
@ -120,14 +122,15 @@ void ShaderHotReloader::pollChanges() {
auto now = static_cast<uint64_t>( auto now = static_cast<uint64_t>(
std::chrono::system_clock::now().time_since_epoch().count()); std::chrono::system_clock::now().time_since_epoch().count());
for (auto& pair : watchMap_) { for (auto &pair : watchMap_) {
WatchInfo& info = pair.second; WatchInfo &info = pair.second;
for (const auto& filePath : info.filePaths) { for (const auto &filePath : info.filePaths) {
uint64_t currentModTime = getFileModifiedTime(filePath); uint64_t currentModTime = getFileModifiedTime(filePath);
uint64_t lastModTime = info.modifiedTimes[filePath]; uint64_t lastModTime = info.modifiedTimes[filePath];
if (currentModTime != 0 && lastModTime != 0 && currentModTime != lastModTime) { if (currentModTime != 0 && lastModTime != 0 &&
currentModTime != lastModTime) {
info.modifiedTimes[filePath] = currentModTime; info.modifiedTimes[filePath] = currentModTime;
FileChangeEvent event; FileChangeEvent event;
@ -150,11 +153,12 @@ void ShaderHotReloader::pollChanges() {
* @param filepath * @param filepath
* @return * @return
*/ */
uint64_t ShaderHotReloader::getFileModifiedTime(const std::string& filepath) { uint64_t ShaderHotReloader::getFileModifiedTime(const std::string &filepath) {
try { try {
auto ftime = fs::last_write_time(filepath); auto ftime = fs::last_write_time(filepath);
auto sctp = std::chrono::time_point_cast<std::chrono::seconds>( auto sctp = std::chrono::time_point_cast<std::chrono::seconds>(
ftime - fs::file_time_type::clock::now() + std::chrono::system_clock::now()); ftime - fs::file_time_type::clock::now() +
std::chrono::system_clock::now());
return static_cast<uint64_t>(sctp.time_since_epoch().count()); return static_cast<uint64_t>(sctp.time_since_epoch().count());
} catch (...) { } catch (...) {
return 0; return 0;

View File

@ -1,7 +1,7 @@
#include <extra2d/graphics/shader/shader_loader.h>
#include <extra2d/utils/logger.h>
#include <algorithm> #include <algorithm>
#include <cctype> #include <extra2d/core/service_locator.h>
#include <extra2d/graphics/shader/shader_loader.h>
#include <extra2d/services/logger_service.h>
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
@ -13,8 +13,7 @@ namespace fs = std::filesystem;
/** /**
* @brief Shader加载器 * @brief Shader加载器
*/ */
ShaderLoader::ShaderLoader() { ShaderLoader::ShaderLoader() {}
}
/** /**
* @brief Shader (.vert + .frag) * @brief Shader (.vert + .frag)
@ -23,10 +22,10 @@ ShaderLoader::ShaderLoader() {
* @param fragPath * @param fragPath
* @return * @return
*/ */
ShaderLoadResult ShaderLoader::loadFromSeparateFiles( ShaderLoadResult
const std::string& name, ShaderLoader::loadFromSeparateFiles(const std::string &name,
const std::string& vertPath, const std::string &vertPath,
const std::string& fragPath) { const std::string &fragPath) {
ShaderLoadResult result; ShaderLoadResult result;
@ -60,8 +59,10 @@ ShaderLoadResult ShaderLoader::loadFromSeparateFiles(
fs::path vertDir = fs::path(vertPath).parent_path(); fs::path vertDir = fs::path(vertPath).parent_path();
fs::path fragDir = fs::path(fragPath).parent_path(); fs::path fragDir = fs::path(fragPath).parent_path();
vertSource = processIncludes(vertSource, vertDir.string(), result.dependencies); vertSource =
fragSource = processIncludes(fragSource, fragDir.string(), result.dependencies); processIncludes(vertSource, vertDir.string(), result.dependencies);
fragSource =
processIncludes(fragSource, fragDir.string(), result.dependencies);
result.vertSource = vertSource; result.vertSource = vertSource;
result.fragSource = fragSource; result.fragSource = fragSource;
@ -75,7 +76,7 @@ ShaderLoadResult ShaderLoader::loadFromSeparateFiles(
* @param path Shader文件路径 * @param path Shader文件路径
* @return * @return
*/ */
ShaderLoadResult ShaderLoader::loadFromCombinedFile(const std::string& path) { ShaderLoadResult ShaderLoader::loadFromCombinedFile(const std::string &path) {
ShaderLoadResult result; ShaderLoadResult result;
if (!fileExists(path)) { if (!fileExists(path)) {
@ -101,8 +102,10 @@ ShaderLoadResult ShaderLoader::loadFromCombinedFile(const std::string& path) {
} }
fs::path baseDir = fs::path(path).parent_path(); fs::path baseDir = fs::path(path).parent_path();
vertSource = processIncludes(vertSource, baseDir.string(), result.dependencies); vertSource =
fragSource = processIncludes(fragSource, baseDir.string(), result.dependencies); processIncludes(vertSource, baseDir.string(), result.dependencies);
fragSource =
processIncludes(fragSource, baseDir.string(), result.dependencies);
result.vertSource = vertSource; result.vertSource = vertSource;
result.fragSource = fragSource; result.fragSource = fragSource;
@ -117,9 +120,8 @@ ShaderLoadResult ShaderLoader::loadFromCombinedFile(const std::string& path) {
* @param fragSource * @param fragSource
* @return * @return
*/ */
ShaderLoadResult ShaderLoader::loadFromSource( ShaderLoadResult ShaderLoader::loadFromSource(const std::string &vertSource,
const std::string& vertSource, const std::string &fragSource) {
const std::string& fragSource) {
ShaderLoadResult result; ShaderLoadResult result;
result.vertSource = vertSource; result.vertSource = vertSource;
@ -135,10 +137,10 @@ ShaderLoadResult ShaderLoader::loadFromSource(
* @param outDependencies * @param outDependencies
* @return * @return
*/ */
std::string ShaderLoader::processIncludes( std::string
const std::string& source, ShaderLoader::processIncludes(const std::string &source,
const std::string& baseDir, const std::string &baseDir,
std::vector<std::string>& outDependencies) { std::vector<std::string> &outDependencies) {
std::string result; std::string result;
std::istringstream stream(source); std::istringstream stream(source);
@ -151,7 +153,8 @@ std::string ShaderLoader::processIncludes(
size_t endQuote = line.find('"', startQuote + 1); size_t endQuote = line.find('"', startQuote + 1);
if (startQuote != std::string::npos && endQuote != std::string::npos) { if (startQuote != std::string::npos && endQuote != std::string::npos) {
std::string includeName = line.substr(startQuote + 1, endQuote - startQuote - 1); std::string includeName =
line.substr(startQuote + 1, endQuote - startQuote - 1);
std::string includePath = findIncludeFile(includeName, baseDir); std::string includePath = findIncludeFile(includeName, baseDir);
if (!includePath.empty()) { if (!includePath.empty()) {
@ -188,16 +191,16 @@ std::string ShaderLoader::processIncludes(
* @param defines * @param defines
* @return * @return
*/ */
std::string ShaderLoader::applyDefines( std::string
const std::string& source, ShaderLoader::applyDefines(const std::string &source,
const std::vector<std::string>& defines) { const std::vector<std::string> &defines) {
if (defines.empty()) { if (defines.empty()) {
return source; return source;
} }
std::string defineBlock; std::string defineBlock;
for (const auto& def : defines) { for (const auto &def : defines) {
defineBlock += "#define " + def + "\n"; defineBlock += "#define " + def + "\n";
} }
@ -229,7 +232,7 @@ std::string ShaderLoader::applyDefines(
* @param path Shader文件路径 * @param path Shader文件路径
* @return * @return
*/ */
ShaderMetadata ShaderLoader::getMetadata(const std::string& path) { ShaderMetadata ShaderLoader::getMetadata(const std::string &path) {
ShaderMetadata metadata; ShaderMetadata metadata;
if (!fileExists(path)) { if (!fileExists(path)) {
@ -249,8 +252,9 @@ ShaderMetadata ShaderLoader::getMetadata(const std::string& path) {
* @brief include搜索路径 * @brief include搜索路径
* @param path * @param path
*/ */
void ShaderLoader::addIncludePath(const std::string& path) { void ShaderLoader::addIncludePath(const std::string &path) {
if (std::find(includePaths_.begin(), includePaths_.end(), path) == includePaths_.end()) { if (std::find(includePaths_.begin(), includePaths_.end(), path) ==
includePaths_.end()) {
includePaths_.push_back(path); includePaths_.push_back(path);
} }
} }
@ -260,7 +264,7 @@ void ShaderLoader::addIncludePath(const std::string& path) {
* @param filepath * @param filepath
* @return * @return
*/ */
std::string ShaderLoader::readFile(const std::string& filepath) { std::string ShaderLoader::readFile(const std::string &filepath) {
std::ifstream file(filepath, std::ios::binary); std::ifstream file(filepath, std::ios::binary);
if (!file.is_open()) { if (!file.is_open()) {
return ""; return "";
@ -276,7 +280,7 @@ std::string ShaderLoader::readFile(const std::string& filepath) {
* @param filepath * @param filepath
* @return * @return
*/ */
uint64_t ShaderLoader::getFileModifiedTime(const std::string& filepath) { uint64_t ShaderLoader::getFileModifiedTime(const std::string &filepath) {
#ifdef __SWITCH__ #ifdef __SWITCH__
(void)filepath; (void)filepath;
return 1; return 1;
@ -284,7 +288,8 @@ uint64_t ShaderLoader::getFileModifiedTime(const std::string& filepath) {
try { try {
auto ftime = fs::last_write_time(filepath); auto ftime = fs::last_write_time(filepath);
auto sctp = std::chrono::time_point_cast<std::chrono::seconds>( auto sctp = std::chrono::time_point_cast<std::chrono::seconds>(
ftime - fs::file_time_type::clock::now() + std::chrono::system_clock::now()); ftime - fs::file_time_type::clock::now() +
std::chrono::system_clock::now());
return static_cast<uint64_t>(sctp.time_since_epoch().count()); return static_cast<uint64_t>(sctp.time_since_epoch().count());
} catch (...) { } catch (...) {
return 0; return 0;
@ -297,7 +302,7 @@ uint64_t ShaderLoader::getFileModifiedTime(const std::string& filepath) {
* @param filepath * @param filepath
* @return truefalse * @return truefalse
*/ */
bool ShaderLoader::fileExists(const std::string& filepath) { bool ShaderLoader::fileExists(const std::string &filepath) {
return fs::exists(filepath); return fs::exists(filepath);
} }
@ -309,16 +314,10 @@ bool ShaderLoader::fileExists(const std::string& filepath) {
* @param outMetadata * @param outMetadata
* @return truefalse * @return truefalse
*/ */
bool ShaderLoader::parseCombinedFile(const std::string& content, bool ShaderLoader::parseCombinedFile(const std::string &content,
std::string& outVert, std::string &outVert, std::string &outFrag,
std::string& outFrag, ShaderMetadata &outMetadata) {
ShaderMetadata& outMetadata) { enum class Section { None, Meta, Vertex, Fragment };
enum class Section {
None,
Meta,
Vertex,
Fragment
};
Section currentSection = Section::None; Section currentSection = Section::None;
std::string metaContent; std::string metaContent;
@ -384,7 +383,8 @@ bool ShaderLoader::parseCombinedFile(const std::string& content,
* @param outMetadata * @param outMetadata
* @return truefalse * @return truefalse
*/ */
bool ShaderLoader::parseMetadata(const std::string& jsonContent, ShaderMetadata& outMetadata) { bool ShaderLoader::parseMetadata(const std::string &jsonContent,
ShaderMetadata &outMetadata) {
std::string content = jsonContent; std::string content = jsonContent;
size_t start = content.find('{'); size_t start = content.find('{');
@ -395,7 +395,7 @@ bool ShaderLoader::parseMetadata(const std::string& jsonContent, ShaderMetadata&
content = content.substr(start, end - start + 1); content = content.substr(start, end - start + 1);
auto extractString = [&content](const std::string& key) -> std::string { auto extractString = [&content](const std::string &key) -> std::string {
std::string searchKey = "\"" + key + "\""; std::string searchKey = "\"" + key + "\"";
size_t keyPos = content.find(searchKey); size_t keyPos = content.find(searchKey);
if (keyPos == std::string::npos) { if (keyPos == std::string::npos) {
@ -430,7 +430,8 @@ bool ShaderLoader::parseMetadata(const std::string& jsonContent, ShaderMetadata&
* @param baseDir * @param baseDir
* @return * @return
*/ */
std::string ShaderLoader::findIncludeFile(const std::string& includeName, const std::string& baseDir) { std::string ShaderLoader::findIncludeFile(const std::string &includeName,
const std::string &baseDir) {
fs::path basePath(baseDir); fs::path basePath(baseDir);
fs::path includePath = basePath / includeName; fs::path includePath = basePath / includeName;
@ -438,7 +439,7 @@ std::string ShaderLoader::findIncludeFile(const std::string& includeName, const
return includePath.string(); return includePath.string();
} }
for (const auto& searchPath : includePaths_) { for (const auto &searchPath : includePaths_) {
includePath = fs::path(searchPath) / includeName; includePath = fs::path(searchPath) / includeName;
if (fs::exists(includePath)) { if (fs::exists(includePath)) {
return includePath.string(); return includePath.string();

View File

@ -1,5 +1,7 @@
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/shader/shader_manager.h> #include <extra2d/graphics/shader/shader_manager.h>
#include <extra2d/utils/logger.h> #include <extra2d/services/logger_service.h>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
@ -11,7 +13,7 @@ namespace extra2d {
* @brief * @brief
* @return Shader管理器实例引用 * @return Shader管理器实例引用
*/ */
ShaderManager& ShaderManager::getInstance() { ShaderManager &ShaderManager::getInstance() {
static ShaderManager instance; static ShaderManager instance;
return instance; return instance;
} }
@ -23,7 +25,8 @@ ShaderManager& ShaderManager::getInstance() {
* @param appName * @param appName
* @return truefalse * @return truefalse
*/ */
bool ShaderManager::init(Ptr<IShaderFactory> factory, const std::string& appName) { bool ShaderManager::init(Ptr<IShaderFactory> factory,
const std::string &appName) {
// 使用相对路径作为Shader目录 // 使用相对路径作为Shader目录
std::string shaderDir = "shaders/"; std::string shaderDir = "shaders/";
std::string cacheDir = "cache/shaders/"; std::string cacheDir = "cache/shaders/";
@ -48,8 +51,8 @@ bool ShaderManager::init(Ptr<IShaderFactory> factory, const std::string& appName
* @param factory Shader工厂 * @param factory Shader工厂
* @return truefalse * @return truefalse
*/ */
bool ShaderManager::init(const std::string& shaderDir, bool ShaderManager::init(const std::string &shaderDir,
const std::string& cacheDir, const std::string &cacheDir,
Ptr<IShaderFactory> factory) { Ptr<IShaderFactory> factory) {
if (initialized_) { if (initialized_) {
E2D_LOG_WARN("ShaderManager already initialized"); E2D_LOG_WARN("ShaderManager already initialized");
@ -94,7 +97,8 @@ bool ShaderManager::init(const std::string& shaderDir,
E2D_LOG_INFO("ShaderManager initialized"); E2D_LOG_INFO("ShaderManager initialized");
E2D_LOG_INFO(" Shader directory: {}", shaderDir_); E2D_LOG_INFO(" Shader directory: {}", shaderDir_);
E2D_LOG_INFO(" Cache directory: {}", cacheDir_); E2D_LOG_INFO(" Cache directory: {}", cacheDir_);
E2D_LOG_INFO(" Hot reload: {}", hotReloadSupported_ ? "supported" : "not supported"); E2D_LOG_INFO(" Hot reload: {}",
hotReloadSupported_ ? "supported" : "not supported");
return true; return true;
} }
@ -126,9 +130,9 @@ void ShaderManager::shutdown() {
* @param fragPath * @param fragPath
* @return Shader实例 * @return Shader实例
*/ */
Ptr<IShader> ShaderManager::loadFromFiles(const std::string& name, Ptr<IShader> ShaderManager::loadFromFiles(const std::string &name,
const std::string& vertPath, const std::string &vertPath,
const std::string& fragPath) { const std::string &fragPath) {
if (!initialized_) { if (!initialized_) {
E2D_LOG_ERROR("ShaderManager not initialized"); E2D_LOG_ERROR("ShaderManager not initialized");
return nullptr; return nullptr;
@ -139,18 +143,23 @@ Ptr<IShader> ShaderManager::loadFromFiles(const std::string& name,
return it->second.shader; return it->second.shader;
} }
ShaderLoadResult result = loader_.loadFromSeparateFiles(name, vertPath, fragPath); ShaderLoadResult result =
loader_.loadFromSeparateFiles(name, vertPath, fragPath);
if (!result.success) { if (!result.success) {
E2D_LOG_ERROR("Failed to load shader files: {} - {}", vertPath, fragPath); E2D_LOG_ERROR("Failed to load shader files: {} - {}", vertPath, fragPath);
return nullptr; return nullptr;
} }
std::string sourceHash = ShaderCache::computeHash(result.vertSource, result.fragSource); std::string sourceHash =
Ptr<IShader> shader = loadFromCache(name, sourceHash, result.vertSource, result.fragSource); ShaderCache::computeHash(result.vertSource, result.fragSource);
Ptr<IShader> shader =
loadFromCache(name, sourceHash, result.vertSource, result.fragSource);
if (!shader) { if (!shader) {
E2D_LOG_DEBUG("No valid cache found, compiling shader from source: {}", name); E2D_LOG_DEBUG("No valid cache found, compiling shader from source: {}",
shader = factory_->createFromSource(name, result.vertSource, result.fragSource); name);
shader =
factory_->createFromSource(name, result.vertSource, result.fragSource);
if (!shader) { if (!shader) {
E2D_LOG_ERROR("Failed to create shader from source: {}", name); E2D_LOG_ERROR("Failed to create shader from source: {}", name);
return nullptr; return nullptr;
@ -175,7 +184,8 @@ Ptr<IShader> ShaderManager::loadFromFiles(const std::string& name,
info.vertSource = result.vertSource; info.vertSource = result.vertSource;
info.fragSource = result.fragSource; info.fragSource = result.fragSource;
info.filePaths = {vertPath, fragPath}; info.filePaths = {vertPath, fragPath};
info.filePaths.insert(info.filePaths.end(), result.dependencies.begin(), result.dependencies.end()); info.filePaths.insert(info.filePaths.end(), result.dependencies.begin(),
result.dependencies.end());
info.metadata.name = name; info.metadata.name = name;
info.metadata.vertPath = vertPath; info.metadata.vertPath = vertPath;
@ -184,10 +194,11 @@ Ptr<IShader> ShaderManager::loadFromFiles(const std::string& name,
shaders_[name] = std::move(info); shaders_[name] = std::move(info);
if (hotReloadEnabled_ && hotReloadSupported_) { if (hotReloadEnabled_ && hotReloadSupported_) {
auto callback = [this, name](const FileChangeEvent& event) { auto callback = [this, name](const FileChangeEvent &event) {
this->handleFileChange(name, event); this->handleFileChange(name, event);
}; };
ShaderHotReloader::getInstance().watch(name, shaders_[name].filePaths, callback); ShaderHotReloader::getInstance().watch(name, shaders_[name].filePaths,
callback);
} }
E2D_LOG_DEBUG("Shader loaded: {}", name); E2D_LOG_DEBUG("Shader loaded: {}", name);
@ -199,7 +210,7 @@ Ptr<IShader> ShaderManager::loadFromFiles(const std::string& name,
* @param path Shader文件路径 * @param path Shader文件路径
* @return Shader实例 * @return Shader实例
*/ */
Ptr<IShader> ShaderManager::loadFromCombinedFile(const std::string& path) { Ptr<IShader> ShaderManager::loadFromCombinedFile(const std::string &path) {
if (!initialized_) { if (!initialized_) {
E2D_LOG_ERROR("ShaderManager not initialized"); E2D_LOG_ERROR("ShaderManager not initialized");
return nullptr; return nullptr;
@ -219,12 +230,16 @@ Ptr<IShader> ShaderManager::loadFromCombinedFile(const std::string& path) {
return nullptr; return nullptr;
} }
std::string sourceHash = ShaderCache::computeHash(result.vertSource, result.fragSource); std::string sourceHash =
Ptr<IShader> shader = loadFromCache(name, sourceHash, result.vertSource, result.fragSource); ShaderCache::computeHash(result.vertSource, result.fragSource);
Ptr<IShader> shader =
loadFromCache(name, sourceHash, result.vertSource, result.fragSource);
if (!shader) { if (!shader) {
E2D_LOG_DEBUG("No valid cache found, compiling shader from source: {}", name); E2D_LOG_DEBUG("No valid cache found, compiling shader from source: {}",
shader = factory_->createFromSource(name, result.vertSource, result.fragSource); name);
shader =
factory_->createFromSource(name, result.vertSource, result.fragSource);
if (!shader) { if (!shader) {
E2D_LOG_ERROR("Failed to create shader from source: {}", name); E2D_LOG_ERROR("Failed to create shader from source: {}", name);
return nullptr; return nullptr;
@ -249,16 +264,18 @@ Ptr<IShader> ShaderManager::loadFromCombinedFile(const std::string& path) {
info.vertSource = result.vertSource; info.vertSource = result.vertSource;
info.fragSource = result.fragSource; info.fragSource = result.fragSource;
info.filePaths = {path}; info.filePaths = {path};
info.filePaths.insert(info.filePaths.end(), result.dependencies.begin(), result.dependencies.end()); info.filePaths.insert(info.filePaths.end(), result.dependencies.begin(),
result.dependencies.end());
info.metadata = metadata; info.metadata = metadata;
shaders_[name] = std::move(info); shaders_[name] = std::move(info);
if (hotReloadEnabled_ && hotReloadSupported_) { if (hotReloadEnabled_ && hotReloadSupported_) {
auto callback = [this, name](const FileChangeEvent& event) { auto callback = [this, name](const FileChangeEvent &event) {
this->handleFileChange(name, event); this->handleFileChange(name, event);
}; };
ShaderHotReloader::getInstance().watch(name, shaders_[name].filePaths, callback); ShaderHotReloader::getInstance().watch(name, shaders_[name].filePaths,
callback);
} }
E2D_LOG_DEBUG("Shader loaded from combined file: {}", name); E2D_LOG_DEBUG("Shader loaded from combined file: {}", name);
@ -272,9 +289,9 @@ Ptr<IShader> ShaderManager::loadFromCombinedFile(const std::string& path) {
* @param fragSource * @param fragSource
* @return Shader实例 * @return Shader实例
*/ */
Ptr<IShader> ShaderManager::loadFromSource(const std::string& name, Ptr<IShader> ShaderManager::loadFromSource(const std::string &name,
const std::string& vertSource, const std::string &vertSource,
const std::string& fragSource) { const std::string &fragSource) {
if (!initialized_) { if (!initialized_) {
E2D_LOG_ERROR("ShaderManager not initialized"); E2D_LOG_ERROR("ShaderManager not initialized");
return nullptr; return nullptr;
@ -285,7 +302,8 @@ Ptr<IShader> ShaderManager::loadFromSource(const std::string& name,
return it->second.shader; return it->second.shader;
} }
Ptr<IShader> shader = factory_->createFromSource(name, vertSource, fragSource); Ptr<IShader> shader =
factory_->createFromSource(name, vertSource, fragSource);
if (!shader) { if (!shader) {
E2D_LOG_ERROR("Failed to create shader from source: {}", name); E2D_LOG_ERROR("Failed to create shader from source: {}", name);
return nullptr; return nullptr;
@ -308,7 +326,7 @@ Ptr<IShader> ShaderManager::loadFromSource(const std::string& name,
* @param name Shader名称 * @param name Shader名称
* @return Shader实例nullptr * @return Shader实例nullptr
*/ */
Ptr<IShader> ShaderManager::get(const std::string& name) const { Ptr<IShader> ShaderManager::get(const std::string &name) const {
auto it = shaders_.find(name); auto it = shaders_.find(name);
if (it != shaders_.end()) { if (it != shaders_.end()) {
return it->second.shader; return it->second.shader;
@ -321,7 +339,7 @@ Ptr<IShader> ShaderManager::get(const std::string& name) const {
* @param name Shader名称 * @param name Shader名称
* @return truefalse * @return truefalse
*/ */
bool ShaderManager::has(const std::string& name) const { bool ShaderManager::has(const std::string &name) const {
return shaders_.find(name) != shaders_.end(); return shaders_.find(name) != shaders_.end();
} }
@ -329,7 +347,7 @@ bool ShaderManager::has(const std::string& name) const {
* @brief Shader * @brief Shader
* @param name Shader名称 * @param name Shader名称
*/ */
void ShaderManager::remove(const std::string& name) { void ShaderManager::remove(const std::string &name) {
auto it = shaders_.find(name); auto it = shaders_.find(name);
if (it != shaders_.end()) { if (it != shaders_.end()) {
ShaderHotReloader::getInstance().unwatch(name); ShaderHotReloader::getInstance().unwatch(name);
@ -343,7 +361,7 @@ void ShaderManager::remove(const std::string& name) {
*/ */
void ShaderManager::clear() { void ShaderManager::clear() {
if (hotReloadSupported_) { if (hotReloadSupported_) {
for (const auto& pair : shaders_) { for (const auto &pair : shaders_) {
ShaderHotReloader::getInstance().unwatch(pair.first); ShaderHotReloader::getInstance().unwatch(pair.first);
} }
} }
@ -356,7 +374,8 @@ void ShaderManager::clear() {
* @param name Shader名称 * @param name Shader名称
* @param callback * @param callback
*/ */
void ShaderManager::setReloadCallback(const std::string& name, ShaderReloadCallback callback) { void ShaderManager::setReloadCallback(const std::string &name,
ShaderReloadCallback callback) {
auto it = shaders_.find(name); auto it = shaders_.find(name);
if (it != shaders_.end()) { if (it != shaders_.end()) {
it->second.reloadCallback = callback; it->second.reloadCallback = callback;
@ -399,33 +418,36 @@ void ShaderManager::update() {
* @param name Shader名称 * @param name Shader名称
* @return truefalse * @return truefalse
*/ */
bool ShaderManager::reload(const std::string& name) { bool ShaderManager::reload(const std::string &name) {
auto it = shaders_.find(name); auto it = shaders_.find(name);
if (it == shaders_.end()) { if (it == shaders_.end()) {
E2D_LOG_WARN("Shader not found for reload: {}", name); E2D_LOG_WARN("Shader not found for reload: {}", name);
return false; return false;
} }
ShaderInfo& info = it->second; ShaderInfo &info = it->second;
std::string vertSource = info.vertSource; std::string vertSource = info.vertSource;
std::string fragSource = info.fragSource; std::string fragSource = info.fragSource;
if (!info.metadata.vertPath.empty() && !info.metadata.fragPath.empty()) { if (!info.metadata.vertPath.empty() && !info.metadata.fragPath.empty()) {
ShaderLoadResult result = loader_.loadFromSeparateFiles(name, info.metadata.vertPath, info.metadata.fragPath); ShaderLoadResult result = loader_.loadFromSeparateFiles(
name, info.metadata.vertPath, info.metadata.fragPath);
if (result.success) { if (result.success) {
vertSource = result.vertSource; vertSource = result.vertSource;
fragSource = result.fragSource; fragSource = result.fragSource;
} }
} else if (!info.metadata.combinedPath.empty()) { } else if (!info.metadata.combinedPath.empty()) {
ShaderLoadResult result = loader_.loadFromCombinedFile(info.metadata.combinedPath); ShaderLoadResult result =
loader_.loadFromCombinedFile(info.metadata.combinedPath);
if (result.success) { if (result.success) {
vertSource = result.vertSource; vertSource = result.vertSource;
fragSource = result.fragSource; fragSource = result.fragSource;
} }
} }
Ptr<IShader> newShader = factory_->createFromSource(name, vertSource, fragSource); Ptr<IShader> newShader =
factory_->createFromSource(name, vertSource, fragSource);
if (!newShader) { if (!newShader) {
E2D_LOG_ERROR("Failed to reload shader: {}", name); E2D_LOG_ERROR("Failed to reload shader: {}", name);
return false; return false;
@ -448,7 +470,7 @@ bool ShaderManager::reload(const std::string& name) {
* @param name Shader名称 * @param name Shader名称
* @return Shader实例 * @return Shader实例
*/ */
Ptr<IShader> ShaderManager::getBuiltin(const std::string& name) { Ptr<IShader> ShaderManager::getBuiltin(const std::string &name) {
Ptr<IShader> shader = get(name); Ptr<IShader> shader = get(name);
if (shader) { if (shader) {
return shader; return shader;
@ -471,7 +493,8 @@ Ptr<IShader> ShaderManager::getBuiltin(const std::string& name) {
* @param name Shader名称 * @param name Shader名称
* @return Shader实例 * @return Shader实例
*/ */
Ptr<IShader> ShaderManager::loadFromMetadata(const std::string& jsonPath, const std::string& name) { Ptr<IShader> ShaderManager::loadFromMetadata(const std::string &jsonPath,
const std::string &name) {
if (!initialized_) { if (!initialized_) {
E2D_LOG_ERROR("ShaderManager not initialized"); E2D_LOG_ERROR("ShaderManager not initialized");
return nullptr; return nullptr;
@ -500,9 +523,10 @@ Ptr<IShader> ShaderManager::loadFromMetadata(const std::string& jsonPath, const
return nullptr; return nullptr;
} }
auto& opengl = j["backends"]["opengl"]; auto &opengl = j["backends"]["opengl"];
if (!opengl.contains("vertex") || !opengl.contains("fragment")) { if (!opengl.contains("vertex") || !opengl.contains("fragment")) {
E2D_LOG_ERROR("Missing vertex or fragment path in shader metadata: {}", jsonPath); E2D_LOG_ERROR("Missing vertex or fragment path in shader metadata: {}",
jsonPath);
return nullptr; return nullptr;
} }
@ -513,12 +537,13 @@ Ptr<IShader> ShaderManager::loadFromMetadata(const std::string& jsonPath, const
std::string vertPath = shaderDir_ + vertRelativePath; std::string vertPath = shaderDir_ + vertRelativePath;
std::string fragPath = shaderDir_ + fragRelativePath; std::string fragPath = shaderDir_ + fragRelativePath;
E2D_LOG_DEBUG("Loading shader from metadata: {} -> vert: {}, frag: {}", name, vertPath, fragPath); E2D_LOG_DEBUG("Loading shader from metadata: {} -> vert: {}, frag: {}",
name, vertPath, fragPath);
// 使用分离文件加载 // 使用分离文件加载
return loadFromFiles(name, vertPath, fragPath); return loadFromFiles(name, vertPath, fragPath);
} catch (const nl::json::exception& e) { } catch (const nl::json::exception &e) {
E2D_LOG_ERROR("Failed to parse shader metadata {}: {}", jsonPath, e.what()); E2D_LOG_ERROR("Failed to parse shader metadata {}: {}", jsonPath, e.what());
return nullptr; return nullptr;
} }
@ -536,15 +561,10 @@ bool ShaderManager::loadBuiltinShaders() {
bool allSuccess = true; bool allSuccess = true;
const char* builtinNames[] = { const char *builtinNames[] = {"sprite", "particle", "shape", "postprocess",
"sprite", "font"};
"particle",
"shape",
"postprocess",
"font"
};
for (const char* name : builtinNames) { for (const char *name : builtinNames) {
// 首先尝试新的多后端JSON格式 // 首先尝试新的多后端JSON格式
std::string jsonPath = shaderDir_ + "shared/builtin/" + name + ".json"; std::string jsonPath = shaderDir_ + "shared/builtin/" + name + ".json";
std::string shaderName = std::string("builtin_") + name; std::string shaderName = std::string("builtin_") + name;
@ -585,10 +605,10 @@ bool ShaderManager::loadBuiltinShaders() {
* @param fragSource * @param fragSource
* @return Shader实例 * @return Shader实例
*/ */
Ptr<IShader> ShaderManager::loadFromCache(const std::string& name, Ptr<IShader> ShaderManager::loadFromCache(const std::string &name,
const std::string& sourceHash, const std::string &sourceHash,
const std::string& vertSource, const std::string &vertSource,
const std::string& fragSource) { const std::string &fragSource) {
if (!ShaderCache::getInstance().isInitialized()) { if (!ShaderCache::getInstance().isInitialized()) {
return nullptr; return nullptr;
} }
@ -615,7 +635,8 @@ Ptr<IShader> ShaderManager::loadFromCache(const std::string& name,
* @param shaderName Shader名称 * @param shaderName Shader名称
* @param event * @param event
*/ */
void ShaderManager::handleFileChange(const std::string& shaderName, const FileChangeEvent& event) { void ShaderManager::handleFileChange(const std::string &shaderName,
const FileChangeEvent &event) {
E2D_LOG_DEBUG("Shader file changed: {} -> {}", shaderName, event.filepath); E2D_LOG_DEBUG("Shader file changed: {} -> {}", shaderName, event.filepath);
reload(shaderName); reload(shaderName);
} }

View File

@ -1,6 +1,8 @@
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/shader/shader_manager.h> #include <extra2d/graphics/shader/shader_manager.h>
#include <extra2d/graphics/shader/shader_preset.h> #include <extra2d/graphics/shader/shader_preset.h>
#include <extra2d/utils/logger.h> #include <extra2d/services/logger_service.h>
namespace extra2d { namespace extra2d {

View File

@ -1,7 +1,6 @@
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/texture/texture_atlas.h> #include <extra2d/graphics/texture/texture_atlas.h>
#include <extra2d/utils/logger.h> #include <extra2d/services/logger_service.h>
#include <algorithm>
#include <cstring>
namespace extra2d { namespace extra2d {
@ -46,8 +45,9 @@ TextureAtlasPage::~TextureAtlasPage() = default;
* *
* 使 * 使
*/ */
bool TextureAtlasPage::tryAddTexture(const std::string& name, int texWidth, int texHeight, bool TextureAtlasPage::tryAddTexture(const std::string &name, int texWidth,
const uint8_t* pixels, Rect& outUvRect) { int texHeight, const uint8_t *pixels,
Rect &outUvRect) {
if (isFull_) { if (isFull_) {
return false; return false;
} }
@ -62,7 +62,7 @@ bool TextureAtlasPage::tryAddTexture(const std::string& name, int texWidth, int
} }
// 尝试插入 // 尝试插入
PackNode* node = insert(root_.get(), paddedWidth, paddedHeight); PackNode *node = insert(root_.get(), paddedWidth, paddedHeight);
if (node == nullptr) { if (node == nullptr) {
// 无法放入,标记为满 // 无法放入,标记为满
isFull_ = true; isFull_ = true;
@ -70,12 +70,14 @@ bool TextureAtlasPage::tryAddTexture(const std::string& name, int texWidth, int
} }
// 写入像素数据(跳过边距区域) // 写入像素数据(跳过边距区域)
writePixels(node->x + PADDING, node->y + PADDING, texWidth, texHeight, pixels); writePixels(node->x + PADDING, node->y + PADDING, texWidth, texHeight,
pixels);
// 创建条目 // 创建条目
AtlasEntry entry; AtlasEntry entry;
entry.name = name; entry.name = name;
entry.originalSize = Vec2(static_cast<float>(texWidth), static_cast<float>(texHeight)); entry.originalSize =
Vec2(static_cast<float>(texWidth), static_cast<float>(texHeight));
entry.padding = PADDING; entry.padding = PADDING;
// 计算 UV 坐标(考虑边距) // 计算 UV 坐标(考虑边距)
@ -90,8 +92,8 @@ bool TextureAtlasPage::tryAddTexture(const std::string& name, int texWidth, int
entries_[name] = std::move(entry); entries_[name] = std::move(entry);
usedArea_ += paddedWidth * paddedHeight; usedArea_ += paddedWidth * paddedHeight;
E2D_LOG_DEBUG("Added texture '{}' to atlas: {}x{} at ({}, {})", E2D_LOG_DEBUG("Added texture '{}' to atlas: {}x{} at ({}, {})", name,
name, texWidth, texHeight, node->x, node->y); texWidth, texHeight, node->x, node->y);
return true; return true;
} }
@ -105,14 +107,15 @@ 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) { if (node == nullptr) {
return nullptr; return nullptr;
} }
// 如果节点已被使用,尝试子节点 // 如果节点已被使用,尝试子节点
if (node->used) { if (node->used) {
PackNode* result = insert(node->left.get(), width, height); PackNode *result = insert(node->left.get(), width, height);
if (result != nullptr) { if (result != nullptr) {
return result; return result;
} }
@ -136,12 +139,16 @@ TextureAtlasPage::PackNode* TextureAtlasPage::insert(PackNode* node, int width,
if (dw > dh) { if (dw > dh) {
// 水平分割 // 水平分割
node->left = std::make_unique<PackNode>(node->x, node->y, width, node->height); node->left =
node->right = std::make_unique<PackNode>(node->x + width, node->y, dw, node->height); std::make_unique<PackNode>(node->x, node->y, width, node->height);
node->right =
std::make_unique<PackNode>(node->x + width, node->y, dw, node->height);
} else { } else {
// 垂直分割 // 垂直分割
node->left = std::make_unique<PackNode>(node->x, node->y, node->width, height); node->left =
node->right = std::make_unique<PackNode>(node->x, node->y + height, node->width, dh); std::make_unique<PackNode>(node->x, node->y, node->width, height);
node->right =
std::make_unique<PackNode>(node->x, node->y + height, node->width, dh);
} }
// 递归插入到左子节点 // 递归插入到左子节点
@ -158,7 +165,8 @@ TextureAtlasPage::PackNode* TextureAtlasPage::insert(PackNode* node, int width,
* *
* 使glTexSubImage2D更新纹理的指定区域 * 使glTexSubImage2D更新纹理的指定区域
*/ */
void TextureAtlasPage::writePixels(int x, int y, int w, int h, const uint8_t* pixels) { void TextureAtlasPage::writePixels(int x, int y, int w, int h,
const uint8_t *pixels) {
if (texture_ == nullptr || pixels == nullptr) { if (texture_ == nullptr || pixels == nullptr) {
return; return;
} }
@ -168,7 +176,8 @@ void TextureAtlasPage::writePixels(int x, int y, int w, int h, const uint8_t* pi
reinterpret_cast<uintptr_t>(texture_->getNativeHandle())); reinterpret_cast<uintptr_t>(texture_->getNativeHandle()));
glBindTexture(GL_TEXTURE_2D, texID); 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); 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 * @param name
* @return nullptr * @return nullptr
*/ */
const AtlasEntry* TextureAtlasPage::getEntry(const std::string& name) const { const AtlasEntry *TextureAtlasPage::getEntry(const std::string &name) const {
auto it = entries_.find(name); auto it = entries_.find(name);
if (it != entries_.end()) { if (it != entries_.end()) {
return &it->second; return &it->second;
@ -205,11 +214,8 @@ float TextureAtlasPage::getUsageRatio() const {
* 使 * 使
*/ */
TextureAtlas::TextureAtlas() TextureAtlas::TextureAtlas()
: pageSize_(TextureAtlasPage::DEFAULT_SIZE), : pageSize_(TextureAtlasPage::DEFAULT_SIZE), sizeThreshold_(256),
sizeThreshold_(256), enabled_(true), initialized_(false) {}
enabled_(true),
initialized_(false) {
}
/** /**
* @brief * @brief
@ -240,8 +246,8 @@ void TextureAtlas::init(int pageSize) {
* *
* *
*/ */
bool TextureAtlas::addTexture(const std::string& name, int width, int height, bool TextureAtlas::addTexture(const std::string &name, int width, int height,
const uint8_t* pixels) { const uint8_t *pixels) {
if (!enabled_ || !initialized_) { if (!enabled_ || !initialized_) {
return false; return false;
} }
@ -260,7 +266,7 @@ bool TextureAtlas::addTexture(const std::string& name, int width, int height,
// 尝试添加到现有页面 // 尝试添加到现有页面
Rect uvRect; Rect uvRect;
for (auto& page : pages_) { for (auto &page : pages_) {
if (page->tryAddTexture(name, width, height, pixels, uvRect)) { if (page->tryAddTexture(name, width, height, pixels, uvRect)) {
entryToPage_[name] = page.get(); entryToPage_[name] = page.get();
return true; return true;
@ -284,7 +290,7 @@ bool TextureAtlas::addTexture(const std::string& name, int width, int height,
* @param name * @param name
* @return truefalse * @return truefalse
*/ */
bool TextureAtlas::contains(const std::string& name) const { bool TextureAtlas::contains(const std::string &name) const {
return entryToPage_.find(name) != entryToPage_.end(); return entryToPage_.find(name) != entryToPage_.end();
} }
@ -293,7 +299,7 @@ bool TextureAtlas::contains(const std::string& name) const {
* @param name * @param name
* @return nullptr * @return nullptr
*/ */
const Texture* TextureAtlas::getAtlasTexture(const std::string& name) const { const Texture *TextureAtlas::getAtlasTexture(const std::string &name) const {
auto it = entryToPage_.find(name); auto it = entryToPage_.find(name);
if (it != entryToPage_.end()) { if (it != entryToPage_.end()) {
return it->second->getTexture().get(); return it->second->getTexture().get();
@ -306,10 +312,10 @@ const Texture* TextureAtlas::getAtlasTexture(const std::string& name) const {
* @param name * @param name
* @return UV坐标矩形 * @return UV坐标矩形
*/ */
Rect TextureAtlas::getUVRect(const std::string& name) const { Rect TextureAtlas::getUVRect(const std::string &name) const {
auto it = entryToPage_.find(name); auto it = entryToPage_.find(name);
if (it != entryToPage_.end()) { if (it != entryToPage_.end()) {
const AtlasEntry* entry = it->second->getEntry(name); const AtlasEntry *entry = it->second->getEntry(name);
if (entry != nullptr) { if (entry != nullptr) {
return entry->uvRect; return entry->uvRect;
} }
@ -322,10 +328,10 @@ Rect TextureAtlas::getUVRect(const std::string& name) const {
* @param name * @param name
* @return * @return
*/ */
Vec2 TextureAtlas::getOriginalSize(const std::string& name) const { Vec2 TextureAtlas::getOriginalSize(const std::string &name) const {
auto it = entryToPage_.find(name); auto it = entryToPage_.find(name);
if (it != entryToPage_.end()) { if (it != entryToPage_.end()) {
const AtlasEntry* entry = it->second->getEntry(name); const AtlasEntry *entry = it->second->getEntry(name);
if (entry != nullptr) { if (entry != nullptr) {
return entry->originalSize; return entry->originalSize;
} }
@ -345,7 +351,7 @@ float TextureAtlas::getTotalUsageRatio() const {
} }
float total = 0.0f; float total = 0.0f;
for (const auto& page : pages_) { for (const auto &page : pages_) {
total += page->getUsageRatio(); total += page->getUsageRatio();
} }
return total / pages_.size(); return total / pages_.size();
@ -372,7 +378,7 @@ void TextureAtlas::clear() {
* *
* 使线 * 使线
*/ */
TextureAtlasMgr& TextureAtlasMgr::get() { TextureAtlasMgr &TextureAtlasMgr::get() {
static TextureAtlasMgr instance; static TextureAtlasMgr instance;
return instance; return instance;
} }

View File

@ -1,6 +1,8 @@
#include "glfw_input.h" #include "glfw_input.h"
#include <extra2d/utils/logger.h>
#include <cmath> #include <cmath>
#include <extra2d/core/service_locator.h>
#include <extra2d/services/logger_service.h>
namespace extra2d { namespace extra2d {
@ -8,92 +10,165 @@ namespace extra2d {
static Key glfwToKey(int glfwKey) { static Key glfwToKey(int glfwKey) {
switch (glfwKey) { switch (glfwKey) {
// 字母键 // 字母键
case GLFW_KEY_A: return Key::A; case GLFW_KEY_A:
case GLFW_KEY_B: return Key::B; return Key::A;
case GLFW_KEY_C: return Key::C; case GLFW_KEY_B:
case GLFW_KEY_D: return Key::D; return Key::B;
case GLFW_KEY_E: return Key::E; case GLFW_KEY_C:
case GLFW_KEY_F: return Key::F; return Key::C;
case GLFW_KEY_G: return Key::G; case GLFW_KEY_D:
case GLFW_KEY_H: return Key::H; return Key::D;
case GLFW_KEY_I: return Key::I; case GLFW_KEY_E:
case GLFW_KEY_J: return Key::J; return Key::E;
case GLFW_KEY_K: return Key::K; case GLFW_KEY_F:
case GLFW_KEY_L: return Key::L; return Key::F;
case GLFW_KEY_M: return Key::M; case GLFW_KEY_G:
case GLFW_KEY_N: return Key::N; return Key::G;
case GLFW_KEY_O: return Key::O; case GLFW_KEY_H:
case GLFW_KEY_P: return Key::P; return Key::H;
case GLFW_KEY_Q: return Key::Q; case GLFW_KEY_I:
case GLFW_KEY_R: return Key::R; return Key::I;
case GLFW_KEY_S: return Key::S; case GLFW_KEY_J:
case GLFW_KEY_T: return Key::T; return Key::J;
case GLFW_KEY_U: return Key::U; case GLFW_KEY_K:
case GLFW_KEY_V: return Key::V; return Key::K;
case GLFW_KEY_W: return Key::W; case GLFW_KEY_L:
case GLFW_KEY_X: return Key::X; return Key::L;
case GLFW_KEY_Y: return Key::Y; case GLFW_KEY_M:
case GLFW_KEY_Z: return Key::Z; 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_0:
case GLFW_KEY_1: return Key::Num1; return Key::Num0;
case GLFW_KEY_2: return Key::Num2; case GLFW_KEY_1:
case GLFW_KEY_3: return Key::Num3; return Key::Num1;
case GLFW_KEY_4: return Key::Num4; case GLFW_KEY_2:
case GLFW_KEY_5: return Key::Num5; return Key::Num2;
case GLFW_KEY_6: return Key::Num6; case GLFW_KEY_3:
case GLFW_KEY_7: return Key::Num7; return Key::Num3;
case GLFW_KEY_8: return Key::Num8; case GLFW_KEY_4:
case GLFW_KEY_9: return Key::Num9; 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_F1:
case GLFW_KEY_F2: return Key::F2; return Key::F1;
case GLFW_KEY_F3: return Key::F3; case GLFW_KEY_F2:
case GLFW_KEY_F4: return Key::F4; return Key::F2;
case GLFW_KEY_F5: return Key::F5; case GLFW_KEY_F3:
case GLFW_KEY_F6: return Key::F6; return Key::F3;
case GLFW_KEY_F7: return Key::F7; case GLFW_KEY_F4:
case GLFW_KEY_F8: return Key::F8; return Key::F4;
case GLFW_KEY_F9: return Key::F9; case GLFW_KEY_F5:
case GLFW_KEY_F10: return Key::F10; return Key::F5;
case GLFW_KEY_F11: return Key::F11; case GLFW_KEY_F6:
case GLFW_KEY_F12: return Key::F12; 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_SPACE:
case GLFW_KEY_ENTER: return Key::Enter; return Key::Space;
case GLFW_KEY_ESCAPE: return Key::Escape; case GLFW_KEY_ENTER:
case GLFW_KEY_TAB: return Key::Tab; return Key::Enter;
case GLFW_KEY_BACKSPACE: return Key::Backspace; case GLFW_KEY_ESCAPE:
case GLFW_KEY_INSERT: return Key::Insert; return Key::Escape;
case GLFW_KEY_DELETE: return Key::Delete; case GLFW_KEY_TAB:
case GLFW_KEY_HOME: return Key::Home; return Key::Tab;
case GLFW_KEY_END: return Key::End; case GLFW_KEY_BACKSPACE:
case GLFW_KEY_PAGE_UP: return Key::PageUp; return Key::Backspace;
case GLFW_KEY_PAGE_DOWN: return Key::PageDown; 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_UP:
case GLFW_KEY_DOWN: return Key::Down; return Key::Up;
case GLFW_KEY_LEFT: return Key::Left; case GLFW_KEY_DOWN:
case GLFW_KEY_RIGHT: return Key::Right; 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_LEFT_SHIFT:
case GLFW_KEY_RIGHT_SHIFT: return Key::RShift; return Key::LShift;
case GLFW_KEY_LEFT_CONTROL: return Key::LCtrl; case GLFW_KEY_RIGHT_SHIFT:
case GLFW_KEY_RIGHT_CONTROL: return Key::RCtrl; return Key::RShift;
case GLFW_KEY_LEFT_ALT: return Key::LAlt; case GLFW_KEY_LEFT_CONTROL:
case GLFW_KEY_RIGHT_ALT: return Key::RAlt; 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_CAPS_LOCK:
case GLFW_KEY_NUM_LOCK: return Key::NumLock; return Key::CapsLock;
case GLFW_KEY_SCROLL_LOCK: return Key::ScrollLock; case GLFW_KEY_NUM_LOCK:
return Key::NumLock;
case GLFW_KEY_SCROLL_LOCK:
return Key::ScrollLock;
default: return Key::None; default:
return Key::None;
} }
} }
@ -106,9 +181,7 @@ GLFWInput::GLFWInput() {
gamepadPrevious_.fill(false); gamepadPrevious_.fill(false);
} }
GLFWInput::~GLFWInput() { GLFWInput::~GLFWInput() { shutdown(); }
shutdown();
}
void GLFWInput::init() { void GLFWInput::init() {
E2D_LOG_INFO("GLFWInput initialized"); E2D_LOG_INFO("GLFWInput initialized");
@ -207,31 +280,21 @@ bool GLFWInput::released(Mouse btn) const {
return false; return false;
} }
Vec2 GLFWInput::mouse() const { Vec2 GLFWInput::mouse() const { return mousePos_; }
return mousePos_;
}
Vec2 GLFWInput::mouseDelta() const { Vec2 GLFWInput::mouseDelta() const { return mouseDelta_; }
return mouseDelta_;
}
float GLFWInput::scroll() const { float GLFWInput::scroll() const { return scroll_; }
return scroll_;
}
float GLFWInput::scrollDelta() const { float GLFWInput::scrollDelta() const { return scrollDelta_; }
return scrollDelta_;
}
void GLFWInput::setMouse(const Vec2& pos) { void GLFWInput::setMouse(const Vec2 &pos) {
if (window_) { if (window_) {
glfwSetCursorPos(window_, pos.x, pos.y); glfwSetCursorPos(window_, pos.x, pos.y);
} }
} }
bool GLFWInput::gamepad() const { bool GLFWInput::gamepad() const { return gamepadId_ != -1; }
return gamepadId_ != -1;
}
bool GLFWInput::down(Gamepad btn) const { bool GLFWInput::down(Gamepad btn) const {
size_t idx = static_cast<size_t>(btn); size_t idx = static_cast<size_t>(btn);
@ -257,21 +320,13 @@ bool GLFWInput::released(Gamepad btn) const {
return false; return false;
} }
Vec2 GLFWInput::leftStick() const { Vec2 GLFWInput::leftStick() const { return leftStick_; }
return leftStick_;
}
Vec2 GLFWInput::rightStick() const { Vec2 GLFWInput::rightStick() const { return rightStick_; }
return rightStick_;
}
float GLFWInput::leftTrigger() const { float GLFWInput::leftTrigger() const { return leftTrigger_; }
return leftTrigger_;
}
float GLFWInput::rightTrigger() const { float GLFWInput::rightTrigger() const { return rightTrigger_; }
return rightTrigger_;
}
void GLFWInput::vibrate(float left, float right) { void GLFWInput::vibrate(float left, float right) {
// GLFW 本身不支持震动,需要平台特定的代码 // GLFW 本身不支持震动,需要平台特定的代码
@ -280,13 +335,9 @@ void GLFWInput::vibrate(float left, float right) {
(void)right; (void)right;
} }
bool GLFWInput::touching() const { bool GLFWInput::touching() const { return false; }
return false;
}
int GLFWInput::touchCount() const { int GLFWInput::touchCount() const { return 0; }
return 0;
}
Vec2 GLFWInput::touch(int index) const { Vec2 GLFWInput::touch(int index) const {
(void)index; (void)index;
@ -366,21 +417,36 @@ void GLFWInput::updateGamepad() {
} }
// 更新按钮状态 // 更新按钮状态
gamepadCurrent_[static_cast<size_t>(Gamepad::A)] = state.buttons[GLFW_GAMEPAD_BUTTON_A] == GLFW_PRESS; gamepadCurrent_[static_cast<size_t>(Gamepad::A)] =
gamepadCurrent_[static_cast<size_t>(Gamepad::B)] = state.buttons[GLFW_GAMEPAD_BUTTON_B] == GLFW_PRESS; state.buttons[GLFW_GAMEPAD_BUTTON_A] == GLFW_PRESS;
gamepadCurrent_[static_cast<size_t>(Gamepad::X)] = state.buttons[GLFW_GAMEPAD_BUTTON_X] == GLFW_PRESS; gamepadCurrent_[static_cast<size_t>(Gamepad::B)] =
gamepadCurrent_[static_cast<size_t>(Gamepad::Y)] = state.buttons[GLFW_GAMEPAD_BUTTON_Y] == GLFW_PRESS; state.buttons[GLFW_GAMEPAD_BUTTON_B] == GLFW_PRESS;
gamepadCurrent_[static_cast<size_t>(Gamepad::Back)] = state.buttons[GLFW_GAMEPAD_BUTTON_BACK] == GLFW_PRESS; gamepadCurrent_[static_cast<size_t>(Gamepad::X)] =
gamepadCurrent_[static_cast<size_t>(Gamepad::Start)] = state.buttons[GLFW_GAMEPAD_BUTTON_START] == GLFW_PRESS; state.buttons[GLFW_GAMEPAD_BUTTON_X] == GLFW_PRESS;
gamepadCurrent_[static_cast<size_t>(Gamepad::LStick)] = state.buttons[GLFW_GAMEPAD_BUTTON_LEFT_THUMB] == GLFW_PRESS; gamepadCurrent_[static_cast<size_t>(Gamepad::Y)] =
gamepadCurrent_[static_cast<size_t>(Gamepad::RStick)] = state.buttons[GLFW_GAMEPAD_BUTTON_RIGHT_THUMB] == GLFW_PRESS; state.buttons[GLFW_GAMEPAD_BUTTON_Y] == GLFW_PRESS;
gamepadCurrent_[static_cast<size_t>(Gamepad::LB)] = state.buttons[GLFW_GAMEPAD_BUTTON_LEFT_BUMPER] == GLFW_PRESS; gamepadCurrent_[static_cast<size_t>(Gamepad::Back)] =
gamepadCurrent_[static_cast<size_t>(Gamepad::RB)] = state.buttons[GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER] == GLFW_PRESS; state.buttons[GLFW_GAMEPAD_BUTTON_BACK] == GLFW_PRESS;
gamepadCurrent_[static_cast<size_t>(Gamepad::DUp)] = state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_UP] == GLFW_PRESS; gamepadCurrent_[static_cast<size_t>(Gamepad::Start)] =
gamepadCurrent_[static_cast<size_t>(Gamepad::DDown)] = state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_DOWN] == GLFW_PRESS; state.buttons[GLFW_GAMEPAD_BUTTON_START] == GLFW_PRESS;
gamepadCurrent_[static_cast<size_t>(Gamepad::DLeft)] = state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_LEFT] == GLFW_PRESS; gamepadCurrent_[static_cast<size_t>(Gamepad::LStick)] =
gamepadCurrent_[static_cast<size_t>(Gamepad::DRight)] = state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_RIGHT] == GLFW_PRESS; state.buttons[GLFW_GAMEPAD_BUTTON_LEFT_THUMB] == GLFW_PRESS;
gamepadCurrent_[static_cast<size_t>(Gamepad::Guide)] = state.buttons[GLFW_GAMEPAD_BUTTON_GUIDE] == GLFW_PRESS; gamepadCurrent_[static_cast<size_t>(Gamepad::RStick)] =
state.buttons[GLFW_GAMEPAD_BUTTON_RIGHT_THUMB] == GLFW_PRESS;
gamepadCurrent_[static_cast<size_t>(Gamepad::LB)] =
state.buttons[GLFW_GAMEPAD_BUTTON_LEFT_BUMPER] == GLFW_PRESS;
gamepadCurrent_[static_cast<size_t>(Gamepad::RB)] =
state.buttons[GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER] == GLFW_PRESS;
gamepadCurrent_[static_cast<size_t>(Gamepad::DUp)] =
state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_UP] == GLFW_PRESS;
gamepadCurrent_[static_cast<size_t>(Gamepad::DDown)] =
state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_DOWN] == GLFW_PRESS;
gamepadCurrent_[static_cast<size_t>(Gamepad::DLeft)] =
state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_LEFT] == GLFW_PRESS;
gamepadCurrent_[static_cast<size_t>(Gamepad::DRight)] =
state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_RIGHT] == GLFW_PRESS;
gamepadCurrent_[static_cast<size_t>(Gamepad::Guide)] =
state.buttons[GLFW_GAMEPAD_BUTTON_GUIDE] == GLFW_PRESS;
// 更新摇杆值(应用死区) // 更新摇杆值(应用死区)
leftStick_.x = applyDeadzone(state.axes[GLFW_GAMEPAD_AXIS_LEFT_X]); leftStick_.x = applyDeadzone(state.axes[GLFW_GAMEPAD_AXIS_LEFT_X]);

View File

@ -1,17 +1,18 @@
#include "glfw_window.h" #include "glfw_window.h"
#include "glfw_input.h" #include "glfw_input.h"
#include <extra2d/utils/logger.h> #include <extra2d/core/service_locator.h>
#include <extra2d/services/logger_service.h>
#include <glad/glad.h> #include <glad/glad.h>
namespace extra2d { namespace extra2d {
GLFWWindow::GLFWWindow() {} GLFWWindow::GLFWWindow() {}
GLFWWindow::~GLFWWindow() { GLFWWindow::~GLFWWindow() { destroy(); }
destroy();
}
bool GLFWWindow::create(const std::string& title, int width, int height, bool vsync) { bool GLFWWindow::create(const std::string &title, int width, int height,
bool vsync) {
if (!initGLFW()) { if (!initGLFW()) {
return false; return false;
} }
@ -32,17 +33,13 @@ bool GLFWWindow::create(const std::string& title, int width, int height, bool vs
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
#endif #endif
GLFWmonitor* monitor = nullptr; GLFWmonitor *monitor = nullptr;
#ifdef __SWITCH__ #ifdef __SWITCH__
monitor = glfwGetPrimaryMonitor(); monitor = glfwGetPrimaryMonitor();
#endif #endif
glfwWindow_ = glfwCreateWindow( glfwWindow_ =
width, height, glfwCreateWindow(width, height, title.c_str(), monitor, nullptr);
title.c_str(),
monitor,
nullptr
);
if (!glfwWindow_) { if (!glfwWindow_) {
E2D_LOG_ERROR("Failed to create GLFW window"); E2D_LOG_ERROR("Failed to create GLFW window");
@ -52,9 +49,9 @@ bool GLFWWindow::create(const std::string& title, int width, int height, bool vs
#ifndef __SWITCH__ #ifndef __SWITCH__
if (!fullscreen_ && !monitor) { if (!fullscreen_ && !monitor) {
GLFWmonitor* primaryMonitor = glfwGetPrimaryMonitor(); GLFWmonitor *primaryMonitor = glfwGetPrimaryMonitor();
if (primaryMonitor) { if (primaryMonitor) {
const GLFWvidmode* mode = glfwGetVideoMode(primaryMonitor); const GLFWvidmode *mode = glfwGetVideoMode(primaryMonitor);
if (mode) { if (mode) {
int screenWidth = mode->width; int screenWidth = mode->width;
int screenHeight = mode->height; int screenHeight = mode->height;
@ -117,7 +114,8 @@ void GLFWWindow::destroy() {
} }
void GLFWWindow::poll() { void GLFWWindow::poll() {
if (!glfwWindow_) return; if (!glfwWindow_)
return;
if (input_) { if (input_) {
input_->update(); input_->update();
@ -133,7 +131,8 @@ void GLFWWindow::swap() {
} }
bool GLFWWindow::shouldClose() const { bool GLFWWindow::shouldClose() const {
if (!glfwWindow_) return true; if (!glfwWindow_)
return true;
return shouldClose_ || glfwWindowShouldClose(glfwWindow_); return shouldClose_ || glfwWindowShouldClose(glfwWindow_);
} }
@ -144,7 +143,7 @@ void GLFWWindow::close() {
} }
} }
void GLFWWindow::setTitle(const std::string& title) { void GLFWWindow::setTitle(const std::string &title) {
if (glfwWindow_) { if (glfwWindow_) {
glfwSetWindowTitle(glfwWindow_, title.c_str()); glfwSetWindowTitle(glfwWindow_, title.c_str());
} }
@ -171,14 +170,17 @@ void GLFWWindow::setPos(int x, int y) {
void GLFWWindow::setFullscreen(bool fs) { void GLFWWindow::setFullscreen(bool fs) {
#ifndef __SWITCH__ #ifndef __SWITCH__
if (!glfwWindow_) return; if (!glfwWindow_)
return;
if (fs == fullscreen_) return; if (fs == fullscreen_)
return;
if (fs) { if (fs) {
GLFWmonitor* monitor = glfwGetPrimaryMonitor(); GLFWmonitor *monitor = glfwGetPrimaryMonitor();
const GLFWvidmode* mode = glfwGetVideoMode(monitor); const GLFWvidmode *mode = glfwGetVideoMode(monitor);
glfwSetWindowMonitor(glfwWindow_, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); glfwSetWindowMonitor(glfwWindow_, monitor, 0, 0, mode->width, mode->height,
mode->refreshRate);
} else { } else {
glfwSetWindowMonitor(glfwWindow_, nullptr, 100, 100, 1280, 720, 0); glfwSetWindowMonitor(glfwWindow_, nullptr, 100, 100, 1280, 720, 0);
} }
@ -211,13 +213,9 @@ void GLFWWindow::setVisible(bool visible) {
#endif #endif
} }
int GLFWWindow::width() const { int GLFWWindow::width() const { return width_; }
return width_;
}
int GLFWWindow::height() const { int GLFWWindow::height() const { return height_; }
return height_;
}
Size GLFWWindow::size() const { Size GLFWWindow::size() const {
return Size(static_cast<float>(width_), static_cast<float>(height_)); return Size(static_cast<float>(width_), static_cast<float>(height_));
@ -233,33 +231,22 @@ Vec2 GLFWWindow::pos() const {
return Vec2(static_cast<float>(x), static_cast<float>(y)); return Vec2(static_cast<float>(x), static_cast<float>(y));
} }
bool GLFWWindow::fullscreen() const { bool GLFWWindow::fullscreen() const { return fullscreen_; }
return fullscreen_;
}
bool GLFWWindow::vsync() const { bool GLFWWindow::vsync() const { return vsync_; }
return vsync_;
}
bool GLFWWindow::focused() const { bool GLFWWindow::focused() const { return focused_; }
return focused_;
}
bool GLFWWindow::minimized() const { bool GLFWWindow::minimized() const { return minimized_; }
return minimized_;
}
float GLFWWindow::scaleX() const { float GLFWWindow::scaleX() const { return scaleX_; }
return scaleX_;
}
float GLFWWindow::scaleY() const { float GLFWWindow::scaleY() const { return scaleY_; }
return scaleY_;
}
void GLFWWindow::setCursor(Cursor cursor) { void GLFWWindow::setCursor(Cursor cursor) {
#ifndef __SWITCH__ #ifndef __SWITCH__
if (!glfwWindow_) return; if (!glfwWindow_)
return;
if (cursor == Cursor::Hidden) { if (cursor == Cursor::Hidden) {
glfwSetInputMode(glfwWindow_, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); glfwSetInputMode(glfwWindow_, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
@ -268,7 +255,7 @@ void GLFWWindow::setCursor(Cursor cursor) {
glfwSetInputMode(glfwWindow_, GLFW_CURSOR, GLFW_CURSOR_NORMAL); glfwSetInputMode(glfwWindow_, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
GLFWcursor* glfwCursor = nullptr; GLFWcursor *glfwCursor = nullptr;
switch (cursor) { switch (cursor) {
case Cursor::Arrow: case Cursor::Arrow:
glfwCursor = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); glfwCursor = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
@ -304,7 +291,8 @@ void GLFWWindow::setCursor(Cursor cursor) {
void GLFWWindow::showCursor(bool show) { void GLFWWindow::showCursor(bool show) {
#ifndef __SWITCH__ #ifndef __SWITCH__
if (glfwWindow_) { if (glfwWindow_) {
glfwSetInputMode(glfwWindow_, GLFW_CURSOR, show ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_HIDDEN); glfwSetInputMode(glfwWindow_, GLFW_CURSOR,
show ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_HIDDEN);
cursorVisible_ = show; cursorVisible_ = show;
} }
#else #else
@ -315,7 +303,8 @@ void GLFWWindow::showCursor(bool show) {
void GLFWWindow::lockCursor(bool lock) { void GLFWWindow::lockCursor(bool lock) {
#ifndef __SWITCH__ #ifndef __SWITCH__
if (glfwWindow_) { if (glfwWindow_) {
glfwSetInputMode(glfwWindow_, GLFW_CURSOR, lock ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_NORMAL); glfwSetInputMode(glfwWindow_, GLFW_CURSOR,
lock ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_NORMAL);
cursorLocked_ = lock; cursorLocked_ = lock;
} }
#else #else
@ -323,25 +312,15 @@ void GLFWWindow::lockCursor(bool lock) {
#endif #endif
} }
IInput* GLFWWindow::input() const { IInput *GLFWWindow::input() const { return input_.get(); }
return input_.get();
}
void GLFWWindow::onResize(ResizeCb cb) { void GLFWWindow::onResize(ResizeCb cb) { resizeCb_ = cb; }
resizeCb_ = cb;
}
void GLFWWindow::onClose(CloseCb cb) { void GLFWWindow::onClose(CloseCb cb) { closeCb_ = cb; }
closeCb_ = cb;
}
void GLFWWindow::onFocus(FocusCb cb) { void GLFWWindow::onFocus(FocusCb cb) { focusCb_ = cb; }
focusCb_ = cb;
}
void* GLFWWindow::native() const { void *GLFWWindow::native() const { return glfwWindow_; }
return glfwWindow_;
}
bool GLFWWindow::initGLFW() { bool GLFWWindow::initGLFW() {
static int glfwInitCount = 0; static int glfwInitCount = 0;
@ -373,8 +352,10 @@ void GLFWWindow::updateContentScale() {
} }
// 静态回调函数 // 静态回调函数
void GLFWWindow::framebufferSizeCallback(GLFWwindow* window, int width, int height) { void GLFWWindow::framebufferSizeCallback(GLFWwindow *window, int width,
GLFWWindow* self = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window)); int height) {
GLFWWindow *self =
static_cast<GLFWWindow *>(glfwGetWindowUserPointer(window));
if (self) { if (self) {
self->width_ = width; self->width_ = width;
self->height_ = height; self->height_ = height;
@ -385,8 +366,9 @@ void GLFWWindow::framebufferSizeCallback(GLFWwindow* window, int width, int heig
} }
} }
void GLFWWindow::windowCloseCallback(GLFWwindow* window) { void GLFWWindow::windowCloseCallback(GLFWwindow *window) {
GLFWWindow* self = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window)); GLFWWindow *self =
static_cast<GLFWWindow *>(glfwGetWindowUserPointer(window));
if (self) { if (self) {
self->shouldClose_ = true; self->shouldClose_ = true;
if (self->closeCb_) { if (self->closeCb_) {
@ -395,8 +377,9 @@ void GLFWWindow::windowCloseCallback(GLFWwindow* window) {
} }
} }
void GLFWWindow::windowFocusCallback(GLFWwindow* window, int focused) { void GLFWWindow::windowFocusCallback(GLFWwindow *window, int focused) {
GLFWWindow* self = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window)); GLFWWindow *self =
static_cast<GLFWWindow *>(glfwGetWindowUserPointer(window));
if (self) { if (self) {
self->focused_ = (focused == GLFW_TRUE); self->focused_ = (focused == GLFW_TRUE);
if (self->focusCb_) { if (self->focusCb_) {
@ -405,36 +388,45 @@ void GLFWWindow::windowFocusCallback(GLFWwindow* window, int focused) {
} }
} }
void GLFWWindow::windowIconifyCallback(GLFWwindow* window, int iconified) { void GLFWWindow::windowIconifyCallback(GLFWwindow *window, int iconified) {
GLFWWindow* self = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window)); GLFWWindow *self =
static_cast<GLFWWindow *>(glfwGetWindowUserPointer(window));
if (self) { if (self) {
self->minimized_ = (iconified == GLFW_TRUE); self->minimized_ = (iconified == GLFW_TRUE);
} }
} }
void GLFWWindow::cursorPosCallback(GLFWwindow* window, double xpos, double ypos) { void GLFWWindow::cursorPosCallback(GLFWwindow *window, double xpos,
GLFWWindow* self = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window)); double ypos) {
GLFWWindow *self =
static_cast<GLFWWindow *>(glfwGetWindowUserPointer(window));
if (self && self->input_) { if (self && self->input_) {
self->input_->handleCursorPosEvent(xpos, ypos); self->input_->handleCursorPosEvent(xpos, ypos);
} }
} }
void GLFWWindow::mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) { void GLFWWindow::mouseButtonCallback(GLFWwindow *window, int button, int action,
GLFWWindow* self = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window)); int mods) {
GLFWWindow *self =
static_cast<GLFWWindow *>(glfwGetWindowUserPointer(window));
if (self && self->input_) { if (self && self->input_) {
self->input_->handleMouseButtonEvent(button, action, mods); self->input_->handleMouseButtonEvent(button, action, mods);
} }
} }
void GLFWWindow::scrollCallback(GLFWwindow* window, double xoffset, double yoffset) { void GLFWWindow::scrollCallback(GLFWwindow *window, double xoffset,
GLFWWindow* self = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window)); double yoffset) {
GLFWWindow *self =
static_cast<GLFWWindow *>(glfwGetWindowUserPointer(window));
if (self && self->input_) { if (self && self->input_) {
self->input_->handleScrollEvent(xoffset, yoffset); self->input_->handleScrollEvent(xoffset, yoffset);
} }
} }
void GLFWWindow::keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { void GLFWWindow::keyCallback(GLFWwindow *window, int key, int scancode,
GLFWWindow* self = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window)); int action, int mods) {
GLFWWindow *self =
static_cast<GLFWWindow *>(glfwGetWindowUserPointer(window));
if (self && self->input_) { if (self && self->input_) {
self->input_->handleKeyEvent(key, scancode, action, mods); self->input_->handleKeyEvent(key, scancode, action, mods);
} }

View File

@ -1,6 +1,8 @@
#include "sdl2_input.h" #include "sdl2_input.h"
#include <extra2d/utils/logger.h>
#include <cmath> #include <cmath>
#include <extra2d/core/service_locator.h>
#include <extra2d/services/logger_service.h>
namespace extra2d { namespace extra2d {
@ -13,9 +15,7 @@ SDL2Input::SDL2Input() {
gamepadPrevious_.fill(false); gamepadPrevious_.fill(false);
} }
SDL2Input::~SDL2Input() { SDL2Input::~SDL2Input() { shutdown(); }
shutdown();
}
void SDL2Input::init() { void SDL2Input::init() {
E2D_LOG_INFO("SDL2Input initialized"); E2D_LOG_INFO("SDL2Input initialized");
@ -47,7 +47,7 @@ void SDL2Input::setEventCallback(EventCallback callback) {
eventCallback_ = std::move(callback); eventCallback_ = std::move(callback);
} }
void SDL2Input::handleSDLEvent(const SDL_Event& event) { void SDL2Input::handleSDLEvent(const SDL_Event &event) {
switch (event.type) { switch (event.type) {
case SDL_KEYDOWN: { case SDL_KEYDOWN: {
int key = event.key.keysym.scancode; int key = event.key.keysym.scancode;
@ -55,11 +55,9 @@ void SDL2Input::handleSDLEvent(const SDL_Event& event) {
if (!keyCurrent_[key]) { if (!keyCurrent_[key]) {
keyCurrent_[key] = true; keyCurrent_[key] = true;
Event e = Event::createKeyPress( Event e = Event::createKeyPress(event.key.keysym.sym,
event.key.keysym.sym,
event.key.keysym.scancode, event.key.keysym.scancode,
event.key.keysym.mod event.key.keysym.mod);
);
dispatchEvent(e); dispatchEvent(e);
} }
} }
@ -71,11 +69,9 @@ void SDL2Input::handleSDLEvent(const SDL_Event& event) {
if (key >= 0 && key < static_cast<int>(Key::Count)) { if (key >= 0 && key < static_cast<int>(Key::Count)) {
keyCurrent_[key] = false; keyCurrent_[key] = false;
Event e = Event::createKeyRelease( Event e = Event::createKeyRelease(event.key.keysym.sym,
event.key.keysym.sym,
event.key.keysym.scancode, event.key.keysym.scancode,
event.key.keysym.mod event.key.keysym.mod);
);
dispatchEvent(e); dispatchEvent(e);
} }
break; break;
@ -140,7 +136,9 @@ void SDL2Input::handleSDLEvent(const SDL_Event& event) {
break; break;
case SDL_CONTROLLERDEVICEREMOVED: case SDL_CONTROLLERDEVICEREMOVED:
if (gamepad_ && event.cdevice.which == SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(gamepad_))) { if (gamepad_ &&
event.cdevice.which ==
SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(gamepad_))) {
E2D_LOG_INFO("Gamepad disconnected"); E2D_LOG_INFO("Gamepad disconnected");
closeGamepad(); closeGamepad();
} }
@ -187,7 +185,7 @@ void SDL2Input::handleSDLEvent(const SDL_Event& event) {
} }
} }
void SDL2Input::dispatchEvent(const Event& event) { void SDL2Input::dispatchEvent(const Event &event) {
if (eventCallback_) { if (eventCallback_) {
eventCallback_(event); eventCallback_(event);
} }
@ -241,29 +239,20 @@ bool SDL2Input::released(Mouse btn) const {
return false; return false;
} }
Vec2 SDL2Input::mouse() const { Vec2 SDL2Input::mouse() const { return mousePos_; }
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<int>(pos.x),
static_cast<int>(pos.y));
} }
Vec2 SDL2Input::mouseDelta() const { bool SDL2Input::gamepad() const { return gamepad_ != nullptr; }
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<int>(pos.x), static_cast<int>(pos.y));
}
bool SDL2Input::gamepad() const {
return gamepad_ != nullptr;
}
bool SDL2Input::down(Gamepad btn) const { bool SDL2Input::down(Gamepad btn) const {
size_t idx = static_cast<size_t>(btn); size_t idx = static_cast<size_t>(btn);
@ -289,21 +278,13 @@ bool SDL2Input::released(Gamepad btn) const {
return false; return false;
} }
Vec2 SDL2Input::leftStick() const { Vec2 SDL2Input::leftStick() const { return leftStick_; }
return leftStick_;
}
Vec2 SDL2Input::rightStick() const { Vec2 SDL2Input::rightStick() const { return rightStick_; }
return rightStick_;
}
float SDL2Input::leftTrigger() const { float SDL2Input::leftTrigger() const { return leftTrigger_; }
return leftTrigger_;
}
float SDL2Input::rightTrigger() const { float SDL2Input::rightTrigger() const { return rightTrigger_; }
return rightTrigger_;
}
void SDL2Input::vibrate(float left, float right) { void SDL2Input::vibrate(float left, float right) {
if (gamepad_) { if (gamepad_) {
@ -313,13 +294,9 @@ void SDL2Input::vibrate(float left, float right) {
} }
} }
bool SDL2Input::touching() const { bool SDL2Input::touching() const { return false; }
return false;
}
int SDL2Input::touchCount() const { int SDL2Input::touchCount() const { return 0; }
return 0;
}
Vec2 SDL2Input::touch(int index) const { Vec2 SDL2Input::touch(int index) const {
(void)index; (void)index;
@ -331,8 +308,7 @@ TouchPoint SDL2Input::touchPoint(int index) const {
return TouchPoint{}; return TouchPoint{};
} }
void SDL2Input::updateKeyboard() { void SDL2Input::updateKeyboard() {}
}
void SDL2Input::updateMouse() { void SDL2Input::updateMouse() {
int x = 0, y = 0; int x = 0, y = 0;
@ -364,7 +340,8 @@ void SDL2Input::updateGamepad() {
rightStick_.y = applyDeadzone(ry / 32767.0f); rightStick_.y = applyDeadzone(ry / 32767.0f);
int lt = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_TRIGGERLEFT); int lt = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_TRIGGERLEFT);
int rt = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_TRIGGERRIGHT); int rt =
SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
leftTrigger_ = lt / 32767.0f; leftTrigger_ = lt / 32767.0f;
rightTrigger_ = rt / 32767.0f; rightTrigger_ = rt / 32767.0f;
@ -394,39 +371,59 @@ void SDL2Input::closeGamepad() {
} }
} }
int SDL2Input::keyToSDL(Key key) { int SDL2Input::keyToSDL(Key key) { return static_cast<int>(key); }
return static_cast<int>(key);
}
int SDL2Input::mouseToSDL(Mouse btn) { int SDL2Input::mouseToSDL(Mouse btn) {
switch (btn) { switch (btn) {
case Mouse::Left: return SDL_BUTTON_LEFT; case Mouse::Left:
case Mouse::Middle: return SDL_BUTTON_MIDDLE; return SDL_BUTTON_LEFT;
case Mouse::Right: return SDL_BUTTON_RIGHT; case Mouse::Middle:
case Mouse::X1: return SDL_BUTTON_X1; return SDL_BUTTON_MIDDLE;
case Mouse::X2: return SDL_BUTTON_X2; case Mouse::Right:
default: return 0; 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) { int SDL2Input::gamepadToSDL(Gamepad btn) {
switch (btn) { switch (btn) {
case Gamepad::A: return SDL_CONTROLLER_BUTTON_A; case Gamepad::A:
case Gamepad::B: return SDL_CONTROLLER_BUTTON_B; return SDL_CONTROLLER_BUTTON_A;
case Gamepad::X: return SDL_CONTROLLER_BUTTON_X; case Gamepad::B:
case Gamepad::Y: return SDL_CONTROLLER_BUTTON_Y; return SDL_CONTROLLER_BUTTON_B;
case Gamepad::Back: return SDL_CONTROLLER_BUTTON_BACK; case Gamepad::X:
case Gamepad::Start: return SDL_CONTROLLER_BUTTON_START; return SDL_CONTROLLER_BUTTON_X;
case Gamepad::LStick: return SDL_CONTROLLER_BUTTON_LEFTSTICK; case Gamepad::Y:
case Gamepad::RStick: return SDL_CONTROLLER_BUTTON_RIGHTSTICK; return SDL_CONTROLLER_BUTTON_Y;
case Gamepad::LB: return SDL_CONTROLLER_BUTTON_LEFTSHOULDER; case Gamepad::Back:
case Gamepad::RB: return SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; return SDL_CONTROLLER_BUTTON_BACK;
case Gamepad::DUp: return SDL_CONTROLLER_BUTTON_DPAD_UP; case Gamepad::Start:
case Gamepad::DDown: return SDL_CONTROLLER_BUTTON_DPAD_DOWN; return SDL_CONTROLLER_BUTTON_START;
case Gamepad::DLeft: return SDL_CONTROLLER_BUTTON_DPAD_LEFT; case Gamepad::LStick:
case Gamepad::DRight: return SDL_CONTROLLER_BUTTON_DPAD_RIGHT; return SDL_CONTROLLER_BUTTON_LEFTSTICK;
case Gamepad::Guide: return SDL_CONTROLLER_BUTTON_GUIDE; case Gamepad::RStick:
default: return 0; 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;
} }
} }
@ -439,13 +436,19 @@ Key SDL2Input::sdlToKey(int sdlKey) {
Mouse SDL2Input::sdlToMouse(int sdlButton) { Mouse SDL2Input::sdlToMouse(int sdlButton) {
switch (sdlButton) { switch (sdlButton) {
case SDL_BUTTON_LEFT: return Mouse::Left; case SDL_BUTTON_LEFT:
case SDL_BUTTON_MIDDLE: return Mouse::Middle; return Mouse::Left;
case SDL_BUTTON_RIGHT: return Mouse::Right; case SDL_BUTTON_MIDDLE:
case SDL_BUTTON_X1: return Mouse::X1; return Mouse::Middle;
case SDL_BUTTON_X2: return Mouse::X2; case SDL_BUTTON_RIGHT:
default: return Mouse::Count; return Mouse::Right;
case SDL_BUTTON_X1:
return Mouse::X1;
case SDL_BUTTON_X2:
return Mouse::X2;
default:
return Mouse::Count;
} }
} }
} } // namespace extra2d

View File

@ -1,8 +1,10 @@
#include "sdl2_window.h" #include "sdl2_window.h"
#include "sdl2_input.h" #include "sdl2_input.h"
#include <extra2d/utils/logger.h> #include <extra2d/core/service_locator.h>
#include <extra2d/services/logger_service.h>
#include <glad/glad.h> #include <glad/glad.h>
namespace extra2d { namespace extra2d {
SDL2Window::SDL2Window() { SDL2Window::SDL2Window() {
@ -11,11 +13,10 @@ SDL2Window::SDL2Window() {
} }
} }
SDL2Window::~SDL2Window() { SDL2Window::~SDL2Window() { destroy(); }
destroy();
}
bool SDL2Window::create(const std::string& title, int width, int height, bool vsync) { bool SDL2Window::create(const std::string &title, int width, int height,
bool vsync) {
if (!initSDL()) { if (!initSDL()) {
return false; return false;
} }
@ -34,12 +35,8 @@ bool SDL2Window::create(const std::string& title, int width, int height, bool vs
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
sdlWindow_ = SDL_CreateWindow( sdlWindow_ = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED,
title.c_str(), SDL_WINDOWPOS_CENTERED, width, height, flags);
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
width, height,
flags
);
if (!sdlWindow_) { if (!sdlWindow_) {
E2D_LOG_ERROR("Failed to create SDL window: {}", SDL_GetError()); E2D_LOG_ERROR("Failed to create SDL window: {}", SDL_GetError());
@ -109,7 +106,8 @@ void SDL2Window::destroy() {
} }
void SDL2Window::poll() { void SDL2Window::poll() {
if (!sdlWindow_) return; if (!sdlWindow_)
return;
if (input_) { if (input_) {
input_->update(); input_->update();
@ -127,15 +125,11 @@ void SDL2Window::swap() {
} }
} }
bool SDL2Window::shouldClose() const { bool SDL2Window::shouldClose() const { return shouldClose_; }
return shouldClose_;
}
void SDL2Window::close() { void SDL2Window::close() { shouldClose_ = true; }
shouldClose_ = true;
}
void SDL2Window::setTitle(const std::string& title) { void SDL2Window::setTitle(const std::string &title) {
if (sdlWindow_) { if (sdlWindow_) {
SDL_SetWindowTitle(sdlWindow_, title.c_str()); SDL_SetWindowTitle(sdlWindow_, title.c_str());
} }
@ -192,13 +186,9 @@ void SDL2Window::setVisible(bool visible) {
#endif #endif
} }
int SDL2Window::width() const { int SDL2Window::width() const { return width_; }
return width_;
}
int SDL2Window::height() const { int SDL2Window::height() const { return height_; }
return height_;
}
Size SDL2Window::size() const { Size SDL2Window::size() const {
return Size(static_cast<float>(width_), static_cast<float>(height_)); return Size(static_cast<float>(width_), static_cast<float>(height_));
@ -214,29 +204,17 @@ Vec2 SDL2Window::pos() const {
return Vec2(static_cast<float>(x), static_cast<float>(y)); return Vec2(static_cast<float>(x), static_cast<float>(y));
} }
bool SDL2Window::fullscreen() const { bool SDL2Window::fullscreen() const { return fullscreen_; }
return fullscreen_;
}
bool SDL2Window::vsync() const { bool SDL2Window::vsync() const { return vsync_; }
return vsync_;
}
bool SDL2Window::focused() const { bool SDL2Window::focused() const { return focused_; }
return focused_;
}
bool SDL2Window::minimized() const { bool SDL2Window::minimized() const { return minimized_; }
return minimized_;
}
float SDL2Window::scaleX() const { float SDL2Window::scaleX() const { return scaleX_; }
return scaleX_;
}
float SDL2Window::scaleY() const { float SDL2Window::scaleY() const { return scaleY_; }
return scaleY_;
}
void SDL2Window::setCursor(Cursor cursor) { void SDL2Window::setCursor(Cursor cursor) {
#ifndef __SWITCH__ #ifndef __SWITCH__
@ -277,25 +255,15 @@ void SDL2Window::lockCursor(bool lock) {
#endif #endif
} }
IInput* SDL2Window::input() const { IInput *SDL2Window::input() const { return input_.get(); }
return input_.get();
}
void SDL2Window::onResize(ResizeCb cb) { void SDL2Window::onResize(ResizeCb cb) { resizeCb_ = cb; }
resizeCb_ = cb;
}
void SDL2Window::onClose(CloseCb cb) { void SDL2Window::onClose(CloseCb cb) { closeCb_ = cb; }
closeCb_ = cb;
}
void SDL2Window::onFocus(FocusCb cb) { void SDL2Window::onFocus(FocusCb cb) { focusCb_ = cb; }
focusCb_ = cb;
}
void* SDL2Window::native() const { void *SDL2Window::native() const { return sdlWindow_; }
return sdlWindow_;
}
bool SDL2Window::initSDL() { bool SDL2Window::initSDL() {
static int sdlInitCount = 0; static int sdlInitCount = 0;
@ -349,7 +317,7 @@ void SDL2Window::updateContentScale() {
} }
} }
void SDL2Window::handleEvent(const SDL_Event& event) { void SDL2Window::handleEvent(const SDL_Event &event) {
if (input_) { if (input_) {
input_->handleSDLEvent(event); input_->handleSDLEvent(event);
} }
@ -357,7 +325,8 @@ void SDL2Window::handleEvent(const SDL_Event& event) {
switch (event.type) { switch (event.type) {
case SDL_QUIT: case SDL_QUIT:
shouldClose_ = true; shouldClose_ = true;
if (closeCb_) closeCb_(); if (closeCb_)
closeCb_();
break; break;
case SDL_WINDOWEVENT: case SDL_WINDOWEVENT:
@ -367,17 +336,20 @@ void SDL2Window::handleEvent(const SDL_Event& event) {
width_ = event.window.data1; width_ = event.window.data1;
height_ = event.window.data2; height_ = event.window.data2;
updateContentScale(); updateContentScale();
if (resizeCb_) resizeCb_(width_, height_); if (resizeCb_)
resizeCb_(width_, height_);
break; break;
case SDL_WINDOWEVENT_FOCUS_GAINED: case SDL_WINDOWEVENT_FOCUS_GAINED:
focused_ = true; focused_ = true;
if (focusCb_) focusCb_(true); if (focusCb_)
focusCb_(true);
break; break;
case SDL_WINDOWEVENT_FOCUS_LOST: case SDL_WINDOWEVENT_FOCUS_LOST:
focused_ = false; focused_ = false;
if (focusCb_) focusCb_(false); if (focusCb_)
focusCb_(false);
break; break;
case SDL_WINDOWEVENT_MINIMIZED: case SDL_WINDOWEVENT_MINIMIZED:
@ -390,11 +362,12 @@ void SDL2Window::handleEvent(const SDL_Event& event) {
case SDL_WINDOWEVENT_CLOSE: case SDL_WINDOWEVENT_CLOSE:
shouldClose_ = true; shouldClose_ = true;
if (closeCb_) closeCb_(); if (closeCb_)
closeCb_();
break; break;
} }
break; break;
} }
} }
} } // namespace extra2d

View File

@ -1,7 +1,7 @@
#include <extra2d/platform/window_module.h>
#include <extra2d/platform/backend_factory.h>
#include <extra2d/core/service_locator.h> #include <extra2d/core/service_locator.h>
#include <extra2d/utils/logger.h> #include <extra2d/platform/backend_factory.h>
#include <extra2d/platform/window_module.h>
#include <extra2d/services/logger_service.h>
#ifdef __SWITCH__ #ifdef __SWITCH__
#include <switch.h> #include <switch.h>
@ -16,9 +16,9 @@ void initSDL2Backend();
#elif defined(E2D_BACKEND_GLFW) #elif defined(E2D_BACKEND_GLFW)
void initGLFWBackend(); void initGLFWBackend();
#endif #endif
} } // namespace platform
WindowModule::WindowModule(std::function<void(WindowCfg&)> configFn) { WindowModule::WindowModule(std::function<void(WindowCfg &)> configFn) {
configFn(cfg_); configFn(cfg_);
} }
@ -29,7 +29,8 @@ WindowModule::~WindowModule() {
} }
bool WindowModule::init() { bool WindowModule::init() {
if (initialized_) return true; if (initialized_)
return true;
// 初始化后端(注册到工厂) // 初始化后端(注册到工厂)
#if defined(E2D_BACKEND_SDL2) #if defined(E2D_BACKEND_SDL2)
@ -37,7 +38,7 @@ bool WindowModule::init() {
#elif defined(E2D_BACKEND_GLFW) #elif defined(E2D_BACKEND_GLFW)
platform::initGLFWBackend(); platform::initGLFWBackend();
#else #else
#error "No window backend defined" #error "No window backend defined"
#endif #endif
E2D_LOG_INFO("Window backend initialized"); E2D_LOG_INFO("Window backend initialized");
@ -63,7 +64,8 @@ bool WindowModule::init() {
} }
void WindowModule::shutdown() { void WindowModule::shutdown() {
if (!initialized_) return; if (!initialized_)
return;
if (win_) { if (win_) {
win_->destroy(); win_->destroy();

View File

@ -1,9 +1,11 @@
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/core/render_command.h> #include <extra2d/graphics/core/render_command.h>
#include <extra2d/scene/node.h> #include <extra2d/scene/node.h>
#include <extra2d/scene/scene.h> #include <extra2d/scene/scene.h>
#include <extra2d/utils/logger.h> #include <extra2d/services/logger_service.h>
namespace extra2d { namespace extra2d {

View File

@ -1,7 +1,9 @@
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/core/render_backend.h> #include <extra2d/graphics/core/render_backend.h>
#include <extra2d/graphics/core/render_command.h> #include <extra2d/graphics/core/render_command.h>
#include <extra2d/scene/scene.h> #include <extra2d/scene/scene.h>
#include <extra2d/utils/logger.h> #include <extra2d/services/logger_service.h>
namespace extra2d { namespace extra2d {

View File

@ -1,5 +1,6 @@
#include <algorithm> #include <algorithm>
#include <extra2d/app/application.h> #include <extra2d/app/application.h>
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/core/render_backend.h> #include <extra2d/graphics/core/render_backend.h>
#include <extra2d/graphics/core/render_command.h> #include <extra2d/graphics/core/render_command.h>
#include <extra2d/platform/iinput.h> #include <extra2d/platform/iinput.h>
@ -10,7 +11,8 @@
#include <extra2d/scene/transition_scale_scene.h> #include <extra2d/scene/transition_scale_scene.h>
#include <extra2d/scene/transition_scene.h> #include <extra2d/scene/transition_scene.h>
#include <extra2d/scene/transition_slide_scene.h> #include <extra2d/scene/transition_slide_scene.h>
#include <extra2d/utils/logger.h> #include <extra2d/services/logger_service.h>
namespace extra2d { namespace extra2d {
@ -748,7 +750,8 @@ void SceneManager::finishTransition() {
*/ */
void SceneManager::dispatchPointerEvents(Scene &scene) { void SceneManager::dispatchPointerEvents(Scene &scene) {
auto *input = Application::get().input(); auto *input = Application::get().input();
if (!input) return; if (!input)
return;
Vec2 screenPos = input->mouse(); Vec2 screenPos = input->mouse();
Vec2 worldPos = screenPos; Vec2 worldPos = screenPos;
@ -832,7 +835,6 @@ void SceneManager::dispatchPointerEvents(Scene &scene) {
lastPointerWorld_ = worldPos; lastPointerWorld_ = worldPos;
} }
void SceneManager::doSceneSwitch() { void SceneManager::doSceneSwitch() {}
}
} // namespace extra2d } // namespace extra2d

View File

@ -1,9 +1,9 @@
#include <extra2d/scene/transition_fade_scene.h>
#include <extra2d/app/application.h> #include <extra2d/app/application.h>
#include <extra2d/core/service_locator.h>
#include <extra2d/graphics/core/render_backend.h> #include <extra2d/graphics/core/render_backend.h>
#include <extra2d/platform/iwindow.h> #include <extra2d/platform/iwindow.h>
#include <extra2d/utils/logger.h> #include <extra2d/scene/transition_fade_scene.h>
#include <algorithm> #include <extra2d/services/logger_service.h>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
namespace extra2d { namespace extra2d {

View File

@ -1,6 +1,7 @@
#include <extra2d/scene/transition_scene.h> #include <extra2d/core/service_locator.h>
#include <extra2d/graphics/core/render_backend.h> #include <extra2d/graphics/core/render_backend.h>
#include <extra2d/utils/logger.h> #include <extra2d/scene/transition_scene.h>
#include <extra2d/services/logger_service.h>
namespace extra2d { namespace extra2d {