refactor: 移除logger.h头文件并统一使用logger_service.h
将项目中所有对logger.h的引用替换为logger_service.h,并删除logger.h文件。同时调整了部分文件的include顺序和格式,保持代码风格一致。
This commit is contained in:
parent
6008331fc5
commit
65b143573c
|
|
@ -1,18 +1,19 @@
|
|||
#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 <chrono>
|
||||
#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 <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// 前向声明
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
#include <extra2d/core/service_interface.h>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <cstdarg>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
|
|
@ -47,42 +46,42 @@ public:
|
|||
/**
|
||||
* @brief 记录日志(格式化)
|
||||
*/
|
||||
virtual void log(LogLevel level, const char* fmt, ...) = 0;
|
||||
virtual void log(LogLevel level, const char *fmt, ...) = 0;
|
||||
|
||||
/**
|
||||
* @brief 记录日志(字符串)
|
||||
*/
|
||||
virtual void log(LogLevel level, const std::string& msg) = 0;
|
||||
virtual void log(LogLevel level, const std::string &msg) = 0;
|
||||
|
||||
/**
|
||||
* @brief Trace级别日志
|
||||
*/
|
||||
virtual void trace(const char* fmt, ...) = 0;
|
||||
virtual void trace(const char *fmt, ...) = 0;
|
||||
|
||||
/**
|
||||
* @brief Debug级别日志
|
||||
*/
|
||||
virtual void debug(const char* fmt, ...) = 0;
|
||||
virtual void debug(const char *fmt, ...) = 0;
|
||||
|
||||
/**
|
||||
* @brief Info级别日志
|
||||
*/
|
||||
virtual void info(const char* fmt, ...) = 0;
|
||||
virtual void info(const char *fmt, ...) = 0;
|
||||
|
||||
/**
|
||||
* @brief Warn级别日志
|
||||
*/
|
||||
virtual void warn(const char* fmt, ...) = 0;
|
||||
virtual void warn(const char *fmt, ...) = 0;
|
||||
|
||||
/**
|
||||
* @brief Error级别日志
|
||||
*/
|
||||
virtual void error(const char* fmt, ...) = 0;
|
||||
virtual void error(const char *fmt, ...) = 0;
|
||||
|
||||
/**
|
||||
* @brief Fatal级别日志
|
||||
*/
|
||||
virtual void fatal(const char* fmt, ...) = 0;
|
||||
virtual void fatal(const char *fmt, ...) = 0;
|
||||
|
||||
ServiceInfo getServiceInfo() const override {
|
||||
ServiceInfo info;
|
||||
|
|
@ -108,19 +107,19 @@ public:
|
|||
LogLevel getLevel() const override;
|
||||
bool isEnabled(LogLevel level) const override;
|
||||
|
||||
void log(LogLevel level, const char* fmt, ...) override;
|
||||
void log(LogLevel level, const std::string& msg) override;
|
||||
void log(LogLevel level, const char *fmt, ...) override;
|
||||
void log(LogLevel level, const std::string &msg) override;
|
||||
|
||||
void trace(const char* fmt, ...) override;
|
||||
void debug(const char* fmt, ...) override;
|
||||
void info(const char* fmt, ...) override;
|
||||
void warn(const char* fmt, ...) override;
|
||||
void error(const char* fmt, ...) override;
|
||||
void fatal(const char* fmt, ...) override;
|
||||
void trace(const char *fmt, ...) override;
|
||||
void debug(const char *fmt, ...) override;
|
||||
void info(const char *fmt, ...) override;
|
||||
void warn(const char *fmt, ...) override;
|
||||
void error(const char *fmt, ...) override;
|
||||
void fatal(const char *fmt, ...) override;
|
||||
|
||||
private:
|
||||
void output(LogLevel level, const char* msg);
|
||||
const char* getLevelString(LogLevel level);
|
||||
void output(LogLevel level, const char *msg);
|
||||
const char *getLevelString(LogLevel level);
|
||||
|
||||
LogLevel level_;
|
||||
class Impl;
|
||||
|
|
@ -135,12 +134,11 @@ private:
|
|||
// 格式化辅助函数 - 将参数转换为字符串
|
||||
namespace extra2d {
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
std::string to_string(T&& value) {
|
||||
template <typename T> std::string to_string(T &&value) {
|
||||
using Decayed = std::decay_t<T>;
|
||||
if constexpr (std::is_same_v<Decayed, std::string>) {
|
||||
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)";
|
||||
} else if constexpr (std::is_arithmetic_v<Decayed>) {
|
||||
if constexpr (std::is_same_v<Decayed, bool>) {
|
||||
|
|
@ -153,15 +151,14 @@ namespace detail {
|
|||
} else {
|
||||
return "<?>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void format_impl(std::string& result, const char* fmt) {
|
||||
result += fmt;
|
||||
}
|
||||
inline void format_impl(std::string &result, const char *fmt) { result += fmt; }
|
||||
|
||||
template<typename T, typename... Args>
|
||||
void format_impl(std::string& result, const char* fmt, T&& value, Args&&... args) {
|
||||
const char* p = fmt;
|
||||
template <typename T, typename... Args>
|
||||
void format_impl(std::string &result, const char *fmt, T &&value,
|
||||
Args &&...args) {
|
||||
const char *p = fmt;
|
||||
while (*p) {
|
||||
if (*p == '{' && *(p + 1) == '}') {
|
||||
result += to_string(std::forward<T>(value));
|
||||
|
|
@ -174,11 +171,11 @@ namespace detail {
|
|||
result += " ";
|
||||
result += to_string(std::forward<T>(value));
|
||||
format_impl(result, p, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template<typename... Args>
|
||||
std::string format_str(const char* fmt, Args&&... args) {
|
||||
template <typename... Args>
|
||||
std::string format_str(const char *fmt, Args &&...args) {
|
||||
if constexpr (sizeof...(args) == 0) {
|
||||
return std::string(fmt);
|
||||
} else {
|
||||
|
|
@ -187,35 +184,30 @@ std::string format_str(const char* fmt, Args&&... args) {
|
|||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace extra2d
|
||||
|
||||
// 便捷宏 - 自动获取日志服务
|
||||
#define E2D_LOG(level, ...) \
|
||||
do { \
|
||||
if (auto logService = ::extra2d::ServiceLocator::instance().tryGetService<::extra2d::ILogger>()) { \
|
||||
if (auto logService = ::extra2d::ServiceLocator::instance() \
|
||||
.tryGetService<::extra2d::ILogger>()) { \
|
||||
if (logService->isEnabled(level)) { \
|
||||
logService->log(level, ::extra2d::format_str(__VA_ARGS__)); \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
} while (0)
|
||||
|
||||
#define E2D_LOG_TRACE(...) \
|
||||
E2D_LOG(::extra2d::LogLevel::Trace, __VA_ARGS__)
|
||||
#define E2D_LOG_TRACE(...) E2D_LOG(::extra2d::LogLevel::Trace, __VA_ARGS__)
|
||||
|
||||
#define E2D_LOG_DEBUG(...) \
|
||||
E2D_LOG(::extra2d::LogLevel::Debug, __VA_ARGS__)
|
||||
#define E2D_LOG_DEBUG(...) E2D_LOG(::extra2d::LogLevel::Debug, __VA_ARGS__)
|
||||
|
||||
#define E2D_LOG_INFO(...) \
|
||||
E2D_LOG(::extra2d::LogLevel::Info, __VA_ARGS__)
|
||||
#define E2D_LOG_INFO(...) E2D_LOG(::extra2d::LogLevel::Info, __VA_ARGS__)
|
||||
|
||||
#define E2D_LOG_WARN(...) \
|
||||
E2D_LOG(::extra2d::LogLevel::Warn, __VA_ARGS__)
|
||||
#define E2D_LOG_WARN(...) E2D_LOG(::extra2d::LogLevel::Warn, __VA_ARGS__)
|
||||
|
||||
#define E2D_LOG_ERROR(...) \
|
||||
E2D_LOG(::extra2d::LogLevel::Error, __VA_ARGS__)
|
||||
#define E2D_LOG_ERROR(...) E2D_LOG(::extra2d::LogLevel::Error, __VA_ARGS__)
|
||||
|
||||
#define E2D_LOG_FATAL(...) \
|
||||
E2D_LOG(::extra2d::LogLevel::Fatal, __VA_ARGS__)
|
||||
#define E2D_LOG_FATAL(...) E2D_LOG(::extra2d::LogLevel::Fatal, __VA_ARGS__)
|
||||
|
||||
// 简写宏
|
||||
#define E2D_INFO(...) E2D_LOG_INFO(__VA_ARGS__)
|
||||
|
|
@ -224,9 +216,9 @@ std::string format_str(const char* fmt, Args&&... args) {
|
|||
#define E2D_FATAL(...) E2D_LOG_FATAL(__VA_ARGS__)
|
||||
|
||||
#ifdef E2D_DEBUG
|
||||
#define E2D_DEBUG_LOG(...) E2D_LOG_DEBUG(__VA_ARGS__)
|
||||
#define E2D_TRACE(...) E2D_LOG_TRACE(__VA_ARGS__)
|
||||
#define E2D_DEBUG_LOG(...) E2D_LOG_DEBUG(__VA_ARGS__)
|
||||
#define E2D_TRACE(...) E2D_LOG_TRACE(__VA_ARGS__)
|
||||
#else
|
||||
#define E2D_DEBUG_LOG(...)
|
||||
#define E2D_TRACE(...)
|
||||
#define E2D_DEBUG_LOG(...)
|
||||
#define E2D_TRACE(...)
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
@ -1,13 +1,12 @@
|
|||
#include <extra2d/core/registry.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <algorithm>
|
||||
#include <queue>
|
||||
#include <unordered_set>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
Registry& Registry::instance() {
|
||||
Registry &Registry::instance() {
|
||||
static Registry instance;
|
||||
return instance;
|
||||
}
|
||||
|
|
@ -15,15 +14,19 @@ Registry& Registry::instance() {
|
|||
bool Registry::init() {
|
||||
auto sorted = topologicalSort();
|
||||
|
||||
std::cout << "[Registry] Initializing " << sorted.size() << " modules..." << std::endl;
|
||||
std::cout << "[Registry] Initializing " << sorted.size() << " modules..."
|
||||
<< std::endl;
|
||||
|
||||
for (auto* module : sorted) {
|
||||
std::cout << "[Registry] Initializing module: " << module->name() << std::endl;
|
||||
for (auto *module : sorted) {
|
||||
std::cout << "[Registry] Initializing module: " << module->name()
|
||||
<< std::endl;
|
||||
if (!module->init()) {
|
||||
std::cerr << "[Registry] Failed to initialize module: " << module->name() << std::endl;
|
||||
std::cerr << "[Registry] Failed to initialize module: " << module->name()
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
std::cout << "[Registry] Module " << module->name() << " initialized successfully" << std::endl;
|
||||
std::cout << "[Registry] Module " << module->name()
|
||||
<< " initialized successfully" << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "[Registry] All modules initialized" << std::endl;
|
||||
|
|
@ -44,19 +47,19 @@ void Registry::clear() {
|
|||
modules_.clear();
|
||||
}
|
||||
|
||||
std::vector<Module*> Registry::topologicalSort() {
|
||||
std::vector<Module*> result;
|
||||
std::unordered_map<Module*, int> inDegree;
|
||||
std::unordered_map<Module*, std::vector<Module*>> adj;
|
||||
std::vector<Module *> Registry::topologicalSort() {
|
||||
std::vector<Module *> result;
|
||||
std::unordered_map<Module *, int> inDegree;
|
||||
std::unordered_map<Module *, std::vector<Module *>> adj;
|
||||
|
||||
// 构建图
|
||||
for (auto& [typeIdx, module] : modules_) {
|
||||
for (auto &[typeIdx, module] : modules_) {
|
||||
inDegree[module.get()] = 0;
|
||||
}
|
||||
|
||||
for (auto& [typeIdx, module] : modules_) {
|
||||
for (auto& depType : module->deps()) {
|
||||
Module* dep = get(depType);
|
||||
for (auto &[typeIdx, module] : modules_) {
|
||||
for (auto &depType : module->deps()) {
|
||||
Module *dep = get(depType);
|
||||
if (dep) {
|
||||
adj[dep].push_back(module.get());
|
||||
inDegree[module.get()]++;
|
||||
|
|
@ -65,12 +68,10 @@ std::vector<Module*> Registry::topologicalSort() {
|
|||
}
|
||||
|
||||
// 优先级队列(优先级小的先处理)
|
||||
auto cmp = [](Module* a, Module* b) {
|
||||
return a->priority() > b->priority();
|
||||
};
|
||||
std::priority_queue<Module*, std::vector<Module*>, decltype(cmp)> pq(cmp);
|
||||
auto cmp = [](Module *a, Module *b) { return a->priority() > b->priority(); };
|
||||
std::priority_queue<Module *, std::vector<Module *>, decltype(cmp)> pq(cmp);
|
||||
|
||||
for (auto& [mod, degree] : inDegree) {
|
||||
for (auto &[mod, degree] : inDegree) {
|
||||
if (degree == 0) {
|
||||
pq.push(mod);
|
||||
}
|
||||
|
|
@ -78,11 +79,11 @@ std::vector<Module*> Registry::topologicalSort() {
|
|||
|
||||
// 拓扑排序
|
||||
while (!pq.empty()) {
|
||||
Module* curr = pq.top();
|
||||
Module *curr = pq.top();
|
||||
pq.pop();
|
||||
result.push_back(curr);
|
||||
|
||||
for (Module* next : adj[curr]) {
|
||||
for (Module *next : adj[curr]) {
|
||||
inDegree[next]--;
|
||||
if (inDegree[next] == 0) {
|
||||
pq.push(next);
|
||||
|
|
|
|||
|
|
@ -1,23 +1,26 @@
|
|||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/backends/backend_factory.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
namespace extra2d {
|
||||
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;
|
||||
return reg;
|
||||
}
|
||||
|
||||
void BackendFactory::reg(const std::string& name, BackendFn backend,
|
||||
const std::vector<std::string>& windowBackends) {
|
||||
void BackendFactory::reg(const std::string &name, BackendFn backend,
|
||||
const std::vector<std::string> &windowBackends) {
|
||||
registry()[name] = {backend, windowBackends};
|
||||
E2D_LOG_DEBUG("Registered graphics backend: {} (window backends: {})",
|
||||
name, windowBackends.size());
|
||||
E2D_LOG_DEBUG("Registered graphics backend: {} (window backends: {})", name,
|
||||
windowBackends.size());
|
||||
}
|
||||
|
||||
UniquePtr<RenderBackend> BackendFactory::createBackend(const std::string& name) {
|
||||
auto& reg = registry();
|
||||
UniquePtr<RenderBackend>
|
||||
BackendFactory::createBackend(const std::string &name) {
|
||||
auto ® = registry();
|
||||
auto it = reg.find(name);
|
||||
if (it != reg.end() && it->second.createFn) {
|
||||
E2D_LOG_INFO("Creating graphics backend: {}", name);
|
||||
|
|
@ -36,10 +39,12 @@ UniquePtr<RenderBackend> BackendFactory::createDefaultBackend() {
|
|||
return createBackend(recommended);
|
||||
}
|
||||
|
||||
UniquePtr<RenderBackend> BackendFactory::createBackendForWindow(const std::string& windowBackend) {
|
||||
UniquePtr<RenderBackend>
|
||||
BackendFactory::createBackendForWindow(const std::string &windowBackend) {
|
||||
std::string recommended = getRecommendedBackendForWindow(windowBackend);
|
||||
if (recommended.empty()) {
|
||||
E2D_LOG_ERROR("No compatible graphics backend for window backend: {}", windowBackend);
|
||||
E2D_LOG_ERROR("No compatible graphics backend for window backend: {}",
|
||||
windowBackend);
|
||||
return nullptr;
|
||||
}
|
||||
return createBackend(recommended);
|
||||
|
|
@ -47,24 +52,23 @@ UniquePtr<RenderBackend> BackendFactory::createBackendForWindow(const std::strin
|
|||
|
||||
std::vector<std::string> BackendFactory::backends() {
|
||||
std::vector<std::string> result;
|
||||
for (const auto& pair : registry()) {
|
||||
for (const auto &pair : registry()) {
|
||||
result.push_back(pair.first);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool BackendFactory::has(const std::string& name) {
|
||||
bool BackendFactory::has(const std::string &name) {
|
||||
return registry().find(name) != registry().end();
|
||||
}
|
||||
|
||||
std::string BackendFactory::getRecommendedBackend() {
|
||||
auto& reg = registry();
|
||||
auto ® = registry();
|
||||
|
||||
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()) {
|
||||
return name;
|
||||
}
|
||||
|
|
@ -78,43 +82,45 @@ std::string BackendFactory::getRecommendedBackend() {
|
|||
return "";
|
||||
}
|
||||
|
||||
std::string BackendFactory::getRecommendedBackendForWindow(const std::string& windowBackend) {
|
||||
auto& reg = registry();
|
||||
std::string BackendFactory::getRecommendedBackendForWindow(
|
||||
const std::string &windowBackend) {
|
||||
auto ® = registry();
|
||||
|
||||
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);
|
||||
if (it != reg.end() && isCompatible(name, windowBackend)) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& pair : reg) {
|
||||
for (const auto &pair : reg) {
|
||||
if (isCompatible(pair.first, windowBackend)) {
|
||||
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 "";
|
||||
}
|
||||
|
||||
bool BackendFactory::isCompatible(const std::string& graphicsBackend, const std::string& windowBackend) {
|
||||
auto& reg = registry();
|
||||
bool BackendFactory::isCompatible(const std::string &graphicsBackend,
|
||||
const std::string &windowBackend) {
|
||||
auto ® = registry();
|
||||
auto it = reg.find(graphicsBackend);
|
||||
if (it == reg.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& windowBackends = it->second.windowBackends;
|
||||
const auto &windowBackends = it->second.windowBackends;
|
||||
if (windowBackends.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto& wb : windowBackends) {
|
||||
for (const auto &wb : windowBackends) {
|
||||
if (wb == windowBackend) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -123,8 +129,9 @@ bool BackendFactory::isCompatible(const std::string& graphicsBackend, const std:
|
|||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> BackendFactory::getSupportedWindowBackends(const std::string& graphicsBackend) {
|
||||
auto& reg = registry();
|
||||
std::vector<std::string>
|
||||
BackendFactory::getSupportedWindowBackends(const std::string &graphicsBackend) {
|
||||
auto ® = registry();
|
||||
auto it = reg.find(graphicsBackend);
|
||||
if (it != reg.end()) {
|
||||
return it->second.windowBackends;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
#include <cstring>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/backends/opengl/gl_buffer.h>
|
||||
#include <extra2d/graphics/memory/vram_manager.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <cstring>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
@ -11,11 +13,9 @@ namespace extra2d {
|
|||
|
||||
GLBuffer::GLBuffer() = default;
|
||||
|
||||
GLBuffer::~GLBuffer() {
|
||||
shutdown();
|
||||
}
|
||||
GLBuffer::~GLBuffer() { shutdown(); }
|
||||
|
||||
bool GLBuffer::init(const BufferDesc& desc) {
|
||||
bool GLBuffer::init(const BufferDesc &desc) {
|
||||
if (bufferID_ != 0) {
|
||||
shutdown();
|
||||
}
|
||||
|
|
@ -35,14 +35,16 @@ bool GLBuffer::init(const BufferDesc& desc) {
|
|||
|
||||
// 绑定并分配缓冲区
|
||||
glBindBuffer(target_, bufferID_);
|
||||
glBufferData(target_, static_cast<GLsizeiptr>(size_), desc.initialData, glUsage_);
|
||||
glBufferData(target_, static_cast<GLsizeiptr>(size_), desc.initialData,
|
||||
glUsage_);
|
||||
glBindBuffer(target_, 0);
|
||||
|
||||
// 追踪显存使用
|
||||
VRAMMgr::get().allocBuffer(size_);
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -69,11 +71,9 @@ void GLBuffer::bind() {
|
|||
}
|
||||
}
|
||||
|
||||
void GLBuffer::unbind() {
|
||||
glBindBuffer(target_, 0);
|
||||
}
|
||||
void GLBuffer::unbind() { glBindBuffer(target_, 0); }
|
||||
|
||||
void GLBuffer::setData(const void* data, size_t size) {
|
||||
void GLBuffer::setData(const void *data, size_t size) {
|
||||
if (bufferID_ == 0) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -92,23 +92,25 @@ void GLBuffer::setData(const void* data, size_t size) {
|
|||
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) {
|
||||
return;
|
||||
}
|
||||
|
||||
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_);
|
||||
return;
|
||||
}
|
||||
|
||||
bind();
|
||||
glBufferSubData(target_, static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(size), data);
|
||||
glBufferSubData(target_, static_cast<GLintptr>(offset),
|
||||
static_cast<GLsizeiptr>(size), data);
|
||||
unbind();
|
||||
}
|
||||
|
||||
void* GLBuffer::map() {
|
||||
void *GLBuffer::map() {
|
||||
if (bufferID_ == 0 || mapped_) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -121,7 +123,8 @@ void* GLBuffer::map() {
|
|||
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_) {
|
||||
mapped_ = true;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/backends/opengl/gl_context.h>
|
||||
#include <extra2d/graphics/memory/gpu_context.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
@ -10,7 +9,7 @@ namespace extra2d {
|
|||
// GLContext 实现
|
||||
// ============================================================================
|
||||
|
||||
GLContext& GLContext::get() {
|
||||
GLContext &GLContext::get() {
|
||||
static GLContext instance;
|
||||
return instance;
|
||||
}
|
||||
|
|
@ -57,26 +56,28 @@ void GLContext::shutdown() {
|
|||
}
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
bool GLContext::hasExtension(const std::string& extension) const {
|
||||
bool GLContext::hasExtension(const std::string &extension) const {
|
||||
GLint numExtensions = 0;
|
||||
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
|
||||
|
||||
for (GLint i = 0; i < numExtensions; ++i) {
|
||||
const char* ext = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i));
|
||||
const char *ext =
|
||||
reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i));
|
||||
if (ext && extension == ext) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -138,7 +139,8 @@ bool GLContext::hasShader() const {
|
|||
}
|
||||
|
||||
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) {
|
||||
version_ = GLVersion{0, 0, false};
|
||||
return;
|
||||
|
|
@ -150,7 +152,8 @@ void GLContext::parseVersion() {
|
|||
if (version.find("OpenGL ES") != std::string::npos) {
|
||||
version_.es = true;
|
||||
// 解析 ES 版本号,格式如 "OpenGL ES 3.0"
|
||||
std::sscanf(version.c_str(), "OpenGL ES %d.%d", &version_.major, &version_.minor);
|
||||
std::sscanf(version.c_str(), "OpenGL ES %d.%d", &version_.major,
|
||||
&version_.minor);
|
||||
} else {
|
||||
version_.es = false;
|
||||
// 解析桌面版本号,格式如 "3.3.0 NVIDIA"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/backends/opengl/gl_font_atlas.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/backends/opengl/gl_framebuffer.h>
|
||||
#include <extra2d/graphics/backends/opengl/gl_texture.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
@ -10,11 +12,9 @@ namespace extra2d {
|
|||
|
||||
GLFramebuffer::GLFramebuffer() = default;
|
||||
|
||||
GLFramebuffer::~GLFramebuffer() {
|
||||
shutdown();
|
||||
}
|
||||
GLFramebuffer::~GLFramebuffer() { shutdown(); }
|
||||
|
||||
bool GLFramebuffer::init(const FramebufferDesc& desc) {
|
||||
bool GLFramebuffer::init(const FramebufferDesc &desc) {
|
||||
if (fboID_ != 0) {
|
||||
shutdown();
|
||||
}
|
||||
|
|
@ -51,7 +51,7 @@ void GLFramebuffer::shutdown() {
|
|||
}
|
||||
|
||||
// 清理纹理引用
|
||||
for (auto& tex : colorTextures_) {
|
||||
for (auto &tex : colorTextures_) {
|
||||
tex.reset();
|
||||
}
|
||||
depthTexture_.reset();
|
||||
|
|
@ -66,19 +66,19 @@ void GLFramebuffer::bind() {
|
|||
}
|
||||
}
|
||||
|
||||
void GLFramebuffer::unbind() {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
void GLFramebuffer::unbind() { glBindFramebuffer(GL_FRAMEBUFFER, 0); }
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bind();
|
||||
|
||||
// 获取 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),
|
||||
GL_TEXTURE_2D, texID, 0);
|
||||
|
|
@ -96,10 +96,11 @@ void GLFramebuffer::attachDepthTexture(Ptr<Texture> texture) {
|
|||
bind();
|
||||
|
||||
// 获取 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,
|
||||
GL_TEXTURE_2D, texID, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
|
||||
texID, 0);
|
||||
|
||||
depthTexture_ = texture;
|
||||
hasDepth_ = true;
|
||||
|
|
@ -116,7 +117,8 @@ void GLFramebuffer::attachDepthStencilTexture(Ptr<Texture> texture) {
|
|||
bind();
|
||||
|
||||
// 获取 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,
|
||||
GL_TEXTURE_2D, texID, 0);
|
||||
|
|
@ -147,12 +149,10 @@ Ptr<Texture> GLFramebuffer::getColorTexture(int attachment) const {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
Ptr<Texture> GLFramebuffer::getDepthTexture() const {
|
||||
return depthTexture_;
|
||||
}
|
||||
Ptr<Texture> GLFramebuffer::getDepthTexture() const { return depthTexture_; }
|
||||
|
||||
void GLFramebuffer::clear(const Color& color, bool clearColor,
|
||||
bool clearDepth, bool clearStencil) {
|
||||
void GLFramebuffer::clear(const Color &color, bool clearColor, bool clearDepth,
|
||||
bool clearStencil) {
|
||||
if (fboID_ == 0) {
|
||||
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,
|
||||
std::vector<uint8_t>& outData) {
|
||||
std::vector<uint8_t> &outData) {
|
||||
if (fboID_ == 0 || width <= 0 || height <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -237,17 +237,21 @@ bool GLFramebuffer::checkStatus() {
|
|||
E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_UNDEFINED");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||
E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
|
||||
E2D_LOG_ERROR(
|
||||
"Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||
E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
|
||||
E2D_LOG_ERROR(
|
||||
"Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
|
||||
break;
|
||||
#ifndef GL_ES_VERSION_2_0
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
|
||||
E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER");
|
||||
E2D_LOG_ERROR(
|
||||
"Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
|
||||
E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER");
|
||||
E2D_LOG_ERROR(
|
||||
"Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER");
|
||||
break;
|
||||
#endif
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/backends/opengl/gl_pipeline.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
@ -9,11 +11,9 @@ namespace extra2d {
|
|||
|
||||
GLPipeline::GLPipeline() = default;
|
||||
|
||||
GLPipeline::~GLPipeline() {
|
||||
shutdown();
|
||||
}
|
||||
GLPipeline::~GLPipeline() { shutdown(); }
|
||||
|
||||
bool GLPipeline::init(const PipelineDesc& desc) {
|
||||
bool GLPipeline::init(const PipelineDesc &desc) {
|
||||
if (initialized_) {
|
||||
shutdown();
|
||||
}
|
||||
|
|
@ -27,15 +27,14 @@ bool GLPipeline::init(const PipelineDesc& desc) {
|
|||
|
||||
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_));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLPipeline::shutdown() {
|
||||
initialized_ = false;
|
||||
}
|
||||
void GLPipeline::shutdown() { initialized_ = false; }
|
||||
|
||||
void GLPipeline::bind() {
|
||||
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_;
|
||||
y = viewportY_;
|
||||
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) {
|
||||
case BlendMode::None:
|
||||
srcFactor = GL_ONE;
|
||||
|
|
@ -198,24 +198,37 @@ void GLPipeline::getBlendFactors(BlendMode mode, GLenum& srcFactor, GLenum& dstF
|
|||
|
||||
GLenum GLPipeline::convertDepthFunc(DepthFunc func) {
|
||||
switch (func) {
|
||||
case DepthFunc::Never: return GL_NEVER;
|
||||
case DepthFunc::Less: return GL_LESS;
|
||||
case DepthFunc::Equal: return GL_EQUAL;
|
||||
case DepthFunc::LessEqual: return GL_LEQUAL;
|
||||
case DepthFunc::Greater: return GL_GREATER;
|
||||
case DepthFunc::NotEqual: return GL_NOTEQUAL;
|
||||
case DepthFunc::GreaterEqual: return GL_GEQUAL;
|
||||
case DepthFunc::Always: return GL_ALWAYS;
|
||||
default: return GL_LESS;
|
||||
case DepthFunc::Never:
|
||||
return GL_NEVER;
|
||||
case DepthFunc::Less:
|
||||
return GL_LESS;
|
||||
case DepthFunc::Equal:
|
||||
return GL_EQUAL;
|
||||
case DepthFunc::LessEqual:
|
||||
return GL_LEQUAL;
|
||||
case DepthFunc::Greater:
|
||||
return GL_GREATER;
|
||||
case DepthFunc::NotEqual:
|
||||
return GL_NOTEQUAL;
|
||||
case DepthFunc::GreaterEqual:
|
||||
return GL_GEQUAL;
|
||||
case DepthFunc::Always:
|
||||
return GL_ALWAYS;
|
||||
default:
|
||||
return GL_LESS;
|
||||
}
|
||||
}
|
||||
|
||||
GLenum GLPipeline::convertCullMode(CullMode mode) {
|
||||
switch (mode) {
|
||||
case CullMode::Front: return GL_FRONT;
|
||||
case CullMode::Back: return GL_BACK;
|
||||
case CullMode::Both: return GL_FRONT_AND_BACK;
|
||||
default: return GL_BACK;
|
||||
case CullMode::Front:
|
||||
return GL_FRONT;
|
||||
case CullMode::Back:
|
||||
return GL_BACK;
|
||||
case CullMode::Both:
|
||||
return GL_FRONT_AND_BACK;
|
||||
default:
|
||||
return GL_BACK;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/backends/opengl/gl_context.h>
|
||||
#include <extra2d/graphics/backends/opengl/gl_font_atlas.h>
|
||||
#include <extra2d/graphics/backends/opengl/gl_framebuffer.h>
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
#include <extra2d/graphics/memory/vram_manager.h>
|
||||
#include <extra2d/graphics/shader/shader_manager.h>
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
|
@ -23,8 +23,8 @@ static constexpr size_t SHAPE_VBO_SIZE = 1024 * sizeof(float);
|
|||
* @brief 构造函数,初始化OpenGL渲染器成员变量
|
||||
*/
|
||||
GLRenderer::GLRenderer()
|
||||
: window_(nullptr), shapeVao_(0), lineVao_(0),
|
||||
vsync_(true), shapeVertexCount_(0), currentShapeMode_(GL_TRIANGLES),
|
||||
: window_(nullptr), shapeVao_(0), lineVao_(0), vsync_(true),
|
||||
shapeVertexCount_(0), currentShapeMode_(GL_TRIANGLES),
|
||||
lineVertexCount_(0), currentLineWidth_(1.0f) {
|
||||
resetStats();
|
||||
for (auto &v : shapeVertexCache_) {
|
||||
|
|
@ -48,7 +48,8 @@ GLRenderer::~GLRenderer() { shutdown(); }
|
|||
bool GLRenderer::init(IWindow *window) {
|
||||
window_ = window;
|
||||
|
||||
// 初始化 OpenGL 上下文(Switch 平台已通过 SDL2 + EGL 初始化,GLContext 会处理兼容性)
|
||||
// 初始化 OpenGL 上下文(Switch 平台已通过 SDL2 + EGL 初始化,GLContext
|
||||
// 会处理兼容性)
|
||||
if (!GLContext::get().init()) {
|
||||
E2D_LOG_ERROR("Failed to initialize OpenGL context");
|
||||
return false;
|
||||
|
|
@ -937,7 +938,7 @@ void GLRenderer::flushLineBatch() {
|
|||
* @param desc 帧缓冲描述
|
||||
* @return 创建的帧缓冲智能指针
|
||||
*/
|
||||
Ptr<GLFramebuffer> GLRenderer::createFramebuffer(const FramebufferDesc& desc) {
|
||||
Ptr<GLFramebuffer> GLRenderer::createFramebuffer(const FramebufferDesc &desc) {
|
||||
auto framebuffer = makePtr<GLFramebuffer>();
|
||||
if (!framebuffer->init(desc)) {
|
||||
E2D_LOG_ERROR("Failed to create framebuffer");
|
||||
|
|
@ -950,7 +951,7 @@ Ptr<GLFramebuffer> GLRenderer::createFramebuffer(const FramebufferDesc& desc) {
|
|||
* @brief 绑定帧缓冲(作为渲染目标)
|
||||
* @param framebuffer 帧缓冲对象指针,传入 nullptr 则绑定默认帧缓冲
|
||||
*/
|
||||
void GLRenderer::bindFramebuffer(GLFramebuffer* framebuffer) {
|
||||
void GLRenderer::bindFramebuffer(GLFramebuffer *framebuffer) {
|
||||
// 先刷新所有待处理的渲染批次
|
||||
flush();
|
||||
flushShapeBatch();
|
||||
|
|
@ -972,9 +973,7 @@ void GLRenderer::bindFramebuffer(GLFramebuffer* framebuffer) {
|
|||
/**
|
||||
* @brief 解绑帧缓冲(恢复到默认帧缓冲)
|
||||
*/
|
||||
void GLRenderer::unbindFramebuffer() {
|
||||
bindFramebuffer(nullptr);
|
||||
}
|
||||
void GLRenderer::unbindFramebuffer() { bindFramebuffer(nullptr); }
|
||||
|
||||
/**
|
||||
* @brief 获取默认帧缓冲
|
||||
|
|
@ -996,7 +995,7 @@ Ptr<GLFramebuffer> GLRenderer::getDefaultFramebuffer() const {
|
|||
* @param clearDepth 是否清除深度缓冲
|
||||
* @param clearStencil 是否清除模板缓冲
|
||||
*/
|
||||
void GLRenderer::clearFramebuffer(const Color& color, bool clearColor,
|
||||
void GLRenderer::clearFramebuffer(const Color &color, bool clearColor,
|
||||
bool clearDepth, bool clearStencil) {
|
||||
GLbitfield mask = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/backends/opengl/gl_shader.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 构造函数,初始化着色器程序ID为0
|
||||
*/
|
||||
GLShader::GLShader() : programID_(0) {
|
||||
}
|
||||
GLShader::GLShader() : programID_(0) {}
|
||||
|
||||
/**
|
||||
* @brief 析构函数,删除OpenGL着色器程序
|
||||
|
|
@ -22,23 +23,19 @@ GLShader::~GLShader() {
|
|||
/**
|
||||
* @brief 绑定Shader程序
|
||||
*/
|
||||
void GLShader::bind() const {
|
||||
glUseProgram(programID_);
|
||||
}
|
||||
void GLShader::bind() const { glUseProgram(programID_); }
|
||||
|
||||
/**
|
||||
* @brief 解绑Shader程序
|
||||
*/
|
||||
void GLShader::unbind() const {
|
||||
glUseProgram(0);
|
||||
}
|
||||
void GLShader::unbind() const { glUseProgram(0); }
|
||||
|
||||
/**
|
||||
* @brief 设置布尔类型uniform变量
|
||||
* @param name uniform变量名
|
||||
* @param value 布尔值
|
||||
*/
|
||||
void GLShader::setBool(const std::string& name, bool value) {
|
||||
void GLShader::setBool(const std::string &name, bool value) {
|
||||
glUniform1i(getUniformLocation(name), value ? 1 : 0);
|
||||
}
|
||||
|
||||
|
|
@ -47,7 +44,7 @@ void GLShader::setBool(const std::string& name, bool value) {
|
|||
* @param name uniform变量名
|
||||
* @param value 整数值
|
||||
*/
|
||||
void GLShader::setInt(const std::string& name, int value) {
|
||||
void GLShader::setInt(const std::string &name, int value) {
|
||||
glUniform1i(getUniformLocation(name), value);
|
||||
}
|
||||
|
||||
|
|
@ -56,7 +53,7 @@ void GLShader::setInt(const std::string& name, int value) {
|
|||
* @param name uniform变量名
|
||||
* @param value 浮点值
|
||||
*/
|
||||
void GLShader::setFloat(const std::string& name, float value) {
|
||||
void GLShader::setFloat(const std::string &name, float value) {
|
||||
glUniform1f(getUniformLocation(name), value);
|
||||
}
|
||||
|
||||
|
|
@ -65,7 +62,7 @@ void GLShader::setFloat(const std::string& name, float value) {
|
|||
* @param name uniform变量名
|
||||
* @param value 二维向量值
|
||||
*/
|
||||
void GLShader::setVec2(const std::string& name, const glm::vec2& value) {
|
||||
void GLShader::setVec2(const std::string &name, const glm::vec2 &value) {
|
||||
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 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]);
|
||||
}
|
||||
|
||||
|
|
@ -83,7 +80,7 @@ void GLShader::setVec3(const std::string& name, const glm::vec3& value) {
|
|||
* @param name uniform变量名
|
||||
* @param value 四维向量值
|
||||
*/
|
||||
void GLShader::setVec4(const std::string& name, const glm::vec4& value) {
|
||||
void GLShader::setVec4(const std::string &name, const glm::vec4 &value) {
|
||||
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 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]);
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +98,7 @@ void GLShader::setMat4(const std::string& name, const glm::mat4& value) {
|
|||
* @param name uniform变量名
|
||||
* @param color 颜色值
|
||||
*/
|
||||
void GLShader::setColor(const std::string& name, const Color& color) {
|
||||
void GLShader::setColor(const std::string &name, const Color &color) {
|
||||
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 片段着色器源码
|
||||
* @return 编译成功返回true,失败返回false
|
||||
*/
|
||||
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);
|
||||
if (vertexShader == 0) {
|
||||
return false;
|
||||
|
|
@ -154,7 +152,7 @@ bool GLShader::compileFromSource(const char* vertexSource, const char* fragmentS
|
|||
* @param binary 二进制数据
|
||||
* @return 创建成功返回true,失败返回false
|
||||
*/
|
||||
bool GLShader::compileFromBinary(const std::vector<uint8_t>& binary) {
|
||||
bool GLShader::compileFromBinary(const std::vector<uint8_t> &binary) {
|
||||
if (binary.empty()) {
|
||||
E2D_LOG_ERROR("Binary data is empty");
|
||||
return false;
|
||||
|
|
@ -175,9 +173,11 @@ bool GLShader::compileFromBinary(const std::vector<uint8_t>& binary) {
|
|||
programID_ = glCreateProgram();
|
||||
|
||||
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;
|
||||
glGetProgramiv(programID_, GL_LINK_STATUS, &success);
|
||||
|
|
@ -198,7 +198,7 @@ bool GLShader::compileFromBinary(const std::vector<uint8_t>& binary) {
|
|||
* @param outBinary 输出的二进制数据
|
||||
* @return 成功返回true,失败返回false
|
||||
*/
|
||||
bool GLShader::getBinary(std::vector<uint8_t>& outBinary) {
|
||||
bool GLShader::getBinary(std::vector<uint8_t> &outBinary) {
|
||||
if (programID_ == 0) {
|
||||
E2D_LOG_WARN("Cannot get binary: shader program is 0");
|
||||
return false;
|
||||
|
|
@ -218,7 +218,8 @@ bool GLShader::getBinary(std::vector<uint8_t>& outBinary) {
|
|||
|
||||
GLenum binaryFormat = 0;
|
||||
GLsizei actualLength = 0;
|
||||
glGetProgramBinary(programID_, binaryLength, &actualLength, &binaryFormat, outBinary.data());
|
||||
glGetProgramBinary(programID_, binaryLength, &actualLength, &binaryFormat,
|
||||
outBinary.data());
|
||||
|
||||
GLenum err = glGetError();
|
||||
if (err != GL_NO_ERROR) {
|
||||
|
|
@ -237,7 +238,8 @@ bool GLShader::getBinary(std::vector<uint8_t>& outBinary) {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
@ -247,7 +249,7 @@ bool GLShader::getBinary(std::vector<uint8_t>& outBinary) {
|
|||
* @param source 着色器源码
|
||||
* @return 着色器ID,失败返回0
|
||||
*/
|
||||
GLuint GLShader::compileShader(GLenum type, const char* source) {
|
||||
GLuint GLShader::compileShader(GLenum type, const char *source) {
|
||||
GLuint shader = glCreateShader(type);
|
||||
glShaderSource(shader, 1, &source, nullptr);
|
||||
glCompileShader(shader);
|
||||
|
|
@ -270,7 +272,7 @@ GLuint GLShader::compileShader(GLenum type, const char* source) {
|
|||
* @param name uniform变量名
|
||||
* @return uniform位置
|
||||
*/
|
||||
GLint GLShader::getUniformLocation(const std::string& name) {
|
||||
GLint GLShader::getUniformLocation(const std::string &name) {
|
||||
auto it = uniformCache_.find(name);
|
||||
if (it != uniformCache_.end()) {
|
||||
return it->second;
|
||||
|
|
@ -292,10 +294,9 @@ GLint GLShader::getUniformLocation(const std::string& name) {
|
|||
* @param fragSource 片段着色器源码
|
||||
* @return 创建的Shader实例
|
||||
*/
|
||||
Ptr<IShader> GLShaderFactory::createFromSource(
|
||||
const std::string& name,
|
||||
const std::string& vertSource,
|
||||
const std::string& fragSource) {
|
||||
Ptr<IShader> GLShaderFactory::createFromSource(const std::string &name,
|
||||
const std::string &vertSource,
|
||||
const std::string &fragSource) {
|
||||
|
||||
auto shader = std::make_shared<GLShader>();
|
||||
shader->setName(name);
|
||||
|
|
@ -314,9 +315,9 @@ Ptr<IShader> GLShaderFactory::createFromSource(
|
|||
* @param binary 编译后的二进制数据
|
||||
* @return 创建的Shader实例
|
||||
*/
|
||||
Ptr<IShader> GLShaderFactory::createFromBinary(
|
||||
const std::string& name,
|
||||
const std::vector<uint8_t>& binary) {
|
||||
Ptr<IShader>
|
||||
GLShaderFactory::createFromBinary(const std::string &name,
|
||||
const std::vector<uint8_t> &binary) {
|
||||
|
||||
auto shader = std::make_shared<GLShader>();
|
||||
shader->setName(name);
|
||||
|
|
@ -335,14 +336,15 @@ Ptr<IShader> GLShaderFactory::createFromBinary(
|
|||
* @param outBinary 输出的二进制数据
|
||||
* @return 成功返回true,失败返回false
|
||||
*/
|
||||
bool GLShaderFactory::getShaderBinary(const IShader& shader, std::vector<uint8_t>& outBinary) {
|
||||
const GLShader* glShader = dynamic_cast<const GLShader*>(&shader);
|
||||
bool GLShaderFactory::getShaderBinary(const IShader &shader,
|
||||
std::vector<uint8_t> &outBinary) {
|
||||
const GLShader *glShader = dynamic_cast<const GLShader *>(&shader);
|
||||
if (!glShader) {
|
||||
E2D_LOG_ERROR("Shader is not a GLShader instance");
|
||||
return false;
|
||||
}
|
||||
|
||||
return const_cast<GLShader*>(glShader)->getBinary(outBinary);
|
||||
return const_cast<GLShader *>(glShader)->getBinary(outBinary);
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
|
|||
|
|
@ -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_texture.h>
|
||||
#include <extra2d/graphics/shader/shader_manager.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
@ -36,15 +38,18 @@ bool GLSpriteBatch::init() {
|
|||
|
||||
// 设置顶点属性
|
||||
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)));
|
||||
|
||||
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)));
|
||||
|
||||
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)));
|
||||
|
||||
// 初始化 EBO(索引缓冲区)- 静态使用模式
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@
|
|||
#include <extra2d/graphics/memory/vram_manager.h>
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <cstring>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
#include <fstream>
|
||||
#include <stb/stb_image.h>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
|
|
|
|||
|
|
@ -1,23 +1,21 @@
|
|||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/backends/vulkan/vk_renderer.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
VulkanRenderer::VulkanRenderer() = default;
|
||||
|
||||
VulkanRenderer::~VulkanRenderer() {
|
||||
shutdown();
|
||||
}
|
||||
VulkanRenderer::~VulkanRenderer() { shutdown(); }
|
||||
|
||||
bool VulkanRenderer::init(IWindow* window) {
|
||||
bool VulkanRenderer::init(IWindow *window) {
|
||||
E2D_LOG_WARN("Vulkan renderer is not fully implemented yet");
|
||||
initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanRenderer::shutdown() {
|
||||
initialized_ = false;
|
||||
}
|
||||
void VulkanRenderer::shutdown() { initialized_ = false; }
|
||||
|
||||
void VulkanRenderer::beginFrame(const Color &clearColor) {
|
||||
// TODO: 实现Vulkan帧开始
|
||||
|
|
@ -55,7 +53,9 @@ glm::mat4 VulkanRenderer::getCurrentTransform() const {
|
|||
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纹理创建
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -70,8 +70,8 @@ void VulkanRenderer::beginSpriteBatch() {
|
|||
}
|
||||
|
||||
void VulkanRenderer::drawSprite(const Texture &texture, const Rect &destRect,
|
||||
const Rect &srcRect, const Color &tint, float rotation,
|
||||
const Vec2 &anchor) {
|
||||
const Rect &srcRect, const Color &tint,
|
||||
float rotation, const Vec2 &anchor) {
|
||||
// TODO: 实现精灵绘制
|
||||
}
|
||||
|
||||
|
|
@ -84,12 +84,13 @@ void VulkanRenderer::endSpriteBatch() {
|
|||
// TODO: 实现精灵批处理结束
|
||||
}
|
||||
|
||||
void VulkanRenderer::drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
|
||||
float width) {
|
||||
void VulkanRenderer::drawLine(const Vec2 &start, const Vec2 &end,
|
||||
const Color &color, float width) {
|
||||
// TODO: 实现线条绘制
|
||||
}
|
||||
|
||||
void VulkanRenderer::drawRect(const Rect &rect, const Color &color, float width) {
|
||||
void VulkanRenderer::drawRect(const Rect &rect, const Color &color,
|
||||
float width) {
|
||||
// TODO: 实现矩形边框绘制
|
||||
}
|
||||
|
||||
|
|
@ -97,28 +98,29 @@ void VulkanRenderer::fillRect(const Rect &rect, const Color &color) {
|
|||
// TODO: 实现矩形填充
|
||||
}
|
||||
|
||||
void VulkanRenderer::drawCircle(const Vec2 ¢er, float radius, const Color &color,
|
||||
int segments, float width) {
|
||||
void VulkanRenderer::drawCircle(const Vec2 ¢er, float radius,
|
||||
const Color &color, int segments, float width) {
|
||||
// TODO: 实现圆形边框绘制
|
||||
}
|
||||
|
||||
void VulkanRenderer::fillCircle(const Vec2 ¢er, float radius, const Color &color,
|
||||
int segments) {
|
||||
void VulkanRenderer::fillCircle(const Vec2 ¢er, float radius,
|
||||
const Color &color, int segments) {
|
||||
// TODO: 实现圆形填充
|
||||
}
|
||||
|
||||
void VulkanRenderer::drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
|
||||
const Color &color, float width) {
|
||||
void VulkanRenderer::drawTriangle(const Vec2 &p1, const Vec2 &p2,
|
||||
const Vec2 &p3, const Color &color,
|
||||
float width) {
|
||||
// TODO: 实现三角形边框绘制
|
||||
}
|
||||
|
||||
void VulkanRenderer::fillTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
|
||||
const Color &color) {
|
||||
void VulkanRenderer::fillTriangle(const Vec2 &p1, const Vec2 &p2,
|
||||
const Vec2 &p3, const Color &color) {
|
||||
// TODO: 实现三角形填充
|
||||
}
|
||||
|
||||
void VulkanRenderer::drawPolygon(const std::vector<Vec2> &points, const Color &color,
|
||||
float width) {
|
||||
void VulkanRenderer::drawPolygon(const std::vector<Vec2> &points,
|
||||
const Color &color, float width) {
|
||||
// TODO: 实现多边形边框绘制
|
||||
}
|
||||
|
||||
|
|
@ -127,8 +129,8 @@ void VulkanRenderer::fillPolygon(const std::vector<Vec2> &points,
|
|||
// TODO: 实现多边形填充
|
||||
}
|
||||
|
||||
Ptr<FontAtlas> VulkanRenderer::createFontAtlas(const std::string &filepath, int fontSize,
|
||||
bool useSDF) {
|
||||
Ptr<FontAtlas> VulkanRenderer::createFontAtlas(const std::string &filepath,
|
||||
int fontSize, bool useSDF) {
|
||||
// TODO: 实现字体图集创建
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -138,13 +140,11 @@ void VulkanRenderer::drawText(const FontAtlas &font, const std::string &text,
|
|||
// TODO: 实现文本绘制
|
||||
}
|
||||
|
||||
void VulkanRenderer::drawText(const FontAtlas &font, const std::string &text, float x,
|
||||
float y, const Color &color) {
|
||||
void VulkanRenderer::drawText(const FontAtlas &font, const std::string &text,
|
||||
float x, float y, const Color &color) {
|
||||
// TODO: 实现文本绘制
|
||||
}
|
||||
|
||||
void VulkanRenderer::resetStats() {
|
||||
stats_ = Stats{};
|
||||
}
|
||||
void VulkanRenderer::resetStats() { stats_ = Stats{}; }
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/batch/sprite_batch.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
|
@ -47,9 +49,7 @@ float TrigLookup::cosRad(float rad) const {
|
|||
// ============================================================================
|
||||
// SpriteBatch 实现
|
||||
// ============================================================================
|
||||
SpriteBatch::SpriteBatch()
|
||||
: spriteCount_(0)
|
||||
, vpDirty_(true) {
|
||||
SpriteBatch::SpriteBatch() : spriteCount_(0), vpDirty_(true) {
|
||||
// 预分配顶点缓冲区
|
||||
vertices_.reserve(MAX_VERTICES);
|
||||
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;
|
||||
vpDirty_ = true;
|
||||
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) {
|
||||
// 缓冲区已满,需要刷新
|
||||
flush();
|
||||
|
|
@ -93,7 +93,7 @@ void SpriteBatch::draw(const SpriteData& sprite) {
|
|||
spriteCount_++;
|
||||
}
|
||||
|
||||
void SpriteBatch::drawBatch(const std::vector<SpriteData>& sprites) {
|
||||
void SpriteBatch::drawBatch(const std::vector<SpriteData> &sprites) {
|
||||
size_t index = 0;
|
||||
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();
|
||||
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) {
|
||||
vertices_.resize(vertexOffset + VERTICES_PER_SPRITE);
|
||||
|
|
@ -148,8 +149,8 @@ void SpriteBatch::generateVertices(const SpriteData& sprite, size_t vertexOffset
|
|||
// 四个角的本地坐标
|
||||
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) // 左上
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
#include <extra2d/graphics/core/render_module.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/app/application.h>
|
||||
#include <extra2d/core/registry.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/utils/logger.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
#include <filesystem>
|
||||
|
||||
namespace extra2d {
|
||||
|
|
@ -19,9 +19,9 @@ void initOpenGLBackend();
|
|||
#ifdef E2D_BACKEND_VULKAN
|
||||
void initVulkanBackend();
|
||||
#endif
|
||||
}
|
||||
} // namespace graphics
|
||||
|
||||
RenderModule::RenderModule(std::function<void(RenderCfg&)> configFn) {
|
||||
RenderModule::RenderModule(std::function<void(RenderCfg &)> configFn) {
|
||||
configFn(cfg_);
|
||||
}
|
||||
|
||||
|
|
@ -41,9 +41,10 @@ static std::string getExecutableDir() {
|
|||
}
|
||||
|
||||
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()) {
|
||||
E2D_LOG_ERROR("WindowModule not available");
|
||||
return false;
|
||||
|
|
@ -62,18 +63,22 @@ bool RenderModule::init() {
|
|||
std::string shaderDir = getExecutableDir() + "shaders/";
|
||||
std::string cacheDir = getExecutableDir() + "shader_cache/";
|
||||
if (!ShaderManager::getInstance().init(shaderDir, cacheDir, factory)) {
|
||||
E2D_LOG_WARN("Failed to initialize ShaderManager with dir: {}", shaderDir);
|
||||
E2D_LOG_WARN("Failed to initialize ShaderManager with dir: {}",
|
||||
shaderDir);
|
||||
}
|
||||
}
|
||||
|
||||
std::string windowBackend = winMod->getWindowBackend();
|
||||
|
||||
if (cfg_.backend.empty()) {
|
||||
E2D_LOG_INFO("No graphics backend specified, auto-selecting for window backend: {}", windowBackend);
|
||||
E2D_LOG_INFO(
|
||||
"No graphics backend specified, auto-selecting for window backend: {}",
|
||||
windowBackend);
|
||||
renderer_ = graphics::BackendFactory::createBackendForWindow(windowBackend);
|
||||
} else {
|
||||
if (!graphics::BackendFactory::isCompatible(cfg_.backend, windowBackend)) {
|
||||
E2D_LOG_WARN("Graphics backend '{}' is not compatible with window backend '{}'",
|
||||
E2D_LOG_WARN(
|
||||
"Graphics backend '{}' is not compatible with window backend '{}'",
|
||||
cfg_.backend, windowBackend);
|
||||
}
|
||||
renderer_ = graphics::BackendFactory::createBackend(cfg_.backend);
|
||||
|
|
@ -96,7 +101,8 @@ bool RenderModule::init() {
|
|||
}
|
||||
|
||||
void RenderModule::shutdown() {
|
||||
if (!initialized_) return;
|
||||
if (!initialized_)
|
||||
return;
|
||||
|
||||
if (renderer_) {
|
||||
renderer_->shutdown();
|
||||
|
|
|
|||
|
|
@ -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/core/render_target.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
#include <glad/glad.h>
|
||||
|
||||
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include <stb/stb_image_write.h>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#include <algorithm>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/memory/vram_manager.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
#include <extra2d/graphics/shader/shader_cache.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <chrono>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/shader/shader_cache.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
|
@ -13,7 +15,7 @@ namespace fs = std::filesystem;
|
|||
* @brief 获取单例实例
|
||||
* @return 缓存管理器实例引用
|
||||
*/
|
||||
ShaderCache& ShaderCache::getInstance() {
|
||||
ShaderCache &ShaderCache::getInstance() {
|
||||
static ShaderCache instance;
|
||||
return instance;
|
||||
}
|
||||
|
|
@ -23,7 +25,7 @@ ShaderCache& ShaderCache::getInstance() {
|
|||
* @param cacheDir 缓存目录路径
|
||||
* @return 初始化成功返回true,失败返回false
|
||||
*/
|
||||
bool ShaderCache::init(const std::string& cacheDir) {
|
||||
bool ShaderCache::init(const std::string &cacheDir) {
|
||||
cacheDir_ = cacheDir;
|
||||
|
||||
if (!ensureCacheDirectory()) {
|
||||
|
|
@ -60,7 +62,8 @@ void ShaderCache::shutdown() {
|
|||
* @param sourceHash 源码哈希值
|
||||
* @return 缓存有效返回true,否则返回false
|
||||
*/
|
||||
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);
|
||||
if (it == cacheMap_.end()) {
|
||||
return false;
|
||||
|
|
@ -74,7 +77,7 @@ bool ShaderCache::hasValidCache(const std::string& name, const std::string& sour
|
|||
* @param name Shader名称
|
||||
* @return 缓存条目指针,不存在返回nullptr
|
||||
*/
|
||||
Ptr<ShaderCacheEntry> ShaderCache::loadCache(const std::string& name) {
|
||||
Ptr<ShaderCacheEntry> ShaderCache::loadCache(const std::string &name) {
|
||||
auto it = cacheMap_.find(name);
|
||||
if (it == cacheMap_.end()) {
|
||||
return nullptr;
|
||||
|
|
@ -95,7 +98,7 @@ Ptr<ShaderCacheEntry> ShaderCache::loadCache(const std::string& name) {
|
|||
file.seekg(0, std::ios::beg);
|
||||
|
||||
entry->binary.resize(fileSize);
|
||||
file.read(reinterpret_cast<char*>(entry->binary.data()), fileSize);
|
||||
file.read(reinterpret_cast<char *>(entry->binary.data()), fileSize);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
|
@ -105,19 +108,21 @@ Ptr<ShaderCacheEntry> ShaderCache::loadCache(const std::string& name) {
|
|||
* @param entry 缓存条目
|
||||
* @return 保存成功返回true,失败返回false
|
||||
*/
|
||||
bool ShaderCache::saveCache(const ShaderCacheEntry& entry) {
|
||||
bool ShaderCache::saveCache(const ShaderCacheEntry &entry) {
|
||||
if (!initialized_) {
|
||||
E2D_LOG_WARN("ShaderCache not initialized, cannot save cache");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entry.binary.empty()) {
|
||||
E2D_LOG_WARN("Shader binary is empty, skipping cache save for: {}", entry.name);
|
||||
E2D_LOG_WARN("Shader binary is empty, skipping cache save for: {}",
|
||||
entry.name);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string cachePath = getCachePath(entry.name);
|
||||
E2D_LOG_DEBUG("Saving shader cache to: {} ({} bytes)", cachePath, entry.binary.size());
|
||||
E2D_LOG_DEBUG("Saving shader cache to: {} ({} bytes)", cachePath,
|
||||
entry.binary.size());
|
||||
|
||||
std::ofstream file(cachePath, std::ios::binary);
|
||||
if (!file.is_open()) {
|
||||
|
|
@ -125,13 +130,15 @@ bool ShaderCache::saveCache(const ShaderCacheEntry& entry) {
|
|||
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();
|
||||
|
||||
cacheMap_[entry.name] = entry;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -139,7 +146,7 @@ bool ShaderCache::saveCache(const ShaderCacheEntry& entry) {
|
|||
* @brief 使缓存失效
|
||||
* @param name Shader名称
|
||||
*/
|
||||
void ShaderCache::invalidate(const std::string& name) {
|
||||
void ShaderCache::invalidate(const std::string &name) {
|
||||
auto it = cacheMap_.find(name);
|
||||
if (it == cacheMap_.end()) {
|
||||
return;
|
||||
|
|
@ -158,7 +165,7 @@ void ShaderCache::invalidate(const std::string& name) {
|
|||
* @brief 清除所有缓存
|
||||
*/
|
||||
void ShaderCache::clearAll() {
|
||||
for (const auto& pair : cacheMap_) {
|
||||
for (const auto &pair : cacheMap_) {
|
||||
std::string cachePath = getCachePath(pair.first);
|
||||
fs::remove(cachePath);
|
||||
}
|
||||
|
|
@ -175,8 +182,8 @@ void ShaderCache::clearAll() {
|
|||
* @param fragSource 片段着色器源码
|
||||
* @return 哈希值字符串
|
||||
*/
|
||||
std::string ShaderCache::computeHash(const std::string& vertSource,
|
||||
const std::string& fragSource) {
|
||||
std::string ShaderCache::computeHash(const std::string &vertSource,
|
||||
const std::string &fragSource) {
|
||||
std::string combined = vertSource + fragSource;
|
||||
|
||||
uint32_t hash = 5381;
|
||||
|
|
@ -248,7 +255,7 @@ bool ShaderCache::saveCacheIndex() {
|
|||
file << "# Extra2D Shader Cache Index\n";
|
||||
file << "# Format: name=hash\n";
|
||||
|
||||
for (const auto& pair : cacheMap_) {
|
||||
for (const auto &pair : cacheMap_) {
|
||||
file << pair.first << "=" << pair.second.sourceHash << "\n";
|
||||
}
|
||||
|
||||
|
|
@ -260,7 +267,7 @@ bool ShaderCache::saveCacheIndex() {
|
|||
* @param name Shader名称
|
||||
* @return 缓存文件完整路径
|
||||
*/
|
||||
std::string ShaderCache::getCachePath(const std::string& name) const {
|
||||
std::string ShaderCache::getCachePath(const std::string &name) const {
|
||||
return cacheDir_ + "/" + name + ".cache";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
#include <extra2d/graphics/shader/shader_hot_reloader.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <chrono>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/shader/shader_hot_reloader.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
#include <filesystem>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
|
@ -11,7 +13,7 @@ namespace fs = std::filesystem;
|
|||
* @brief 获取单例实例
|
||||
* @return 热重载管理器实例引用
|
||||
*/
|
||||
ShaderHotReloader& ShaderHotReloader::getInstance() {
|
||||
ShaderHotReloader &ShaderHotReloader::getInstance() {
|
||||
static ShaderHotReloader instance;
|
||||
return instance;
|
||||
}
|
||||
|
|
@ -61,8 +63,8 @@ void ShaderHotReloader::shutdown() {
|
|||
* @param filePaths 要监视的文件列表
|
||||
* @param callback 文件变化时的回调
|
||||
*/
|
||||
void ShaderHotReloader::watch(const std::string& shaderName,
|
||||
const std::vector<std::string>& filePaths,
|
||||
void ShaderHotReloader::watch(const std::string &shaderName,
|
||||
const std::vector<std::string> &filePaths,
|
||||
FileChangeCallback callback) {
|
||||
if (!initialized_) {
|
||||
E2D_LOG_WARN("Hot reloader not initialized");
|
||||
|
|
@ -73,7 +75,7 @@ void ShaderHotReloader::watch(const std::string& shaderName,
|
|||
info.filePaths = filePaths;
|
||||
info.callback = callback;
|
||||
|
||||
for (const auto& path : filePaths) {
|
||||
for (const auto &path : filePaths) {
|
||||
info.modifiedTimes[path] = getFileModifiedTime(path);
|
||||
}
|
||||
|
||||
|
|
@ -85,7 +87,7 @@ void ShaderHotReloader::watch(const std::string& shaderName,
|
|||
* @brief 取消监视
|
||||
* @param shaderName Shader名称
|
||||
*/
|
||||
void ShaderHotReloader::unwatch(const std::string& shaderName) {
|
||||
void ShaderHotReloader::unwatch(const std::string &shaderName) {
|
||||
auto it = watchMap_.find(shaderName);
|
||||
if (it != watchMap_.end()) {
|
||||
watchMap_.erase(it);
|
||||
|
|
@ -120,14 +122,15 @@ void ShaderHotReloader::pollChanges() {
|
|||
auto now = static_cast<uint64_t>(
|
||||
std::chrono::system_clock::now().time_since_epoch().count());
|
||||
|
||||
for (auto& pair : watchMap_) {
|
||||
WatchInfo& info = pair.second;
|
||||
for (auto &pair : watchMap_) {
|
||||
WatchInfo &info = pair.second;
|
||||
|
||||
for (const auto& filePath : info.filePaths) {
|
||||
for (const auto &filePath : info.filePaths) {
|
||||
uint64_t currentModTime = getFileModifiedTime(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;
|
||||
|
||||
FileChangeEvent event;
|
||||
|
|
@ -150,11 +153,12 @@ void ShaderHotReloader::pollChanges() {
|
|||
* @param filepath 文件路径
|
||||
* @return 修改时间戳
|
||||
*/
|
||||
uint64_t ShaderHotReloader::getFileModifiedTime(const std::string& filepath) {
|
||||
uint64_t ShaderHotReloader::getFileModifiedTime(const std::string &filepath) {
|
||||
try {
|
||||
auto ftime = fs::last_write_time(filepath);
|
||||
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());
|
||||
} catch (...) {
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include <extra2d/graphics/shader/shader_loader.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#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 <fstream>
|
||||
#include <sstream>
|
||||
|
|
@ -13,8 +13,7 @@ namespace fs = std::filesystem;
|
|||
/**
|
||||
* @brief 构造函数,初始化Shader加载器
|
||||
*/
|
||||
ShaderLoader::ShaderLoader() {
|
||||
}
|
||||
ShaderLoader::ShaderLoader() {}
|
||||
|
||||
/**
|
||||
* @brief 从分离文件加载Shader (.vert + .frag)
|
||||
|
|
@ -23,10 +22,10 @@ ShaderLoader::ShaderLoader() {
|
|||
* @param fragPath 片段着色器文件路径
|
||||
* @return 加载结果
|
||||
*/
|
||||
ShaderLoadResult ShaderLoader::loadFromSeparateFiles(
|
||||
const std::string& name,
|
||||
const std::string& vertPath,
|
||||
const std::string& fragPath) {
|
||||
ShaderLoadResult
|
||||
ShaderLoader::loadFromSeparateFiles(const std::string &name,
|
||||
const std::string &vertPath,
|
||||
const std::string &fragPath) {
|
||||
|
||||
ShaderLoadResult result;
|
||||
|
||||
|
|
@ -60,8 +59,10 @@ ShaderLoadResult ShaderLoader::loadFromSeparateFiles(
|
|||
fs::path vertDir = fs::path(vertPath).parent_path();
|
||||
fs::path fragDir = fs::path(fragPath).parent_path();
|
||||
|
||||
vertSource = processIncludes(vertSource, vertDir.string(), result.dependencies);
|
||||
fragSource = processIncludes(fragSource, fragDir.string(), result.dependencies);
|
||||
vertSource =
|
||||
processIncludes(vertSource, vertDir.string(), result.dependencies);
|
||||
fragSource =
|
||||
processIncludes(fragSource, fragDir.string(), result.dependencies);
|
||||
|
||||
result.vertSource = vertSource;
|
||||
result.fragSource = fragSource;
|
||||
|
|
@ -75,7 +76,7 @@ ShaderLoadResult ShaderLoader::loadFromSeparateFiles(
|
|||
* @param path 组合Shader文件路径
|
||||
* @return 加载结果
|
||||
*/
|
||||
ShaderLoadResult ShaderLoader::loadFromCombinedFile(const std::string& path) {
|
||||
ShaderLoadResult ShaderLoader::loadFromCombinedFile(const std::string &path) {
|
||||
ShaderLoadResult result;
|
||||
|
||||
if (!fileExists(path)) {
|
||||
|
|
@ -101,8 +102,10 @@ ShaderLoadResult ShaderLoader::loadFromCombinedFile(const std::string& path) {
|
|||
}
|
||||
|
||||
fs::path baseDir = fs::path(path).parent_path();
|
||||
vertSource = processIncludes(vertSource, baseDir.string(), result.dependencies);
|
||||
fragSource = processIncludes(fragSource, baseDir.string(), result.dependencies);
|
||||
vertSource =
|
||||
processIncludes(vertSource, baseDir.string(), result.dependencies);
|
||||
fragSource =
|
||||
processIncludes(fragSource, baseDir.string(), result.dependencies);
|
||||
|
||||
result.vertSource = vertSource;
|
||||
result.fragSource = fragSource;
|
||||
|
|
@ -117,9 +120,8 @@ ShaderLoadResult ShaderLoader::loadFromCombinedFile(const std::string& path) {
|
|||
* @param fragSource 片段着色器源码
|
||||
* @return 加载结果
|
||||
*/
|
||||
ShaderLoadResult ShaderLoader::loadFromSource(
|
||||
const std::string& vertSource,
|
||||
const std::string& fragSource) {
|
||||
ShaderLoadResult ShaderLoader::loadFromSource(const std::string &vertSource,
|
||||
const std::string &fragSource) {
|
||||
|
||||
ShaderLoadResult result;
|
||||
result.vertSource = vertSource;
|
||||
|
|
@ -135,10 +137,10 @@ ShaderLoadResult ShaderLoader::loadFromSource(
|
|||
* @param outDependencies 输出依赖列表
|
||||
* @return 处理后的源码
|
||||
*/
|
||||
std::string ShaderLoader::processIncludes(
|
||||
const std::string& source,
|
||||
const std::string& baseDir,
|
||||
std::vector<std::string>& outDependencies) {
|
||||
std::string
|
||||
ShaderLoader::processIncludes(const std::string &source,
|
||||
const std::string &baseDir,
|
||||
std::vector<std::string> &outDependencies) {
|
||||
|
||||
std::string result;
|
||||
std::istringstream stream(source);
|
||||
|
|
@ -151,7 +153,8 @@ std::string ShaderLoader::processIncludes(
|
|||
size_t endQuote = line.find('"', startQuote + 1);
|
||||
|
||||
if (startQuote != std::string::npos && endQuote != std::string::npos) {
|
||||
std::string includeName = line.substr(startQuote + 1, endQuote - startQuote - 1);
|
||||
std::string includeName =
|
||||
line.substr(startQuote + 1, endQuote - startQuote - 1);
|
||||
std::string includePath = findIncludeFile(includeName, baseDir);
|
||||
|
||||
if (!includePath.empty()) {
|
||||
|
|
@ -188,16 +191,16 @@ std::string ShaderLoader::processIncludes(
|
|||
* @param defines 预处理器定义列表
|
||||
* @return 处理后的源码
|
||||
*/
|
||||
std::string ShaderLoader::applyDefines(
|
||||
const std::string& source,
|
||||
const std::vector<std::string>& defines) {
|
||||
std::string
|
||||
ShaderLoader::applyDefines(const std::string &source,
|
||||
const std::vector<std::string> &defines) {
|
||||
|
||||
if (defines.empty()) {
|
||||
return source;
|
||||
}
|
||||
|
||||
std::string defineBlock;
|
||||
for (const auto& def : defines) {
|
||||
for (const auto &def : defines) {
|
||||
defineBlock += "#define " + def + "\n";
|
||||
}
|
||||
|
||||
|
|
@ -229,7 +232,7 @@ std::string ShaderLoader::applyDefines(
|
|||
* @param path Shader文件路径
|
||||
* @return 元数据
|
||||
*/
|
||||
ShaderMetadata ShaderLoader::getMetadata(const std::string& path) {
|
||||
ShaderMetadata ShaderLoader::getMetadata(const std::string &path) {
|
||||
ShaderMetadata metadata;
|
||||
|
||||
if (!fileExists(path)) {
|
||||
|
|
@ -249,8 +252,9 @@ ShaderMetadata ShaderLoader::getMetadata(const std::string& path) {
|
|||
* @brief 添加include搜索路径
|
||||
* @param path 搜索路径
|
||||
*/
|
||||
void ShaderLoader::addIncludePath(const std::string& path) {
|
||||
if (std::find(includePaths_.begin(), includePaths_.end(), path) == includePaths_.end()) {
|
||||
void ShaderLoader::addIncludePath(const std::string &path) {
|
||||
if (std::find(includePaths_.begin(), includePaths_.end(), path) ==
|
||||
includePaths_.end()) {
|
||||
includePaths_.push_back(path);
|
||||
}
|
||||
}
|
||||
|
|
@ -260,7 +264,7 @@ void ShaderLoader::addIncludePath(const std::string& path) {
|
|||
* @param filepath 文件路径
|
||||
* @return 文件内容字符串
|
||||
*/
|
||||
std::string ShaderLoader::readFile(const std::string& filepath) {
|
||||
std::string ShaderLoader::readFile(const std::string &filepath) {
|
||||
std::ifstream file(filepath, std::ios::binary);
|
||||
if (!file.is_open()) {
|
||||
return "";
|
||||
|
|
@ -276,7 +280,7 @@ std::string ShaderLoader::readFile(const std::string& filepath) {
|
|||
* @param filepath 文件路径
|
||||
* @return 修改时间戳
|
||||
*/
|
||||
uint64_t ShaderLoader::getFileModifiedTime(const std::string& filepath) {
|
||||
uint64_t ShaderLoader::getFileModifiedTime(const std::string &filepath) {
|
||||
#ifdef __SWITCH__
|
||||
(void)filepath;
|
||||
return 1;
|
||||
|
|
@ -284,7 +288,8 @@ uint64_t ShaderLoader::getFileModifiedTime(const std::string& filepath) {
|
|||
try {
|
||||
auto ftime = fs::last_write_time(filepath);
|
||||
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());
|
||||
} catch (...) {
|
||||
return 0;
|
||||
|
|
@ -297,7 +302,7 @@ uint64_t ShaderLoader::getFileModifiedTime(const std::string& filepath) {
|
|||
* @param filepath 文件路径
|
||||
* @return 存在返回true,否则返回false
|
||||
*/
|
||||
bool ShaderLoader::fileExists(const std::string& filepath) {
|
||||
bool ShaderLoader::fileExists(const std::string &filepath) {
|
||||
return fs::exists(filepath);
|
||||
}
|
||||
|
||||
|
|
@ -309,16 +314,10 @@ bool ShaderLoader::fileExists(const std::string& filepath) {
|
|||
* @param outMetadata 输出元数据
|
||||
* @return 解析成功返回true,失败返回false
|
||||
*/
|
||||
bool ShaderLoader::parseCombinedFile(const std::string& content,
|
||||
std::string& outVert,
|
||||
std::string& outFrag,
|
||||
ShaderMetadata& outMetadata) {
|
||||
enum class Section {
|
||||
None,
|
||||
Meta,
|
||||
Vertex,
|
||||
Fragment
|
||||
};
|
||||
bool ShaderLoader::parseCombinedFile(const std::string &content,
|
||||
std::string &outVert, std::string &outFrag,
|
||||
ShaderMetadata &outMetadata) {
|
||||
enum class Section { None, Meta, Vertex, Fragment };
|
||||
|
||||
Section currentSection = Section::None;
|
||||
std::string metaContent;
|
||||
|
|
@ -384,7 +383,8 @@ bool ShaderLoader::parseCombinedFile(const std::string& content,
|
|||
* @param outMetadata 输出元数据
|
||||
* @return 解析成功返回true,失败返回false
|
||||
*/
|
||||
bool ShaderLoader::parseMetadata(const std::string& jsonContent, ShaderMetadata& outMetadata) {
|
||||
bool ShaderLoader::parseMetadata(const std::string &jsonContent,
|
||||
ShaderMetadata &outMetadata) {
|
||||
std::string content = jsonContent;
|
||||
|
||||
size_t start = content.find('{');
|
||||
|
|
@ -395,7 +395,7 @@ bool ShaderLoader::parseMetadata(const std::string& jsonContent, ShaderMetadata&
|
|||
|
||||
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 + "\"";
|
||||
size_t keyPos = content.find(searchKey);
|
||||
if (keyPos == std::string::npos) {
|
||||
|
|
@ -430,7 +430,8 @@ bool ShaderLoader::parseMetadata(const std::string& jsonContent, ShaderMetadata&
|
|||
* @param baseDir 基础目录
|
||||
* @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 includePath = basePath / includeName;
|
||||
|
||||
|
|
@ -438,7 +439,7 @@ std::string ShaderLoader::findIncludeFile(const std::string& includeName, const
|
|||
return includePath.string();
|
||||
}
|
||||
|
||||
for (const auto& searchPath : includePaths_) {
|
||||
for (const auto &searchPath : includePaths_) {
|
||||
includePath = fs::path(searchPath) / includeName;
|
||||
if (fs::exists(includePath)) {
|
||||
return includePath.string();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/shader/shader_manager.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
|
|
@ -11,7 +13,7 @@ namespace extra2d {
|
|||
* @brief 获取单例实例
|
||||
* @return Shader管理器实例引用
|
||||
*/
|
||||
ShaderManager& ShaderManager::getInstance() {
|
||||
ShaderManager &ShaderManager::getInstance() {
|
||||
static ShaderManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
|
@ -23,7 +25,8 @@ ShaderManager& ShaderManager::getInstance() {
|
|||
* @param appName 应用名称(用于缓存目录)
|
||||
* @return 初始化成功返回true,失败返回false
|
||||
*/
|
||||
bool ShaderManager::init(Ptr<IShaderFactory> factory, const std::string& appName) {
|
||||
bool ShaderManager::init(Ptr<IShaderFactory> factory,
|
||||
const std::string &appName) {
|
||||
// 使用相对路径作为Shader目录
|
||||
std::string shaderDir = "shaders/";
|
||||
std::string cacheDir = "cache/shaders/";
|
||||
|
|
@ -48,8 +51,8 @@ bool ShaderManager::init(Ptr<IShaderFactory> factory, const std::string& appName
|
|||
* @param factory 渲染后端Shader工厂
|
||||
* @return 初始化成功返回true,失败返回false
|
||||
*/
|
||||
bool ShaderManager::init(const std::string& shaderDir,
|
||||
const std::string& cacheDir,
|
||||
bool ShaderManager::init(const std::string &shaderDir,
|
||||
const std::string &cacheDir,
|
||||
Ptr<IShaderFactory> factory) {
|
||||
if (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(" Shader directory: {}", shaderDir_);
|
||||
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;
|
||||
}
|
||||
|
|
@ -126,9 +130,9 @@ void ShaderManager::shutdown() {
|
|||
* @param fragPath 片段着色器文件路径
|
||||
* @return 加载的Shader实例
|
||||
*/
|
||||
Ptr<IShader> ShaderManager::loadFromFiles(const std::string& name,
|
||||
const std::string& vertPath,
|
||||
const std::string& fragPath) {
|
||||
Ptr<IShader> ShaderManager::loadFromFiles(const std::string &name,
|
||||
const std::string &vertPath,
|
||||
const std::string &fragPath) {
|
||||
if (!initialized_) {
|
||||
E2D_LOG_ERROR("ShaderManager not initialized");
|
||||
return nullptr;
|
||||
|
|
@ -139,18 +143,23 @@ Ptr<IShader> ShaderManager::loadFromFiles(const std::string& name,
|
|||
return it->second.shader;
|
||||
}
|
||||
|
||||
ShaderLoadResult result = loader_.loadFromSeparateFiles(name, vertPath, fragPath);
|
||||
ShaderLoadResult result =
|
||||
loader_.loadFromSeparateFiles(name, vertPath, fragPath);
|
||||
if (!result.success) {
|
||||
E2D_LOG_ERROR("Failed to load shader files: {} - {}", vertPath, fragPath);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string sourceHash = ShaderCache::computeHash(result.vertSource, result.fragSource);
|
||||
Ptr<IShader> shader = loadFromCache(name, sourceHash, result.vertSource, result.fragSource);
|
||||
std::string sourceHash =
|
||||
ShaderCache::computeHash(result.vertSource, result.fragSource);
|
||||
Ptr<IShader> shader =
|
||||
loadFromCache(name, sourceHash, result.vertSource, result.fragSource);
|
||||
|
||||
if (!shader) {
|
||||
E2D_LOG_DEBUG("No valid cache found, compiling shader from source: {}", name);
|
||||
shader = factory_->createFromSource(name, result.vertSource, result.fragSource);
|
||||
E2D_LOG_DEBUG("No valid cache found, compiling shader from source: {}",
|
||||
name);
|
||||
shader =
|
||||
factory_->createFromSource(name, result.vertSource, result.fragSource);
|
||||
if (!shader) {
|
||||
E2D_LOG_ERROR("Failed to create shader from source: {}", name);
|
||||
return nullptr;
|
||||
|
|
@ -175,7 +184,8 @@ Ptr<IShader> ShaderManager::loadFromFiles(const std::string& name,
|
|||
info.vertSource = result.vertSource;
|
||||
info.fragSource = result.fragSource;
|
||||
info.filePaths = {vertPath, fragPath};
|
||||
info.filePaths.insert(info.filePaths.end(), result.dependencies.begin(), result.dependencies.end());
|
||||
info.filePaths.insert(info.filePaths.end(), result.dependencies.begin(),
|
||||
result.dependencies.end());
|
||||
|
||||
info.metadata.name = name;
|
||||
info.metadata.vertPath = vertPath;
|
||||
|
|
@ -184,10 +194,11 @@ Ptr<IShader> ShaderManager::loadFromFiles(const std::string& name,
|
|||
shaders_[name] = std::move(info);
|
||||
|
||||
if (hotReloadEnabled_ && hotReloadSupported_) {
|
||||
auto callback = [this, name](const FileChangeEvent& event) {
|
||||
auto callback = [this, name](const FileChangeEvent &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);
|
||||
|
|
@ -199,7 +210,7 @@ Ptr<IShader> ShaderManager::loadFromFiles(const std::string& name,
|
|||
* @param path 组合Shader文件路径
|
||||
* @return 加载的Shader实例
|
||||
*/
|
||||
Ptr<IShader> ShaderManager::loadFromCombinedFile(const std::string& path) {
|
||||
Ptr<IShader> ShaderManager::loadFromCombinedFile(const std::string &path) {
|
||||
if (!initialized_) {
|
||||
E2D_LOG_ERROR("ShaderManager not initialized");
|
||||
return nullptr;
|
||||
|
|
@ -219,12 +230,16 @@ Ptr<IShader> ShaderManager::loadFromCombinedFile(const std::string& path) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
std::string sourceHash = ShaderCache::computeHash(result.vertSource, result.fragSource);
|
||||
Ptr<IShader> shader = loadFromCache(name, sourceHash, result.vertSource, result.fragSource);
|
||||
std::string sourceHash =
|
||||
ShaderCache::computeHash(result.vertSource, result.fragSource);
|
||||
Ptr<IShader> shader =
|
||||
loadFromCache(name, sourceHash, result.vertSource, result.fragSource);
|
||||
|
||||
if (!shader) {
|
||||
E2D_LOG_DEBUG("No valid cache found, compiling shader from source: {}", name);
|
||||
shader = factory_->createFromSource(name, result.vertSource, result.fragSource);
|
||||
E2D_LOG_DEBUG("No valid cache found, compiling shader from source: {}",
|
||||
name);
|
||||
shader =
|
||||
factory_->createFromSource(name, result.vertSource, result.fragSource);
|
||||
if (!shader) {
|
||||
E2D_LOG_ERROR("Failed to create shader from source: {}", name);
|
||||
return nullptr;
|
||||
|
|
@ -249,16 +264,18 @@ Ptr<IShader> ShaderManager::loadFromCombinedFile(const std::string& path) {
|
|||
info.vertSource = result.vertSource;
|
||||
info.fragSource = result.fragSource;
|
||||
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;
|
||||
|
||||
shaders_[name] = std::move(info);
|
||||
|
||||
if (hotReloadEnabled_ && hotReloadSupported_) {
|
||||
auto callback = [this, name](const FileChangeEvent& event) {
|
||||
auto callback = [this, name](const FileChangeEvent &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);
|
||||
|
|
@ -272,9 +289,9 @@ Ptr<IShader> ShaderManager::loadFromCombinedFile(const std::string& path) {
|
|||
* @param fragSource 片段着色器源码
|
||||
* @return 加载的Shader实例
|
||||
*/
|
||||
Ptr<IShader> ShaderManager::loadFromSource(const std::string& name,
|
||||
const std::string& vertSource,
|
||||
const std::string& fragSource) {
|
||||
Ptr<IShader> ShaderManager::loadFromSource(const std::string &name,
|
||||
const std::string &vertSource,
|
||||
const std::string &fragSource) {
|
||||
if (!initialized_) {
|
||||
E2D_LOG_ERROR("ShaderManager not initialized");
|
||||
return nullptr;
|
||||
|
|
@ -285,7 +302,8 @@ Ptr<IShader> ShaderManager::loadFromSource(const std::string& name,
|
|||
return it->second.shader;
|
||||
}
|
||||
|
||||
Ptr<IShader> shader = factory_->createFromSource(name, vertSource, fragSource);
|
||||
Ptr<IShader> shader =
|
||||
factory_->createFromSource(name, vertSource, fragSource);
|
||||
if (!shader) {
|
||||
E2D_LOG_ERROR("Failed to create shader from source: {}", name);
|
||||
return nullptr;
|
||||
|
|
@ -308,7 +326,7 @@ Ptr<IShader> ShaderManager::loadFromSource(const std::string& name,
|
|||
* @param name Shader名称
|
||||
* @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);
|
||||
if (it != shaders_.end()) {
|
||||
return it->second.shader;
|
||||
|
|
@ -321,7 +339,7 @@ Ptr<IShader> ShaderManager::get(const std::string& name) const {
|
|||
* @param name Shader名称
|
||||
* @return 存在返回true,否则返回false
|
||||
*/
|
||||
bool ShaderManager::has(const std::string& name) const {
|
||||
bool ShaderManager::has(const std::string &name) const {
|
||||
return shaders_.find(name) != shaders_.end();
|
||||
}
|
||||
|
||||
|
|
@ -329,7 +347,7 @@ bool ShaderManager::has(const std::string& name) const {
|
|||
* @brief 移除Shader
|
||||
* @param name Shader名称
|
||||
*/
|
||||
void ShaderManager::remove(const std::string& name) {
|
||||
void ShaderManager::remove(const std::string &name) {
|
||||
auto it = shaders_.find(name);
|
||||
if (it != shaders_.end()) {
|
||||
ShaderHotReloader::getInstance().unwatch(name);
|
||||
|
|
@ -343,7 +361,7 @@ void ShaderManager::remove(const std::string& name) {
|
|||
*/
|
||||
void ShaderManager::clear() {
|
||||
if (hotReloadSupported_) {
|
||||
for (const auto& pair : shaders_) {
|
||||
for (const auto &pair : shaders_) {
|
||||
ShaderHotReloader::getInstance().unwatch(pair.first);
|
||||
}
|
||||
}
|
||||
|
|
@ -356,7 +374,8 @@ void ShaderManager::clear() {
|
|||
* @param name Shader名称
|
||||
* @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);
|
||||
if (it != shaders_.end()) {
|
||||
it->second.reloadCallback = callback;
|
||||
|
|
@ -399,33 +418,36 @@ void ShaderManager::update() {
|
|||
* @param name Shader名称
|
||||
* @return 重载成功返回true,失败返回false
|
||||
*/
|
||||
bool ShaderManager::reload(const std::string& name) {
|
||||
bool ShaderManager::reload(const std::string &name) {
|
||||
auto it = shaders_.find(name);
|
||||
if (it == shaders_.end()) {
|
||||
E2D_LOG_WARN("Shader not found for reload: {}", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
ShaderInfo& info = it->second;
|
||||
ShaderInfo &info = it->second;
|
||||
|
||||
std::string vertSource = info.vertSource;
|
||||
std::string fragSource = info.fragSource;
|
||||
|
||||
if (!info.metadata.vertPath.empty() && !info.metadata.fragPath.empty()) {
|
||||
ShaderLoadResult result = loader_.loadFromSeparateFiles(name, info.metadata.vertPath, info.metadata.fragPath);
|
||||
ShaderLoadResult result = loader_.loadFromSeparateFiles(
|
||||
name, info.metadata.vertPath, info.metadata.fragPath);
|
||||
if (result.success) {
|
||||
vertSource = result.vertSource;
|
||||
fragSource = result.fragSource;
|
||||
}
|
||||
} else if (!info.metadata.combinedPath.empty()) {
|
||||
ShaderLoadResult result = loader_.loadFromCombinedFile(info.metadata.combinedPath);
|
||||
ShaderLoadResult result =
|
||||
loader_.loadFromCombinedFile(info.metadata.combinedPath);
|
||||
if (result.success) {
|
||||
vertSource = result.vertSource;
|
||||
fragSource = result.fragSource;
|
||||
}
|
||||
}
|
||||
|
||||
Ptr<IShader> newShader = factory_->createFromSource(name, vertSource, fragSource);
|
||||
Ptr<IShader> newShader =
|
||||
factory_->createFromSource(name, vertSource, fragSource);
|
||||
if (!newShader) {
|
||||
E2D_LOG_ERROR("Failed to reload shader: {}", name);
|
||||
return false;
|
||||
|
|
@ -448,7 +470,7 @@ bool ShaderManager::reload(const std::string& name) {
|
|||
* @param name 内置Shader名称
|
||||
* @return Shader实例
|
||||
*/
|
||||
Ptr<IShader> ShaderManager::getBuiltin(const std::string& name) {
|
||||
Ptr<IShader> ShaderManager::getBuiltin(const std::string &name) {
|
||||
Ptr<IShader> shader = get(name);
|
||||
if (shader) {
|
||||
return shader;
|
||||
|
|
@ -471,7 +493,8 @@ Ptr<IShader> ShaderManager::getBuiltin(const std::string& name) {
|
|||
* @param name 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_) {
|
||||
E2D_LOG_ERROR("ShaderManager not initialized");
|
||||
return nullptr;
|
||||
|
|
@ -500,9 +523,10 @@ Ptr<IShader> ShaderManager::loadFromMetadata(const std::string& jsonPath, const
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
auto& opengl = j["backends"]["opengl"];
|
||||
auto &opengl = j["backends"]["opengl"];
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -513,12 +537,13 @@ Ptr<IShader> ShaderManager::loadFromMetadata(const std::string& jsonPath, const
|
|||
std::string vertPath = shaderDir_ + vertRelativePath;
|
||||
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);
|
||||
|
||||
} catch (const nl::json::exception& e) {
|
||||
} catch (const nl::json::exception &e) {
|
||||
E2D_LOG_ERROR("Failed to parse shader metadata {}: {}", jsonPath, e.what());
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -536,15 +561,10 @@ bool ShaderManager::loadBuiltinShaders() {
|
|||
|
||||
bool allSuccess = true;
|
||||
|
||||
const char* builtinNames[] = {
|
||||
"sprite",
|
||||
"particle",
|
||||
"shape",
|
||||
"postprocess",
|
||||
"font"
|
||||
};
|
||||
const char *builtinNames[] = {"sprite", "particle", "shape", "postprocess",
|
||||
"font"};
|
||||
|
||||
for (const char* name : builtinNames) {
|
||||
for (const char *name : builtinNames) {
|
||||
// 首先尝试新的多后端JSON格式
|
||||
std::string jsonPath = shaderDir_ + "shared/builtin/" + name + ".json";
|
||||
std::string shaderName = std::string("builtin_") + name;
|
||||
|
|
@ -585,10 +605,10 @@ bool ShaderManager::loadBuiltinShaders() {
|
|||
* @param fragSource 片段着色器源码
|
||||
* @return Shader实例
|
||||
*/
|
||||
Ptr<IShader> ShaderManager::loadFromCache(const std::string& name,
|
||||
const std::string& sourceHash,
|
||||
const std::string& vertSource,
|
||||
const std::string& fragSource) {
|
||||
Ptr<IShader> ShaderManager::loadFromCache(const std::string &name,
|
||||
const std::string &sourceHash,
|
||||
const std::string &vertSource,
|
||||
const std::string &fragSource) {
|
||||
if (!ShaderCache::getInstance().isInitialized()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -615,7 +635,8 @@ Ptr<IShader> ShaderManager::loadFromCache(const std::string& name,
|
|||
* @param shaderName Shader名称
|
||||
* @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);
|
||||
reload(shaderName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/shader/shader_manager.h>
|
||||
#include <extra2d/graphics/shader/shader_preset.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/texture/texture_atlas.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
@ -46,8 +45,9 @@ TextureAtlasPage::~TextureAtlasPage() = default;
|
|||
*
|
||||
* 尝试将纹理添加到图集页面中,使用矩形打包算法找到合适位置
|
||||
*/
|
||||
bool TextureAtlasPage::tryAddTexture(const std::string& name, int texWidth, int texHeight,
|
||||
const uint8_t* pixels, Rect& outUvRect) {
|
||||
bool TextureAtlasPage::tryAddTexture(const std::string &name, int texWidth,
|
||||
int texHeight, const uint8_t *pixels,
|
||||
Rect &outUvRect) {
|
||||
if (isFull_) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -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) {
|
||||
// 无法放入,标记为满
|
||||
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;
|
||||
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;
|
||||
|
||||
// 计算 UV 坐标(考虑边距)
|
||||
|
|
@ -90,8 +92,8 @@ bool TextureAtlasPage::tryAddTexture(const std::string& name, int texWidth, int
|
|||
entries_[name] = std::move(entry);
|
||||
usedArea_ += paddedWidth * paddedHeight;
|
||||
|
||||
E2D_LOG_DEBUG("Added texture '{}' to atlas: {}x{} at ({}, {})",
|
||||
name, texWidth, texHeight, node->x, node->y);
|
||||
E2D_LOG_DEBUG("Added texture '{}' to atlas: {}x{} at ({}, {})", name,
|
||||
texWidth, texHeight, node->x, node->y);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -105,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) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 如果节点已被使用,尝试子节点
|
||||
if (node->used) {
|
||||
PackNode* result = insert(node->left.get(), width, height);
|
||||
PackNode *result = insert(node->left.get(), width, height);
|
||||
if (result != nullptr) {
|
||||
return result;
|
||||
}
|
||||
|
|
@ -136,12 +139,16 @@ TextureAtlasPage::PackNode* TextureAtlasPage::insert(PackNode* node, int width,
|
|||
|
||||
if (dw > dh) {
|
||||
// 水平分割
|
||||
node->left = 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);
|
||||
node->left =
|
||||
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 {
|
||||
// 垂直分割
|
||||
node->left = 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);
|
||||
node->left =
|
||||
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更新纹理的指定区域
|
||||
*/
|
||||
void TextureAtlasPage::writePixels(int x, int y, int w, int h, const uint8_t* pixels) {
|
||||
void TextureAtlasPage::writePixels(int x, int y, int w, int h,
|
||||
const uint8_t *pixels) {
|
||||
if (texture_ == nullptr || pixels == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -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()));
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texID);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
pixels);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
|
|
@ -177,7 +186,7 @@ void TextureAtlasPage::writePixels(int x, int y, int w, int h, const uint8_t* pi
|
|||
* @param name 纹理名称
|
||||
* @return 找到返回条目指针,未找到返回nullptr
|
||||
*/
|
||||
const AtlasEntry* TextureAtlasPage::getEntry(const std::string& name) const {
|
||||
const AtlasEntry *TextureAtlasPage::getEntry(const std::string &name) const {
|
||||
auto it = entries_.find(name);
|
||||
if (it != entries_.end()) {
|
||||
return &it->second;
|
||||
|
|
@ -205,11 +214,8 @@ float TextureAtlasPage::getUsageRatio() const {
|
|||
* 创建一个使用默认页面大小的纹理图集
|
||||
*/
|
||||
TextureAtlas::TextureAtlas()
|
||||
: pageSize_(TextureAtlasPage::DEFAULT_SIZE),
|
||||
sizeThreshold_(256),
|
||||
enabled_(true),
|
||||
initialized_(false) {
|
||||
}
|
||||
: pageSize_(TextureAtlasPage::DEFAULT_SIZE), sizeThreshold_(256),
|
||||
enabled_(true), initialized_(false) {}
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
|
|
@ -240,8 +246,8 @@ void TextureAtlas::init(int pageSize) {
|
|||
*
|
||||
* 尝试将纹理添加到现有页面,如空间不足则创建新页面
|
||||
*/
|
||||
bool TextureAtlas::addTexture(const std::string& name, int width, int height,
|
||||
const uint8_t* pixels) {
|
||||
bool TextureAtlas::addTexture(const std::string &name, int width, int height,
|
||||
const uint8_t *pixels) {
|
||||
if (!enabled_ || !initialized_) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -260,7 +266,7 @@ bool TextureAtlas::addTexture(const std::string& name, int width, int height,
|
|||
|
||||
// 尝试添加到现有页面
|
||||
Rect uvRect;
|
||||
for (auto& page : pages_) {
|
||||
for (auto &page : pages_) {
|
||||
if (page->tryAddTexture(name, width, height, pixels, uvRect)) {
|
||||
entryToPage_[name] = page.get();
|
||||
return true;
|
||||
|
|
@ -284,7 +290,7 @@ bool TextureAtlas::addTexture(const std::string& name, int width, int height,
|
|||
* @param name 纹理名称
|
||||
* @return 存在返回true,不存在返回false
|
||||
*/
|
||||
bool TextureAtlas::contains(const std::string& name) const {
|
||||
bool TextureAtlas::contains(const std::string &name) const {
|
||||
return entryToPage_.find(name) != entryToPage_.end();
|
||||
}
|
||||
|
||||
|
|
@ -293,7 +299,7 @@ bool TextureAtlas::contains(const std::string& name) const {
|
|||
* @param name 纹理名称
|
||||
* @return 找到返回纹理指针,未找到返回nullptr
|
||||
*/
|
||||
const Texture* TextureAtlas::getAtlasTexture(const std::string& name) const {
|
||||
const Texture *TextureAtlas::getAtlasTexture(const std::string &name) const {
|
||||
auto it = entryToPage_.find(name);
|
||||
if (it != entryToPage_.end()) {
|
||||
return it->second->getTexture().get();
|
||||
|
|
@ -306,10 +312,10 @@ const Texture* TextureAtlas::getAtlasTexture(const std::string& name) const {
|
|||
* @param name 纹理名称
|
||||
* @return UV坐标矩形,未找到返回默认值
|
||||
*/
|
||||
Rect TextureAtlas::getUVRect(const std::string& name) const {
|
||||
Rect TextureAtlas::getUVRect(const std::string &name) const {
|
||||
auto it = entryToPage_.find(name);
|
||||
if (it != entryToPage_.end()) {
|
||||
const AtlasEntry* entry = it->second->getEntry(name);
|
||||
const AtlasEntry *entry = it->second->getEntry(name);
|
||||
if (entry != nullptr) {
|
||||
return entry->uvRect;
|
||||
}
|
||||
|
|
@ -322,10 +328,10 @@ Rect TextureAtlas::getUVRect(const std::string& name) const {
|
|||
* @param name 纹理名称
|
||||
* @return 原始尺寸,未找到返回零向量
|
||||
*/
|
||||
Vec2 TextureAtlas::getOriginalSize(const std::string& name) const {
|
||||
Vec2 TextureAtlas::getOriginalSize(const std::string &name) const {
|
||||
auto it = entryToPage_.find(name);
|
||||
if (it != entryToPage_.end()) {
|
||||
const AtlasEntry* entry = it->second->getEntry(name);
|
||||
const AtlasEntry *entry = it->second->getEntry(name);
|
||||
if (entry != nullptr) {
|
||||
return entry->originalSize;
|
||||
}
|
||||
|
|
@ -345,7 +351,7 @@ float TextureAtlas::getTotalUsageRatio() const {
|
|||
}
|
||||
|
||||
float total = 0.0f;
|
||||
for (const auto& page : pages_) {
|
||||
for (const auto &page : pages_) {
|
||||
total += page->getUsageRatio();
|
||||
}
|
||||
return total / pages_.size();
|
||||
|
|
@ -372,7 +378,7 @@ void TextureAtlas::clear() {
|
|||
*
|
||||
* 使用静态局部变量实现线程安全的单例模式
|
||||
*/
|
||||
TextureAtlasMgr& TextureAtlasMgr::get() {
|
||||
TextureAtlasMgr &TextureAtlasMgr::get() {
|
||||
static TextureAtlasMgr instance;
|
||||
return instance;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#include "glfw_input.h"
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <cmath>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
@ -8,92 +10,165 @@ namespace extra2d {
|
|||
static Key glfwToKey(int glfwKey) {
|
||||
switch (glfwKey) {
|
||||
// 字母键
|
||||
case GLFW_KEY_A: return Key::A;
|
||||
case GLFW_KEY_B: return Key::B;
|
||||
case GLFW_KEY_C: return Key::C;
|
||||
case GLFW_KEY_D: return Key::D;
|
||||
case GLFW_KEY_E: return Key::E;
|
||||
case GLFW_KEY_F: return Key::F;
|
||||
case GLFW_KEY_G: return Key::G;
|
||||
case GLFW_KEY_H: return Key::H;
|
||||
case GLFW_KEY_I: return Key::I;
|
||||
case GLFW_KEY_J: return Key::J;
|
||||
case GLFW_KEY_K: return Key::K;
|
||||
case GLFW_KEY_L: return Key::L;
|
||||
case GLFW_KEY_M: return Key::M;
|
||||
case GLFW_KEY_N: return Key::N;
|
||||
case GLFW_KEY_O: return Key::O;
|
||||
case GLFW_KEY_P: return Key::P;
|
||||
case GLFW_KEY_Q: return Key::Q;
|
||||
case GLFW_KEY_R: return Key::R;
|
||||
case GLFW_KEY_S: return Key::S;
|
||||
case GLFW_KEY_T: return Key::T;
|
||||
case GLFW_KEY_U: return Key::U;
|
||||
case GLFW_KEY_V: return Key::V;
|
||||
case GLFW_KEY_W: return Key::W;
|
||||
case GLFW_KEY_X: return Key::X;
|
||||
case GLFW_KEY_Y: return Key::Y;
|
||||
case GLFW_KEY_Z: return Key::Z;
|
||||
case GLFW_KEY_A:
|
||||
return Key::A;
|
||||
case GLFW_KEY_B:
|
||||
return Key::B;
|
||||
case GLFW_KEY_C:
|
||||
return Key::C;
|
||||
case GLFW_KEY_D:
|
||||
return Key::D;
|
||||
case GLFW_KEY_E:
|
||||
return Key::E;
|
||||
case GLFW_KEY_F:
|
||||
return Key::F;
|
||||
case GLFW_KEY_G:
|
||||
return Key::G;
|
||||
case GLFW_KEY_H:
|
||||
return Key::H;
|
||||
case GLFW_KEY_I:
|
||||
return Key::I;
|
||||
case GLFW_KEY_J:
|
||||
return Key::J;
|
||||
case GLFW_KEY_K:
|
||||
return Key::K;
|
||||
case GLFW_KEY_L:
|
||||
return Key::L;
|
||||
case GLFW_KEY_M:
|
||||
return Key::M;
|
||||
case GLFW_KEY_N:
|
||||
return Key::N;
|
||||
case GLFW_KEY_O:
|
||||
return Key::O;
|
||||
case GLFW_KEY_P:
|
||||
return Key::P;
|
||||
case GLFW_KEY_Q:
|
||||
return Key::Q;
|
||||
case GLFW_KEY_R:
|
||||
return Key::R;
|
||||
case GLFW_KEY_S:
|
||||
return Key::S;
|
||||
case GLFW_KEY_T:
|
||||
return Key::T;
|
||||
case GLFW_KEY_U:
|
||||
return Key::U;
|
||||
case GLFW_KEY_V:
|
||||
return Key::V;
|
||||
case GLFW_KEY_W:
|
||||
return Key::W;
|
||||
case GLFW_KEY_X:
|
||||
return Key::X;
|
||||
case GLFW_KEY_Y:
|
||||
return Key::Y;
|
||||
case GLFW_KEY_Z:
|
||||
return Key::Z;
|
||||
|
||||
// 数字键
|
||||
case GLFW_KEY_0: return Key::Num0;
|
||||
case GLFW_KEY_1: return Key::Num1;
|
||||
case GLFW_KEY_2: return Key::Num2;
|
||||
case GLFW_KEY_3: return Key::Num3;
|
||||
case GLFW_KEY_4: return Key::Num4;
|
||||
case GLFW_KEY_5: return Key::Num5;
|
||||
case GLFW_KEY_6: return Key::Num6;
|
||||
case GLFW_KEY_7: return Key::Num7;
|
||||
case GLFW_KEY_8: return Key::Num8;
|
||||
case GLFW_KEY_9: return Key::Num9;
|
||||
case GLFW_KEY_0:
|
||||
return Key::Num0;
|
||||
case GLFW_KEY_1:
|
||||
return Key::Num1;
|
||||
case GLFW_KEY_2:
|
||||
return Key::Num2;
|
||||
case GLFW_KEY_3:
|
||||
return Key::Num3;
|
||||
case GLFW_KEY_4:
|
||||
return Key::Num4;
|
||||
case GLFW_KEY_5:
|
||||
return Key::Num5;
|
||||
case GLFW_KEY_6:
|
||||
return Key::Num6;
|
||||
case GLFW_KEY_7:
|
||||
return Key::Num7;
|
||||
case GLFW_KEY_8:
|
||||
return Key::Num8;
|
||||
case GLFW_KEY_9:
|
||||
return Key::Num9;
|
||||
|
||||
// 功能键
|
||||
case GLFW_KEY_F1: return Key::F1;
|
||||
case GLFW_KEY_F2: return Key::F2;
|
||||
case GLFW_KEY_F3: return Key::F3;
|
||||
case GLFW_KEY_F4: return Key::F4;
|
||||
case GLFW_KEY_F5: return Key::F5;
|
||||
case GLFW_KEY_F6: return Key::F6;
|
||||
case GLFW_KEY_F7: return Key::F7;
|
||||
case GLFW_KEY_F8: return Key::F8;
|
||||
case GLFW_KEY_F9: return Key::F9;
|
||||
case GLFW_KEY_F10: return Key::F10;
|
||||
case GLFW_KEY_F11: return Key::F11;
|
||||
case GLFW_KEY_F12: return Key::F12;
|
||||
case GLFW_KEY_F1:
|
||||
return Key::F1;
|
||||
case GLFW_KEY_F2:
|
||||
return Key::F2;
|
||||
case GLFW_KEY_F3:
|
||||
return Key::F3;
|
||||
case GLFW_KEY_F4:
|
||||
return Key::F4;
|
||||
case GLFW_KEY_F5:
|
||||
return Key::F5;
|
||||
case GLFW_KEY_F6:
|
||||
return Key::F6;
|
||||
case GLFW_KEY_F7:
|
||||
return Key::F7;
|
||||
case GLFW_KEY_F8:
|
||||
return Key::F8;
|
||||
case GLFW_KEY_F9:
|
||||
return Key::F9;
|
||||
case GLFW_KEY_F10:
|
||||
return Key::F10;
|
||||
case GLFW_KEY_F11:
|
||||
return Key::F11;
|
||||
case GLFW_KEY_F12:
|
||||
return Key::F12;
|
||||
|
||||
// 特殊键
|
||||
case GLFW_KEY_SPACE: return Key::Space;
|
||||
case GLFW_KEY_ENTER: return Key::Enter;
|
||||
case GLFW_KEY_ESCAPE: return Key::Escape;
|
||||
case GLFW_KEY_TAB: return Key::Tab;
|
||||
case GLFW_KEY_BACKSPACE: return Key::Backspace;
|
||||
case GLFW_KEY_INSERT: return Key::Insert;
|
||||
case GLFW_KEY_DELETE: return Key::Delete;
|
||||
case GLFW_KEY_HOME: return Key::Home;
|
||||
case GLFW_KEY_END: return Key::End;
|
||||
case GLFW_KEY_PAGE_UP: return Key::PageUp;
|
||||
case GLFW_KEY_PAGE_DOWN: return Key::PageDown;
|
||||
case GLFW_KEY_SPACE:
|
||||
return Key::Space;
|
||||
case GLFW_KEY_ENTER:
|
||||
return Key::Enter;
|
||||
case GLFW_KEY_ESCAPE:
|
||||
return Key::Escape;
|
||||
case GLFW_KEY_TAB:
|
||||
return Key::Tab;
|
||||
case GLFW_KEY_BACKSPACE:
|
||||
return Key::Backspace;
|
||||
case GLFW_KEY_INSERT:
|
||||
return Key::Insert;
|
||||
case GLFW_KEY_DELETE:
|
||||
return Key::Delete;
|
||||
case GLFW_KEY_HOME:
|
||||
return Key::Home;
|
||||
case GLFW_KEY_END:
|
||||
return Key::End;
|
||||
case GLFW_KEY_PAGE_UP:
|
||||
return Key::PageUp;
|
||||
case GLFW_KEY_PAGE_DOWN:
|
||||
return Key::PageDown;
|
||||
|
||||
// 方向键
|
||||
case GLFW_KEY_UP: return Key::Up;
|
||||
case GLFW_KEY_DOWN: return Key::Down;
|
||||
case GLFW_KEY_LEFT: return Key::Left;
|
||||
case GLFW_KEY_RIGHT: return Key::Right;
|
||||
case GLFW_KEY_UP:
|
||||
return Key::Up;
|
||||
case GLFW_KEY_DOWN:
|
||||
return Key::Down;
|
||||
case GLFW_KEY_LEFT:
|
||||
return Key::Left;
|
||||
case GLFW_KEY_RIGHT:
|
||||
return Key::Right;
|
||||
|
||||
// 修饰键
|
||||
case GLFW_KEY_LEFT_SHIFT: return Key::LShift;
|
||||
case GLFW_KEY_RIGHT_SHIFT: return Key::RShift;
|
||||
case GLFW_KEY_LEFT_CONTROL: return Key::LCtrl;
|
||||
case GLFW_KEY_RIGHT_CONTROL: return Key::RCtrl;
|
||||
case GLFW_KEY_LEFT_ALT: return Key::LAlt;
|
||||
case GLFW_KEY_RIGHT_ALT: return Key::RAlt;
|
||||
case GLFW_KEY_LEFT_SHIFT:
|
||||
return Key::LShift;
|
||||
case GLFW_KEY_RIGHT_SHIFT:
|
||||
return Key::RShift;
|
||||
case GLFW_KEY_LEFT_CONTROL:
|
||||
return Key::LCtrl;
|
||||
case GLFW_KEY_RIGHT_CONTROL:
|
||||
return Key::RCtrl;
|
||||
case GLFW_KEY_LEFT_ALT:
|
||||
return Key::LAlt;
|
||||
case GLFW_KEY_RIGHT_ALT:
|
||||
return Key::RAlt;
|
||||
|
||||
// 锁定键
|
||||
case GLFW_KEY_CAPS_LOCK: return Key::CapsLock;
|
||||
case GLFW_KEY_NUM_LOCK: return Key::NumLock;
|
||||
case GLFW_KEY_SCROLL_LOCK: return Key::ScrollLock;
|
||||
case GLFW_KEY_CAPS_LOCK:
|
||||
return Key::CapsLock;
|
||||
case GLFW_KEY_NUM_LOCK:
|
||||
return Key::NumLock;
|
||||
case GLFW_KEY_SCROLL_LOCK:
|
||||
return Key::ScrollLock;
|
||||
|
||||
default: return Key::None;
|
||||
default:
|
||||
return Key::None;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -106,9 +181,7 @@ GLFWInput::GLFWInput() {
|
|||
gamepadPrevious_.fill(false);
|
||||
}
|
||||
|
||||
GLFWInput::~GLFWInput() {
|
||||
shutdown();
|
||||
}
|
||||
GLFWInput::~GLFWInput() { shutdown(); }
|
||||
|
||||
void GLFWInput::init() {
|
||||
E2D_LOG_INFO("GLFWInput initialized");
|
||||
|
|
@ -207,31 +280,21 @@ bool GLFWInput::released(Mouse btn) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
Vec2 GLFWInput::mouse() const {
|
||||
return mousePos_;
|
||||
}
|
||||
Vec2 GLFWInput::mouse() const { return mousePos_; }
|
||||
|
||||
Vec2 GLFWInput::mouseDelta() const {
|
||||
return mouseDelta_;
|
||||
}
|
||||
Vec2 GLFWInput::mouseDelta() const { return mouseDelta_; }
|
||||
|
||||
float GLFWInput::scroll() const {
|
||||
return scroll_;
|
||||
}
|
||||
float GLFWInput::scroll() const { return scroll_; }
|
||||
|
||||
float GLFWInput::scrollDelta() const {
|
||||
return scrollDelta_;
|
||||
}
|
||||
float GLFWInput::scrollDelta() const { return scrollDelta_; }
|
||||
|
||||
void GLFWInput::setMouse(const Vec2& pos) {
|
||||
void GLFWInput::setMouse(const Vec2 &pos) {
|
||||
if (window_) {
|
||||
glfwSetCursorPos(window_, pos.x, pos.y);
|
||||
}
|
||||
}
|
||||
|
||||
bool GLFWInput::gamepad() const {
|
||||
return gamepadId_ != -1;
|
||||
}
|
||||
bool GLFWInput::gamepad() const { return gamepadId_ != -1; }
|
||||
|
||||
bool GLFWInput::down(Gamepad btn) const {
|
||||
size_t idx = static_cast<size_t>(btn);
|
||||
|
|
@ -257,21 +320,13 @@ bool GLFWInput::released(Gamepad btn) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
Vec2 GLFWInput::leftStick() const {
|
||||
return leftStick_;
|
||||
}
|
||||
Vec2 GLFWInput::leftStick() const { return leftStick_; }
|
||||
|
||||
Vec2 GLFWInput::rightStick() const {
|
||||
return rightStick_;
|
||||
}
|
||||
Vec2 GLFWInput::rightStick() const { return rightStick_; }
|
||||
|
||||
float GLFWInput::leftTrigger() const {
|
||||
return leftTrigger_;
|
||||
}
|
||||
float GLFWInput::leftTrigger() const { return leftTrigger_; }
|
||||
|
||||
float GLFWInput::rightTrigger() const {
|
||||
return rightTrigger_;
|
||||
}
|
||||
float GLFWInput::rightTrigger() const { return rightTrigger_; }
|
||||
|
||||
void GLFWInput::vibrate(float left, float right) {
|
||||
// GLFW 本身不支持震动,需要平台特定的代码
|
||||
|
|
@ -280,13 +335,9 @@ void GLFWInput::vibrate(float left, float right) {
|
|||
(void)right;
|
||||
}
|
||||
|
||||
bool GLFWInput::touching() const {
|
||||
return false;
|
||||
}
|
||||
bool GLFWInput::touching() const { return false; }
|
||||
|
||||
int GLFWInput::touchCount() const {
|
||||
return 0;
|
||||
}
|
||||
int GLFWInput::touchCount() const { return 0; }
|
||||
|
||||
Vec2 GLFWInput::touch(int index) const {
|
||||
(void)index;
|
||||
|
|
@ -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::B)] = state.buttons[GLFW_GAMEPAD_BUTTON_B] == GLFW_PRESS;
|
||||
gamepadCurrent_[static_cast<size_t>(Gamepad::X)] = state.buttons[GLFW_GAMEPAD_BUTTON_X] == GLFW_PRESS;
|
||||
gamepadCurrent_[static_cast<size_t>(Gamepad::Y)] = state.buttons[GLFW_GAMEPAD_BUTTON_Y] == GLFW_PRESS;
|
||||
gamepadCurrent_[static_cast<size_t>(Gamepad::Back)] = state.buttons[GLFW_GAMEPAD_BUTTON_BACK] == GLFW_PRESS;
|
||||
gamepadCurrent_[static_cast<size_t>(Gamepad::Start)] = state.buttons[GLFW_GAMEPAD_BUTTON_START] == GLFW_PRESS;
|
||||
gamepadCurrent_[static_cast<size_t>(Gamepad::LStick)] = state.buttons[GLFW_GAMEPAD_BUTTON_LEFT_THUMB] == 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;
|
||||
gamepadCurrent_[static_cast<size_t>(Gamepad::A)] =
|
||||
state.buttons[GLFW_GAMEPAD_BUTTON_A] == GLFW_PRESS;
|
||||
gamepadCurrent_[static_cast<size_t>(Gamepad::B)] =
|
||||
state.buttons[GLFW_GAMEPAD_BUTTON_B] == GLFW_PRESS;
|
||||
gamepadCurrent_[static_cast<size_t>(Gamepad::X)] =
|
||||
state.buttons[GLFW_GAMEPAD_BUTTON_X] == GLFW_PRESS;
|
||||
gamepadCurrent_[static_cast<size_t>(Gamepad::Y)] =
|
||||
state.buttons[GLFW_GAMEPAD_BUTTON_Y] == GLFW_PRESS;
|
||||
gamepadCurrent_[static_cast<size_t>(Gamepad::Back)] =
|
||||
state.buttons[GLFW_GAMEPAD_BUTTON_BACK] == GLFW_PRESS;
|
||||
gamepadCurrent_[static_cast<size_t>(Gamepad::Start)] =
|
||||
state.buttons[GLFW_GAMEPAD_BUTTON_START] == GLFW_PRESS;
|
||||
gamepadCurrent_[static_cast<size_t>(Gamepad::LStick)] =
|
||||
state.buttons[GLFW_GAMEPAD_BUTTON_LEFT_THUMB] == 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]);
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
#include "glfw_window.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>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
GLFWWindow::GLFWWindow() {}
|
||||
|
||||
GLFWWindow::~GLFWWindow() {
|
||||
destroy();
|
||||
}
|
||||
GLFWWindow::~GLFWWindow() { 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()) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -32,17 +33,13 @@ bool GLFWWindow::create(const std::string& title, int width, int height, bool vs
|
|||
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
|
||||
#endif
|
||||
|
||||
GLFWmonitor* monitor = nullptr;
|
||||
GLFWmonitor *monitor = nullptr;
|
||||
#ifdef __SWITCH__
|
||||
monitor = glfwGetPrimaryMonitor();
|
||||
#endif
|
||||
|
||||
glfwWindow_ = glfwCreateWindow(
|
||||
width, height,
|
||||
title.c_str(),
|
||||
monitor,
|
||||
nullptr
|
||||
);
|
||||
glfwWindow_ =
|
||||
glfwCreateWindow(width, height, title.c_str(), monitor, nullptr);
|
||||
|
||||
if (!glfwWindow_) {
|
||||
E2D_LOG_ERROR("Failed to create GLFW window");
|
||||
|
|
@ -52,9 +49,9 @@ bool GLFWWindow::create(const std::string& title, int width, int height, bool vs
|
|||
|
||||
#ifndef __SWITCH__
|
||||
if (!fullscreen_ && !monitor) {
|
||||
GLFWmonitor* primaryMonitor = glfwGetPrimaryMonitor();
|
||||
GLFWmonitor *primaryMonitor = glfwGetPrimaryMonitor();
|
||||
if (primaryMonitor) {
|
||||
const GLFWvidmode* mode = glfwGetVideoMode(primaryMonitor);
|
||||
const GLFWvidmode *mode = glfwGetVideoMode(primaryMonitor);
|
||||
if (mode) {
|
||||
int screenWidth = mode->width;
|
||||
int screenHeight = mode->height;
|
||||
|
|
@ -117,7 +114,8 @@ void GLFWWindow::destroy() {
|
|||
}
|
||||
|
||||
void GLFWWindow::poll() {
|
||||
if (!glfwWindow_) return;
|
||||
if (!glfwWindow_)
|
||||
return;
|
||||
|
||||
if (input_) {
|
||||
input_->update();
|
||||
|
|
@ -133,7 +131,8 @@ void GLFWWindow::swap() {
|
|||
}
|
||||
|
||||
bool GLFWWindow::shouldClose() const {
|
||||
if (!glfwWindow_) return true;
|
||||
if (!glfwWindow_)
|
||||
return true;
|
||||
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_) {
|
||||
glfwSetWindowTitle(glfwWindow_, title.c_str());
|
||||
}
|
||||
|
|
@ -171,14 +170,17 @@ void GLFWWindow::setPos(int x, int y) {
|
|||
|
||||
void GLFWWindow::setFullscreen(bool fs) {
|
||||
#ifndef __SWITCH__
|
||||
if (!glfwWindow_) return;
|
||||
if (!glfwWindow_)
|
||||
return;
|
||||
|
||||
if (fs == fullscreen_) return;
|
||||
if (fs == fullscreen_)
|
||||
return;
|
||||
|
||||
if (fs) {
|
||||
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
|
||||
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
|
||||
glfwSetWindowMonitor(glfwWindow_, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
|
||||
GLFWmonitor *monitor = glfwGetPrimaryMonitor();
|
||||
const GLFWvidmode *mode = glfwGetVideoMode(monitor);
|
||||
glfwSetWindowMonitor(glfwWindow_, monitor, 0, 0, mode->width, mode->height,
|
||||
mode->refreshRate);
|
||||
} else {
|
||||
glfwSetWindowMonitor(glfwWindow_, nullptr, 100, 100, 1280, 720, 0);
|
||||
}
|
||||
|
|
@ -211,13 +213,9 @@ void GLFWWindow::setVisible(bool visible) {
|
|||
#endif
|
||||
}
|
||||
|
||||
int GLFWWindow::width() const {
|
||||
return width_;
|
||||
}
|
||||
int GLFWWindow::width() const { return width_; }
|
||||
|
||||
int GLFWWindow::height() const {
|
||||
return height_;
|
||||
}
|
||||
int GLFWWindow::height() const { return height_; }
|
||||
|
||||
Size GLFWWindow::size() const {
|
||||
return Size(static_cast<float>(width_), static_cast<float>(height_));
|
||||
|
|
@ -233,33 +231,22 @@ Vec2 GLFWWindow::pos() const {
|
|||
return Vec2(static_cast<float>(x), static_cast<float>(y));
|
||||
}
|
||||
|
||||
bool GLFWWindow::fullscreen() const {
|
||||
return fullscreen_;
|
||||
}
|
||||
bool GLFWWindow::fullscreen() const { return fullscreen_; }
|
||||
|
||||
bool GLFWWindow::vsync() const {
|
||||
return vsync_;
|
||||
}
|
||||
bool GLFWWindow::vsync() const { return vsync_; }
|
||||
|
||||
bool GLFWWindow::focused() const {
|
||||
return focused_;
|
||||
}
|
||||
bool GLFWWindow::focused() const { return focused_; }
|
||||
|
||||
bool GLFWWindow::minimized() const {
|
||||
return minimized_;
|
||||
}
|
||||
bool GLFWWindow::minimized() const { return minimized_; }
|
||||
|
||||
float GLFWWindow::scaleX() const {
|
||||
return scaleX_;
|
||||
}
|
||||
float GLFWWindow::scaleX() const { return scaleX_; }
|
||||
|
||||
float GLFWWindow::scaleY() const {
|
||||
return scaleY_;
|
||||
}
|
||||
float GLFWWindow::scaleY() const { return scaleY_; }
|
||||
|
||||
void GLFWWindow::setCursor(Cursor cursor) {
|
||||
#ifndef __SWITCH__
|
||||
if (!glfwWindow_) return;
|
||||
if (!glfwWindow_)
|
||||
return;
|
||||
|
||||
if (cursor == Cursor::Hidden) {
|
||||
glfwSetInputMode(glfwWindow_, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||
|
|
@ -268,7 +255,7 @@ void GLFWWindow::setCursor(Cursor cursor) {
|
|||
|
||||
glfwSetInputMode(glfwWindow_, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||
|
||||
GLFWcursor* glfwCursor = nullptr;
|
||||
GLFWcursor *glfwCursor = nullptr;
|
||||
switch (cursor) {
|
||||
case Cursor::Arrow:
|
||||
glfwCursor = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||
|
|
@ -304,7 +291,8 @@ void GLFWWindow::setCursor(Cursor cursor) {
|
|||
void GLFWWindow::showCursor(bool show) {
|
||||
#ifndef __SWITCH__
|
||||
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;
|
||||
}
|
||||
#else
|
||||
|
|
@ -315,7 +303,8 @@ void GLFWWindow::showCursor(bool show) {
|
|||
void GLFWWindow::lockCursor(bool lock) {
|
||||
#ifndef __SWITCH__
|
||||
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;
|
||||
}
|
||||
#else
|
||||
|
|
@ -323,25 +312,15 @@ void GLFWWindow::lockCursor(bool lock) {
|
|||
#endif
|
||||
}
|
||||
|
||||
IInput* GLFWWindow::input() const {
|
||||
return input_.get();
|
||||
}
|
||||
IInput *GLFWWindow::input() const { return input_.get(); }
|
||||
|
||||
void GLFWWindow::onResize(ResizeCb cb) {
|
||||
resizeCb_ = cb;
|
||||
}
|
||||
void GLFWWindow::onResize(ResizeCb cb) { resizeCb_ = cb; }
|
||||
|
||||
void GLFWWindow::onClose(CloseCb cb) {
|
||||
closeCb_ = cb;
|
||||
}
|
||||
void GLFWWindow::onClose(CloseCb cb) { closeCb_ = cb; }
|
||||
|
||||
void GLFWWindow::onFocus(FocusCb cb) {
|
||||
focusCb_ = cb;
|
||||
}
|
||||
void GLFWWindow::onFocus(FocusCb cb) { focusCb_ = cb; }
|
||||
|
||||
void* GLFWWindow::native() const {
|
||||
return glfwWindow_;
|
||||
}
|
||||
void *GLFWWindow::native() const { return glfwWindow_; }
|
||||
|
||||
bool GLFWWindow::initGLFW() {
|
||||
static int glfwInitCount = 0;
|
||||
|
|
@ -373,8 +352,10 @@ void GLFWWindow::updateContentScale() {
|
|||
}
|
||||
|
||||
// 静态回调函数
|
||||
void GLFWWindow::framebufferSizeCallback(GLFWwindow* window, int width, int height) {
|
||||
GLFWWindow* self = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window));
|
||||
void GLFWWindow::framebufferSizeCallback(GLFWwindow *window, int width,
|
||||
int height) {
|
||||
GLFWWindow *self =
|
||||
static_cast<GLFWWindow *>(glfwGetWindowUserPointer(window));
|
||||
if (self) {
|
||||
self->width_ = width;
|
||||
self->height_ = height;
|
||||
|
|
@ -385,8 +366,9 @@ void GLFWWindow::framebufferSizeCallback(GLFWwindow* window, int width, int heig
|
|||
}
|
||||
}
|
||||
|
||||
void GLFWWindow::windowCloseCallback(GLFWwindow* window) {
|
||||
GLFWWindow* self = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window));
|
||||
void GLFWWindow::windowCloseCallback(GLFWwindow *window) {
|
||||
GLFWWindow *self =
|
||||
static_cast<GLFWWindow *>(glfwGetWindowUserPointer(window));
|
||||
if (self) {
|
||||
self->shouldClose_ = true;
|
||||
if (self->closeCb_) {
|
||||
|
|
@ -395,8 +377,9 @@ void GLFWWindow::windowCloseCallback(GLFWwindow* window) {
|
|||
}
|
||||
}
|
||||
|
||||
void GLFWWindow::windowFocusCallback(GLFWwindow* window, int focused) {
|
||||
GLFWWindow* self = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window));
|
||||
void GLFWWindow::windowFocusCallback(GLFWwindow *window, int focused) {
|
||||
GLFWWindow *self =
|
||||
static_cast<GLFWWindow *>(glfwGetWindowUserPointer(window));
|
||||
if (self) {
|
||||
self->focused_ = (focused == GLFW_TRUE);
|
||||
if (self->focusCb_) {
|
||||
|
|
@ -405,36 +388,45 @@ void GLFWWindow::windowFocusCallback(GLFWwindow* window, int focused) {
|
|||
}
|
||||
}
|
||||
|
||||
void GLFWWindow::windowIconifyCallback(GLFWwindow* window, int iconified) {
|
||||
GLFWWindow* self = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window));
|
||||
void GLFWWindow::windowIconifyCallback(GLFWwindow *window, int iconified) {
|
||||
GLFWWindow *self =
|
||||
static_cast<GLFWWindow *>(glfwGetWindowUserPointer(window));
|
||||
if (self) {
|
||||
self->minimized_ = (iconified == GLFW_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void GLFWWindow::cursorPosCallback(GLFWwindow* window, double xpos, double ypos) {
|
||||
GLFWWindow* self = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window));
|
||||
void GLFWWindow::cursorPosCallback(GLFWwindow *window, double xpos,
|
||||
double ypos) {
|
||||
GLFWWindow *self =
|
||||
static_cast<GLFWWindow *>(glfwGetWindowUserPointer(window));
|
||||
if (self && self->input_) {
|
||||
self->input_->handleCursorPosEvent(xpos, ypos);
|
||||
}
|
||||
}
|
||||
|
||||
void GLFWWindow::mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) {
|
||||
GLFWWindow* self = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window));
|
||||
void GLFWWindow::mouseButtonCallback(GLFWwindow *window, int button, int action,
|
||||
int mods) {
|
||||
GLFWWindow *self =
|
||||
static_cast<GLFWWindow *>(glfwGetWindowUserPointer(window));
|
||||
if (self && self->input_) {
|
||||
self->input_->handleMouseButtonEvent(button, action, mods);
|
||||
}
|
||||
}
|
||||
|
||||
void GLFWWindow::scrollCallback(GLFWwindow* window, double xoffset, double yoffset) {
|
||||
GLFWWindow* self = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window));
|
||||
void GLFWWindow::scrollCallback(GLFWwindow *window, double xoffset,
|
||||
double yoffset) {
|
||||
GLFWWindow *self =
|
||||
static_cast<GLFWWindow *>(glfwGetWindowUserPointer(window));
|
||||
if (self && self->input_) {
|
||||
self->input_->handleScrollEvent(xoffset, yoffset);
|
||||
}
|
||||
}
|
||||
|
||||
void GLFWWindow::keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
|
||||
GLFWWindow* self = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window));
|
||||
void GLFWWindow::keyCallback(GLFWwindow *window, int key, int scancode,
|
||||
int action, int mods) {
|
||||
GLFWWindow *self =
|
||||
static_cast<GLFWWindow *>(glfwGetWindowUserPointer(window));
|
||||
if (self && self->input_) {
|
||||
self->input_->handleKeyEvent(key, scancode, action, mods);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#include "sdl2_input.h"
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <cmath>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
@ -13,9 +15,7 @@ SDL2Input::SDL2Input() {
|
|||
gamepadPrevious_.fill(false);
|
||||
}
|
||||
|
||||
SDL2Input::~SDL2Input() {
|
||||
shutdown();
|
||||
}
|
||||
SDL2Input::~SDL2Input() { shutdown(); }
|
||||
|
||||
void SDL2Input::init() {
|
||||
E2D_LOG_INFO("SDL2Input initialized");
|
||||
|
|
@ -47,7 +47,7 @@ void SDL2Input::setEventCallback(EventCallback callback) {
|
|||
eventCallback_ = std::move(callback);
|
||||
}
|
||||
|
||||
void SDL2Input::handleSDLEvent(const SDL_Event& event) {
|
||||
void SDL2Input::handleSDLEvent(const SDL_Event &event) {
|
||||
switch (event.type) {
|
||||
case SDL_KEYDOWN: {
|
||||
int key = event.key.keysym.scancode;
|
||||
|
|
@ -55,11 +55,9 @@ void SDL2Input::handleSDLEvent(const SDL_Event& event) {
|
|||
if (!keyCurrent_[key]) {
|
||||
keyCurrent_[key] = true;
|
||||
|
||||
Event e = Event::createKeyPress(
|
||||
event.key.keysym.sym,
|
||||
Event e = Event::createKeyPress(event.key.keysym.sym,
|
||||
event.key.keysym.scancode,
|
||||
event.key.keysym.mod
|
||||
);
|
||||
event.key.keysym.mod);
|
||||
dispatchEvent(e);
|
||||
}
|
||||
}
|
||||
|
|
@ -71,11 +69,9 @@ void SDL2Input::handleSDLEvent(const SDL_Event& event) {
|
|||
if (key >= 0 && key < static_cast<int>(Key::Count)) {
|
||||
keyCurrent_[key] = false;
|
||||
|
||||
Event e = Event::createKeyRelease(
|
||||
event.key.keysym.sym,
|
||||
Event e = Event::createKeyRelease(event.key.keysym.sym,
|
||||
event.key.keysym.scancode,
|
||||
event.key.keysym.mod
|
||||
);
|
||||
event.key.keysym.mod);
|
||||
dispatchEvent(e);
|
||||
}
|
||||
break;
|
||||
|
|
@ -140,7 +136,9 @@ void SDL2Input::handleSDLEvent(const SDL_Event& event) {
|
|||
break;
|
||||
|
||||
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");
|
||||
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_) {
|
||||
eventCallback_(event);
|
||||
}
|
||||
|
|
@ -241,29 +239,20 @@ bool SDL2Input::released(Mouse btn) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
Vec2 SDL2Input::mouse() const {
|
||||
return mousePos_;
|
||||
Vec2 SDL2Input::mouse() const { return mousePos_; }
|
||||
|
||||
Vec2 SDL2Input::mouseDelta() const { return mouseDelta_; }
|
||||
|
||||
float SDL2Input::scroll() const { return scroll_; }
|
||||
|
||||
float SDL2Input::scrollDelta() const { return scrollDelta_; }
|
||||
|
||||
void SDL2Input::setMouse(const Vec2 &pos) {
|
||||
SDL_WarpMouseInWindow(nullptr, static_cast<int>(pos.x),
|
||||
static_cast<int>(pos.y));
|
||||
}
|
||||
|
||||
Vec2 SDL2Input::mouseDelta() const {
|
||||
return mouseDelta_;
|
||||
}
|
||||
|
||||
float SDL2Input::scroll() const {
|
||||
return scroll_;
|
||||
}
|
||||
|
||||
float SDL2Input::scrollDelta() const {
|
||||
return scrollDelta_;
|
||||
}
|
||||
|
||||
void SDL2Input::setMouse(const Vec2& pos) {
|
||||
SDL_WarpMouseInWindow(nullptr, static_cast<int>(pos.x), static_cast<int>(pos.y));
|
||||
}
|
||||
|
||||
bool SDL2Input::gamepad() const {
|
||||
return gamepad_ != nullptr;
|
||||
}
|
||||
bool SDL2Input::gamepad() const { return gamepad_ != nullptr; }
|
||||
|
||||
bool SDL2Input::down(Gamepad btn) const {
|
||||
size_t idx = static_cast<size_t>(btn);
|
||||
|
|
@ -289,21 +278,13 @@ bool SDL2Input::released(Gamepad btn) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
Vec2 SDL2Input::leftStick() const {
|
||||
return leftStick_;
|
||||
}
|
||||
Vec2 SDL2Input::leftStick() const { return leftStick_; }
|
||||
|
||||
Vec2 SDL2Input::rightStick() const {
|
||||
return rightStick_;
|
||||
}
|
||||
Vec2 SDL2Input::rightStick() const { return rightStick_; }
|
||||
|
||||
float SDL2Input::leftTrigger() const {
|
||||
return leftTrigger_;
|
||||
}
|
||||
float SDL2Input::leftTrigger() const { return leftTrigger_; }
|
||||
|
||||
float SDL2Input::rightTrigger() const {
|
||||
return rightTrigger_;
|
||||
}
|
||||
float SDL2Input::rightTrigger() const { return rightTrigger_; }
|
||||
|
||||
void SDL2Input::vibrate(float left, float right) {
|
||||
if (gamepad_) {
|
||||
|
|
@ -313,13 +294,9 @@ void SDL2Input::vibrate(float left, float right) {
|
|||
}
|
||||
}
|
||||
|
||||
bool SDL2Input::touching() const {
|
||||
return false;
|
||||
}
|
||||
bool SDL2Input::touching() const { return false; }
|
||||
|
||||
int SDL2Input::touchCount() const {
|
||||
return 0;
|
||||
}
|
||||
int SDL2Input::touchCount() const { return 0; }
|
||||
|
||||
Vec2 SDL2Input::touch(int index) const {
|
||||
(void)index;
|
||||
|
|
@ -331,8 +308,7 @@ TouchPoint SDL2Input::touchPoint(int index) const {
|
|||
return TouchPoint{};
|
||||
}
|
||||
|
||||
void SDL2Input::updateKeyboard() {
|
||||
}
|
||||
void SDL2Input::updateKeyboard() {}
|
||||
|
||||
void SDL2Input::updateMouse() {
|
||||
int x = 0, y = 0;
|
||||
|
|
@ -364,7 +340,8 @@ void SDL2Input::updateGamepad() {
|
|||
rightStick_.y = applyDeadzone(ry / 32767.0f);
|
||||
|
||||
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;
|
||||
rightTrigger_ = rt / 32767.0f;
|
||||
|
|
@ -394,39 +371,59 @@ void SDL2Input::closeGamepad() {
|
|||
}
|
||||
}
|
||||
|
||||
int SDL2Input::keyToSDL(Key key) {
|
||||
return static_cast<int>(key);
|
||||
}
|
||||
int SDL2Input::keyToSDL(Key key) { return static_cast<int>(key); }
|
||||
|
||||
int SDL2Input::mouseToSDL(Mouse btn) {
|
||||
switch (btn) {
|
||||
case Mouse::Left: return SDL_BUTTON_LEFT;
|
||||
case Mouse::Middle: return SDL_BUTTON_MIDDLE;
|
||||
case Mouse::Right: return SDL_BUTTON_RIGHT;
|
||||
case Mouse::X1: return SDL_BUTTON_X1;
|
||||
case Mouse::X2: return SDL_BUTTON_X2;
|
||||
default: return 0;
|
||||
case Mouse::Left:
|
||||
return SDL_BUTTON_LEFT;
|
||||
case Mouse::Middle:
|
||||
return SDL_BUTTON_MIDDLE;
|
||||
case Mouse::Right:
|
||||
return SDL_BUTTON_RIGHT;
|
||||
case Mouse::X1:
|
||||
return SDL_BUTTON_X1;
|
||||
case Mouse::X2:
|
||||
return SDL_BUTTON_X2;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int SDL2Input::gamepadToSDL(Gamepad btn) {
|
||||
switch (btn) {
|
||||
case Gamepad::A: return SDL_CONTROLLER_BUTTON_A;
|
||||
case Gamepad::B: return SDL_CONTROLLER_BUTTON_B;
|
||||
case Gamepad::X: return SDL_CONTROLLER_BUTTON_X;
|
||||
case Gamepad::Y: return SDL_CONTROLLER_BUTTON_Y;
|
||||
case Gamepad::Back: return SDL_CONTROLLER_BUTTON_BACK;
|
||||
case Gamepad::Start: return SDL_CONTROLLER_BUTTON_START;
|
||||
case Gamepad::LStick: return SDL_CONTROLLER_BUTTON_LEFTSTICK;
|
||||
case Gamepad::RStick: return SDL_CONTROLLER_BUTTON_RIGHTSTICK;
|
||||
case Gamepad::LB: return SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
|
||||
case Gamepad::RB: return SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
|
||||
case Gamepad::DUp: return SDL_CONTROLLER_BUTTON_DPAD_UP;
|
||||
case Gamepad::DDown: return SDL_CONTROLLER_BUTTON_DPAD_DOWN;
|
||||
case Gamepad::DLeft: return SDL_CONTROLLER_BUTTON_DPAD_LEFT;
|
||||
case Gamepad::DRight: return SDL_CONTROLLER_BUTTON_DPAD_RIGHT;
|
||||
case Gamepad::Guide: return SDL_CONTROLLER_BUTTON_GUIDE;
|
||||
default: return 0;
|
||||
case Gamepad::A:
|
||||
return SDL_CONTROLLER_BUTTON_A;
|
||||
case Gamepad::B:
|
||||
return SDL_CONTROLLER_BUTTON_B;
|
||||
case Gamepad::X:
|
||||
return SDL_CONTROLLER_BUTTON_X;
|
||||
case Gamepad::Y:
|
||||
return SDL_CONTROLLER_BUTTON_Y;
|
||||
case Gamepad::Back:
|
||||
return SDL_CONTROLLER_BUTTON_BACK;
|
||||
case Gamepad::Start:
|
||||
return SDL_CONTROLLER_BUTTON_START;
|
||||
case Gamepad::LStick:
|
||||
return SDL_CONTROLLER_BUTTON_LEFTSTICK;
|
||||
case Gamepad::RStick:
|
||||
return SDL_CONTROLLER_BUTTON_RIGHTSTICK;
|
||||
case Gamepad::LB:
|
||||
return SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
|
||||
case Gamepad::RB:
|
||||
return SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
|
||||
case Gamepad::DUp:
|
||||
return SDL_CONTROLLER_BUTTON_DPAD_UP;
|
||||
case Gamepad::DDown:
|
||||
return SDL_CONTROLLER_BUTTON_DPAD_DOWN;
|
||||
case Gamepad::DLeft:
|
||||
return SDL_CONTROLLER_BUTTON_DPAD_LEFT;
|
||||
case Gamepad::DRight:
|
||||
return SDL_CONTROLLER_BUTTON_DPAD_RIGHT;
|
||||
case Gamepad::Guide:
|
||||
return SDL_CONTROLLER_BUTTON_GUIDE;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -439,13 +436,19 @@ Key SDL2Input::sdlToKey(int sdlKey) {
|
|||
|
||||
Mouse SDL2Input::sdlToMouse(int sdlButton) {
|
||||
switch (sdlButton) {
|
||||
case SDL_BUTTON_LEFT: return Mouse::Left;
|
||||
case SDL_BUTTON_MIDDLE: return Mouse::Middle;
|
||||
case SDL_BUTTON_RIGHT: return Mouse::Right;
|
||||
case SDL_BUTTON_X1: return Mouse::X1;
|
||||
case SDL_BUTTON_X2: return Mouse::X2;
|
||||
default: return Mouse::Count;
|
||||
case SDL_BUTTON_LEFT:
|
||||
return Mouse::Left;
|
||||
case SDL_BUTTON_MIDDLE:
|
||||
return Mouse::Middle;
|
||||
case SDL_BUTTON_RIGHT:
|
||||
return Mouse::Right;
|
||||
case SDL_BUTTON_X1:
|
||||
return Mouse::X1;
|
||||
case SDL_BUTTON_X2:
|
||||
return Mouse::X2;
|
||||
default:
|
||||
return Mouse::Count;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace extra2d
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
#include "sdl2_window.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>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
SDL2Window::SDL2Window() {
|
||||
|
|
@ -11,11 +13,10 @@ SDL2Window::SDL2Window() {
|
|||
}
|
||||
}
|
||||
|
||||
SDL2Window::~SDL2Window() {
|
||||
destroy();
|
||||
}
|
||||
SDL2Window::~SDL2Window() { 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()) {
|
||||
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_STENCIL_SIZE, 8);
|
||||
|
||||
sdlWindow_ = SDL_CreateWindow(
|
||||
title.c_str(),
|
||||
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||
width, height,
|
||||
flags
|
||||
);
|
||||
sdlWindow_ = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED,
|
||||
SDL_WINDOWPOS_CENTERED, width, height, flags);
|
||||
|
||||
if (!sdlWindow_) {
|
||||
E2D_LOG_ERROR("Failed to create SDL window: {}", SDL_GetError());
|
||||
|
|
@ -109,7 +106,8 @@ void SDL2Window::destroy() {
|
|||
}
|
||||
|
||||
void SDL2Window::poll() {
|
||||
if (!sdlWindow_) return;
|
||||
if (!sdlWindow_)
|
||||
return;
|
||||
|
||||
if (input_) {
|
||||
input_->update();
|
||||
|
|
@ -127,15 +125,11 @@ void SDL2Window::swap() {
|
|||
}
|
||||
}
|
||||
|
||||
bool SDL2Window::shouldClose() const {
|
||||
return shouldClose_;
|
||||
}
|
||||
bool SDL2Window::shouldClose() const { return shouldClose_; }
|
||||
|
||||
void SDL2Window::close() {
|
||||
shouldClose_ = true;
|
||||
}
|
||||
void SDL2Window::close() { shouldClose_ = true; }
|
||||
|
||||
void SDL2Window::setTitle(const std::string& title) {
|
||||
void SDL2Window::setTitle(const std::string &title) {
|
||||
if (sdlWindow_) {
|
||||
SDL_SetWindowTitle(sdlWindow_, title.c_str());
|
||||
}
|
||||
|
|
@ -192,13 +186,9 @@ void SDL2Window::setVisible(bool visible) {
|
|||
#endif
|
||||
}
|
||||
|
||||
int SDL2Window::width() const {
|
||||
return width_;
|
||||
}
|
||||
int SDL2Window::width() const { return width_; }
|
||||
|
||||
int SDL2Window::height() const {
|
||||
return height_;
|
||||
}
|
||||
int SDL2Window::height() const { return height_; }
|
||||
|
||||
Size SDL2Window::size() const {
|
||||
return Size(static_cast<float>(width_), static_cast<float>(height_));
|
||||
|
|
@ -214,29 +204,17 @@ Vec2 SDL2Window::pos() const {
|
|||
return Vec2(static_cast<float>(x), static_cast<float>(y));
|
||||
}
|
||||
|
||||
bool SDL2Window::fullscreen() const {
|
||||
return fullscreen_;
|
||||
}
|
||||
bool SDL2Window::fullscreen() const { return fullscreen_; }
|
||||
|
||||
bool SDL2Window::vsync() const {
|
||||
return vsync_;
|
||||
}
|
||||
bool SDL2Window::vsync() const { return vsync_; }
|
||||
|
||||
bool SDL2Window::focused() const {
|
||||
return focused_;
|
||||
}
|
||||
bool SDL2Window::focused() const { return focused_; }
|
||||
|
||||
bool SDL2Window::minimized() const {
|
||||
return minimized_;
|
||||
}
|
||||
bool SDL2Window::minimized() const { return minimized_; }
|
||||
|
||||
float SDL2Window::scaleX() const {
|
||||
return scaleX_;
|
||||
}
|
||||
float SDL2Window::scaleX() const { return scaleX_; }
|
||||
|
||||
float SDL2Window::scaleY() const {
|
||||
return scaleY_;
|
||||
}
|
||||
float SDL2Window::scaleY() const { return scaleY_; }
|
||||
|
||||
void SDL2Window::setCursor(Cursor cursor) {
|
||||
#ifndef __SWITCH__
|
||||
|
|
@ -277,25 +255,15 @@ void SDL2Window::lockCursor(bool lock) {
|
|||
#endif
|
||||
}
|
||||
|
||||
IInput* SDL2Window::input() const {
|
||||
return input_.get();
|
||||
}
|
||||
IInput *SDL2Window::input() const { return input_.get(); }
|
||||
|
||||
void SDL2Window::onResize(ResizeCb cb) {
|
||||
resizeCb_ = cb;
|
||||
}
|
||||
void SDL2Window::onResize(ResizeCb cb) { resizeCb_ = cb; }
|
||||
|
||||
void SDL2Window::onClose(CloseCb cb) {
|
||||
closeCb_ = cb;
|
||||
}
|
||||
void SDL2Window::onClose(CloseCb cb) { closeCb_ = cb; }
|
||||
|
||||
void SDL2Window::onFocus(FocusCb cb) {
|
||||
focusCb_ = cb;
|
||||
}
|
||||
void SDL2Window::onFocus(FocusCb cb) { focusCb_ = cb; }
|
||||
|
||||
void* SDL2Window::native() const {
|
||||
return sdlWindow_;
|
||||
}
|
||||
void *SDL2Window::native() const { return sdlWindow_; }
|
||||
|
||||
bool SDL2Window::initSDL() {
|
||||
static int sdlInitCount = 0;
|
||||
|
|
@ -349,7 +317,7 @@ void SDL2Window::updateContentScale() {
|
|||
}
|
||||
}
|
||||
|
||||
void SDL2Window::handleEvent(const SDL_Event& event) {
|
||||
void SDL2Window::handleEvent(const SDL_Event &event) {
|
||||
if (input_) {
|
||||
input_->handleSDLEvent(event);
|
||||
}
|
||||
|
|
@ -357,7 +325,8 @@ void SDL2Window::handleEvent(const SDL_Event& event) {
|
|||
switch (event.type) {
|
||||
case SDL_QUIT:
|
||||
shouldClose_ = true;
|
||||
if (closeCb_) closeCb_();
|
||||
if (closeCb_)
|
||||
closeCb_();
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT:
|
||||
|
|
@ -367,17 +336,20 @@ void SDL2Window::handleEvent(const SDL_Event& event) {
|
|||
width_ = event.window.data1;
|
||||
height_ = event.window.data2;
|
||||
updateContentScale();
|
||||
if (resizeCb_) resizeCb_(width_, height_);
|
||||
if (resizeCb_)
|
||||
resizeCb_(width_, height_);
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
||||
focused_ = true;
|
||||
if (focusCb_) focusCb_(true);
|
||||
if (focusCb_)
|
||||
focusCb_(true);
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||
focused_ = false;
|
||||
if (focusCb_) focusCb_(false);
|
||||
if (focusCb_)
|
||||
focusCb_(false);
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_MINIMIZED:
|
||||
|
|
@ -390,11 +362,12 @@ void SDL2Window::handleEvent(const SDL_Event& event) {
|
|||
|
||||
case SDL_WINDOWEVENT_CLOSE:
|
||||
shouldClose_ = true;
|
||||
if (closeCb_) closeCb_();
|
||||
if (closeCb_)
|
||||
closeCb_();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace extra2d
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include <extra2d/platform/window_module.h>
|
||||
#include <extra2d/platform/backend_factory.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__
|
||||
#include <switch.h>
|
||||
|
|
@ -16,9 +16,9 @@ void initSDL2Backend();
|
|||
#elif defined(E2D_BACKEND_GLFW)
|
||||
void initGLFWBackend();
|
||||
#endif
|
||||
}
|
||||
} // namespace platform
|
||||
|
||||
WindowModule::WindowModule(std::function<void(WindowCfg&)> configFn) {
|
||||
WindowModule::WindowModule(std::function<void(WindowCfg &)> configFn) {
|
||||
configFn(cfg_);
|
||||
}
|
||||
|
||||
|
|
@ -29,7 +29,8 @@ WindowModule::~WindowModule() {
|
|||
}
|
||||
|
||||
bool WindowModule::init() {
|
||||
if (initialized_) return true;
|
||||
if (initialized_)
|
||||
return true;
|
||||
|
||||
// 初始化后端(注册到工厂)
|
||||
#if defined(E2D_BACKEND_SDL2)
|
||||
|
|
@ -37,7 +38,7 @@ bool WindowModule::init() {
|
|||
#elif defined(E2D_BACKEND_GLFW)
|
||||
platform::initGLFWBackend();
|
||||
#else
|
||||
#error "No window backend defined"
|
||||
#error "No window backend defined"
|
||||
#endif
|
||||
|
||||
E2D_LOG_INFO("Window backend initialized");
|
||||
|
|
@ -63,7 +64,8 @@ bool WindowModule::init() {
|
|||
}
|
||||
|
||||
void WindowModule::shutdown() {
|
||||
if (!initialized_) return;
|
||||
if (!initialized_)
|
||||
return;
|
||||
|
||||
if (win_) {
|
||||
win_->destroy();
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/core/render_command.h>
|
||||
#include <extra2d/scene/node.h>
|
||||
#include <extra2d/scene/scene.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/graphics/core/render_command.h>
|
||||
#include <extra2d/scene/scene.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include <algorithm>
|
||||
#include <extra2d/app/application.h>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/graphics/core/render_command.h>
|
||||
#include <extra2d/platform/iinput.h>
|
||||
|
|
@ -10,7 +11,8 @@
|
|||
#include <extra2d/scene/transition_scale_scene.h>
|
||||
#include <extra2d/scene/transition_scene.h>
|
||||
#include <extra2d/scene/transition_slide_scene.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
@ -748,7 +750,8 @@ void SceneManager::finishTransition() {
|
|||
*/
|
||||
void SceneManager::dispatchPointerEvents(Scene &scene) {
|
||||
auto *input = Application::get().input();
|
||||
if (!input) return;
|
||||
if (!input)
|
||||
return;
|
||||
Vec2 screenPos = input->mouse();
|
||||
|
||||
Vec2 worldPos = screenPos;
|
||||
|
|
@ -832,7 +835,6 @@ void SceneManager::dispatchPointerEvents(Scene &scene) {
|
|||
lastPointerWorld_ = worldPos;
|
||||
}
|
||||
|
||||
void SceneManager::doSceneSwitch() {
|
||||
}
|
||||
void SceneManager::doSceneSwitch() {}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#include <extra2d/scene/transition_fade_scene.h>
|
||||
#include <extra2d/app/application.h>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
#include <extra2d/utils/logger.h>
|
||||
#include <algorithm>
|
||||
#include <extra2d/scene/transition_fade_scene.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
namespace extra2d {
|
||||
|
|
|
|||
|
|
@ -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/utils/logger.h>
|
||||
#include <extra2d/scene/transition_scene.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue