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