feat: 添加并行模块初始化支持并优化日志本地化
refactor(registry): 重构模块初始化逻辑以支持并行初始化 style: 统一日志消息为中文并优化格式 fix: 修复着色器元数据处理和默认值应用问题
This commit is contained in:
parent
463965439e
commit
e9bd44b63e
|
|
@ -52,6 +52,12 @@ public:
|
|||
*/
|
||||
virtual std::vector<std::type_index> deps() const { return {}; }
|
||||
|
||||
/**
|
||||
* @brief 检查模块是否支持并行初始化
|
||||
* @return 支持并行初始化返回 true
|
||||
*/
|
||||
virtual bool allowParallelInit() const { return true; }
|
||||
|
||||
/**
|
||||
* @brief 设置所属Application
|
||||
* @param app Application指针
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <typeindex>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <future>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
@ -79,7 +80,7 @@ public:
|
|||
void setApp(Application* app) { app_ = app; }
|
||||
|
||||
/**
|
||||
* @brief 初始化所有模块(按优先级拓扑排序)
|
||||
* @brief 初始化所有模块(按优先级拓扑排序,支持并行初始化)
|
||||
* @return 初始化成功返回 true
|
||||
*/
|
||||
bool init();
|
||||
|
|
@ -109,6 +110,13 @@ private:
|
|||
*/
|
||||
std::vector<Module*> topologicalSort();
|
||||
|
||||
/**
|
||||
* @brief 按层级对模块进行分组
|
||||
* 同一层级的模块没有相互依赖,可以并行初始化
|
||||
* @return 按层级分组的模块列表
|
||||
*/
|
||||
std::vector<std::vector<Module*>> groupByLevel();
|
||||
|
||||
std::unordered_map<std::type_index, UniquePtr<Module>> modules_;
|
||||
Application* app_ = nullptr;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -58,6 +58,13 @@ public:
|
|||
return {std::type_index(typeid(WindowModule))};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 是否允许并行初始化
|
||||
* RenderModule 需要 OpenGL 上下文,必须在主线程初始化
|
||||
* @return 不允许并行初始化返回 false
|
||||
*/
|
||||
bool allowParallelInit() const override { return false; }
|
||||
|
||||
/**
|
||||
* @brief 获取渲染器
|
||||
* @return 渲染后端指针
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/types.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
|
@ -18,17 +20,88 @@ struct ShaderLoadResult {
|
|||
std::vector<std::string> dependencies;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Shader Uniform 定义
|
||||
// ============================================================================
|
||||
struct ShaderUniformDef {
|
||||
std::string type;
|
||||
std::string description;
|
||||
float defaultValue = 0.0f; // 默认值(用于float类型)
|
||||
float defaultVec4[4] = {0, 0, 0, 0}; // 默认值(用于vec4类型)
|
||||
float defaultMat4[16] = {
|
||||
1, 0, 0, 0, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 1}; // 默认值(用于mat4类型,默认单位矩阵)
|
||||
int defaultInt = 0; // 默认值(用于int类型)
|
||||
bool defaultBool = false; // 默认值(用于bool类型)
|
||||
bool hasDefault = false; // 是否有默认值
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Shader Uniform 值类型
|
||||
// ============================================================================
|
||||
struct ShaderUniformValue {
|
||||
enum class Type { Float, Int, Bool, Vec2, Vec3, Vec4, Mat4 } type;
|
||||
|
||||
union {
|
||||
float f[16]; // 足够存储 mat4
|
||||
int i;
|
||||
bool b;
|
||||
} data;
|
||||
|
||||
// 构造函数
|
||||
ShaderUniformValue() : type(Type::Float) { data.f[0] = 0; }
|
||||
ShaderUniformValue(float v) : type(Type::Float) { data.f[0] = v; }
|
||||
ShaderUniformValue(int v) : type(Type::Int) { data.i = v; }
|
||||
ShaderUniformValue(bool v) : type(Type::Bool) { data.b = v; }
|
||||
ShaderUniformValue(const glm::vec2 &v) : type(Type::Vec2) {
|
||||
data.f[0] = v.x;
|
||||
data.f[1] = v.y;
|
||||
}
|
||||
ShaderUniformValue(const glm::vec3 &v) : type(Type::Vec3) {
|
||||
data.f[0] = v.x;
|
||||
data.f[1] = v.y;
|
||||
data.f[2] = v.z;
|
||||
}
|
||||
ShaderUniformValue(const glm::vec4 &v) : type(Type::Vec4) {
|
||||
data.f[0] = v.x;
|
||||
data.f[1] = v.y;
|
||||
data.f[2] = v.z;
|
||||
data.f[3] = v.w;
|
||||
}
|
||||
ShaderUniformValue(const glm::mat4 &m) : type(Type::Mat4) {
|
||||
const float *ptr = glm::value_ptr(m);
|
||||
for (int i = 0; i < 16; ++i)
|
||||
data.f[i] = ptr[i];
|
||||
}
|
||||
};
|
||||
|
||||
// Uniform 值映射表
|
||||
using UniformValueMap = std::unordered_map<std::string, ShaderUniformValue>;
|
||||
|
||||
// ============================================================================
|
||||
// Shader Sampler 定义
|
||||
// ============================================================================
|
||||
struct ShaderSamplerDef {
|
||||
std::string type;
|
||||
std::string description;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Shader元数据
|
||||
// ============================================================================
|
||||
struct ShaderMetadata {
|
||||
std::string name;
|
||||
std::string category;
|
||||
std::string version;
|
||||
std::string description;
|
||||
std::string vertPath;
|
||||
std::string fragPath;
|
||||
std::string combinedPath;
|
||||
uint64_t lastModified = 0;
|
||||
std::vector<std::string> defines;
|
||||
std::unordered_map<std::string, std::string> uniforms;
|
||||
std::unordered_map<std::string, ShaderUniformDef> uniformDefs;
|
||||
std::unordered_map<std::string, ShaderSamplerDef> samplerDefs;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -45,17 +118,16 @@ public:
|
|||
* @param fragPath 片段着色器文件路径
|
||||
* @return 加载结果
|
||||
*/
|
||||
virtual ShaderLoadResult loadFromSeparateFiles(
|
||||
const std::string& name,
|
||||
const std::string& vertPath,
|
||||
const std::string& fragPath) = 0;
|
||||
virtual ShaderLoadResult
|
||||
loadFromSeparateFiles(const std::string &name, const std::string &vertPath,
|
||||
const std::string &fragPath) = 0;
|
||||
|
||||
/**
|
||||
* @brief 从组合文件加载Shader (.shader)
|
||||
* @param path 组合Shader文件路径
|
||||
* @return 加载结果
|
||||
*/
|
||||
virtual ShaderLoadResult loadFromCombinedFile(const std::string& path) = 0;
|
||||
virtual ShaderLoadResult loadFromCombinedFile(const std::string &path) = 0;
|
||||
|
||||
/**
|
||||
* @brief 从源码字符串加载Shader
|
||||
|
|
@ -63,9 +135,8 @@ public:
|
|||
* @param fragSource 片段着色器源码
|
||||
* @return 加载结果
|
||||
*/
|
||||
virtual ShaderLoadResult loadFromSource(
|
||||
const std::string& vertSource,
|
||||
const std::string& fragSource) = 0;
|
||||
virtual ShaderLoadResult loadFromSource(const std::string &vertSource,
|
||||
const std::string &fragSource) = 0;
|
||||
|
||||
/**
|
||||
* @brief 处理Shader源码中的#include指令
|
||||
|
|
@ -74,10 +145,9 @@ public:
|
|||
* @param outDependencies 输出依赖列表
|
||||
* @return 处理后的源码
|
||||
*/
|
||||
virtual std::string processIncludes(
|
||||
const std::string& source,
|
||||
const std::string& baseDir,
|
||||
std::vector<std::string>& outDependencies) = 0;
|
||||
virtual std::string
|
||||
processIncludes(const std::string &source, const std::string &baseDir,
|
||||
std::vector<std::string> &outDependencies) = 0;
|
||||
|
||||
/**
|
||||
* @brief 应用预处理器定义
|
||||
|
|
@ -85,16 +155,15 @@ public:
|
|||
* @param defines 预处理器定义列表
|
||||
* @return 处理后的源码
|
||||
*/
|
||||
virtual std::string applyDefines(
|
||||
const std::string& source,
|
||||
const std::vector<std::string>& defines) = 0;
|
||||
virtual std::string applyDefines(const std::string &source,
|
||||
const std::vector<std::string> &defines) = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取Shader元数据
|
||||
* @param path Shader文件路径
|
||||
* @return 元数据
|
||||
*/
|
||||
virtual ShaderMetadata getMetadata(const std::string& path) = 0;
|
||||
virtual ShaderMetadata getMetadata(const std::string &path) = 0;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -112,17 +181,16 @@ public:
|
|||
* @param fragPath 片段着色器文件路径
|
||||
* @return 加载结果
|
||||
*/
|
||||
ShaderLoadResult loadFromSeparateFiles(
|
||||
const std::string& name,
|
||||
const std::string& vertPath,
|
||||
const std::string& fragPath) override;
|
||||
ShaderLoadResult loadFromSeparateFiles(const std::string &name,
|
||||
const std::string &vertPath,
|
||||
const std::string &fragPath) override;
|
||||
|
||||
/**
|
||||
* @brief 从组合文件加载Shader (.shader)
|
||||
* @param path 组合Shader文件路径
|
||||
* @return 加载结果
|
||||
*/
|
||||
ShaderLoadResult loadFromCombinedFile(const std::string& path) override;
|
||||
ShaderLoadResult loadFromCombinedFile(const std::string &path) override;
|
||||
|
||||
/**
|
||||
* @brief 从源码字符串加载Shader
|
||||
|
|
@ -130,9 +198,8 @@ public:
|
|||
* @param fragSource 片段着色器源码
|
||||
* @return 加载结果
|
||||
*/
|
||||
ShaderLoadResult loadFromSource(
|
||||
const std::string& vertSource,
|
||||
const std::string& fragSource) override;
|
||||
ShaderLoadResult loadFromSource(const std::string &vertSource,
|
||||
const std::string &fragSource) override;
|
||||
|
||||
/**
|
||||
* @brief 处理Shader源码中的#include指令
|
||||
|
|
@ -141,10 +208,9 @@ public:
|
|||
* @param outDependencies 输出依赖列表
|
||||
* @return 处理后的源码
|
||||
*/
|
||||
std::string processIncludes(
|
||||
const std::string& source,
|
||||
const std::string& baseDir,
|
||||
std::vector<std::string>& outDependencies) override;
|
||||
std::string
|
||||
processIncludes(const std::string &source, const std::string &baseDir,
|
||||
std::vector<std::string> &outDependencies) override;
|
||||
|
||||
/**
|
||||
* @brief 应用预处理器定义
|
||||
|
|
@ -152,43 +218,42 @@ public:
|
|||
* @param defines 预处理器定义列表
|
||||
* @return 处理后的源码
|
||||
*/
|
||||
std::string applyDefines(
|
||||
const std::string& source,
|
||||
const std::vector<std::string>& defines) override;
|
||||
std::string applyDefines(const std::string &source,
|
||||
const std::vector<std::string> &defines) override;
|
||||
|
||||
/**
|
||||
* @brief 获取Shader元数据
|
||||
* @param path Shader文件路径
|
||||
* @return 元数据
|
||||
*/
|
||||
ShaderMetadata getMetadata(const std::string& path) override;
|
||||
ShaderMetadata getMetadata(const std::string &path) override;
|
||||
|
||||
/**
|
||||
* @brief 添加include搜索路径
|
||||
* @param path 搜索路径
|
||||
*/
|
||||
void addIncludePath(const std::string& path);
|
||||
void addIncludePath(const std::string &path);
|
||||
|
||||
/**
|
||||
* @brief 读取文件内容
|
||||
* @param filepath 文件路径
|
||||
* @return 文件内容字符串
|
||||
*/
|
||||
static std::string readFile(const std::string& filepath);
|
||||
static std::string readFile(const std::string &filepath);
|
||||
|
||||
/**
|
||||
* @brief 获取文件修改时间
|
||||
* @param filepath 文件路径
|
||||
* @return 修改时间戳
|
||||
*/
|
||||
static uint64_t getFileModifiedTime(const std::string& filepath);
|
||||
static uint64_t getFileModifiedTime(const std::string &filepath);
|
||||
|
||||
/**
|
||||
* @brief 检查文件是否存在
|
||||
* @param filepath 文件路径
|
||||
* @return 存在返回true,否则返回false
|
||||
*/
|
||||
static bool fileExists(const std::string& filepath);
|
||||
static bool fileExists(const std::string &filepath);
|
||||
|
||||
private:
|
||||
std::vector<std::string> includePaths_;
|
||||
|
|
@ -202,10 +267,8 @@ private:
|
|||
* @param outMetadata 输出元数据
|
||||
* @return 解析成功返回true,失败返回false
|
||||
*/
|
||||
bool parseCombinedFile(const std::string& content,
|
||||
std::string& outVert,
|
||||
std::string& outFrag,
|
||||
ShaderMetadata& outMetadata);
|
||||
bool parseCombinedFile(const std::string &content, std::string &outVert,
|
||||
std::string &outFrag, ShaderMetadata &outMetadata);
|
||||
|
||||
/**
|
||||
* @brief 解析元数据JSON块
|
||||
|
|
@ -213,7 +276,8 @@ private:
|
|||
* @param outMetadata 输出元数据
|
||||
* @return 解析成功返回true,失败返回false
|
||||
*/
|
||||
bool parseMetadata(const std::string& jsonContent, ShaderMetadata& outMetadata);
|
||||
bool parseMetadata(const std::string &jsonContent,
|
||||
ShaderMetadata &outMetadata);
|
||||
|
||||
/**
|
||||
* @brief 查找include文件路径
|
||||
|
|
@ -221,7 +285,8 @@ private:
|
|||
* @param baseDir 基础目录
|
||||
* @return 找到的完整路径,未找到返回空字符串
|
||||
*/
|
||||
std::string findIncludeFile(const std::string& includeName, const std::string& baseDir);
|
||||
std::string findIncludeFile(const std::string &includeName,
|
||||
const std::string &baseDir);
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
|
|||
|
|
@ -201,6 +201,44 @@ public:
|
|||
*/
|
||||
ShaderLoader& getLoader() { return loader_; }
|
||||
|
||||
/**
|
||||
* @brief 获取Shader元数据
|
||||
* @param name Shader名称
|
||||
* @return Shader元数据,不存在返回空元数据
|
||||
*/
|
||||
ShaderMetadata getMetadata(const std::string& name) const;
|
||||
|
||||
/**
|
||||
* @brief 获取Shader的uniform定义
|
||||
* @param name Shader名称
|
||||
* @return uniform定义映射,不存在返回空映射
|
||||
*/
|
||||
std::unordered_map<std::string, ShaderUniformDef> getUniformDefs(const std::string& name) const;
|
||||
|
||||
/**
|
||||
* @brief 获取Shader的sampler定义
|
||||
* @param name Shader名称
|
||||
* @return sampler定义映射,不存在返回空映射
|
||||
*/
|
||||
std::unordered_map<std::string, ShaderSamplerDef> getSamplerDefs(const std::string& name) const;
|
||||
|
||||
/**
|
||||
* @brief 自动应用uniform值到着色器
|
||||
* 根据JSON元数据中的uniform定义,自动设置对应的uniform值
|
||||
* @param shader 目标着色器
|
||||
* @param shaderName Shader名称(用于查找元数据)
|
||||
* @param values uniform值映射表
|
||||
*/
|
||||
void applyUniforms(Ptr<IShader> shader, const std::string& shaderName, const UniformValueMap& values);
|
||||
|
||||
/**
|
||||
* @brief 自动应用sampler绑定到着色器
|
||||
* 根据JSON元数据中的sampler定义,自动设置对应的纹理单元
|
||||
* @param shader 目标着色器
|
||||
* @param shaderName Shader名称(用于查找元数据)
|
||||
*/
|
||||
void applySamplers(Ptr<IShader> shader, const std::string& shaderName);
|
||||
|
||||
private:
|
||||
ShaderManager() = default;
|
||||
~ShaderManager() = default;
|
||||
|
|
@ -239,11 +277,6 @@ private:
|
|||
const std::string& vertSource,
|
||||
const std::string& fragSource);
|
||||
|
||||
/**
|
||||
* @brief 创建内置Shader源码
|
||||
*/
|
||||
void createBuiltinShaderSources();
|
||||
|
||||
/**
|
||||
* @brief 处理文件变化事件
|
||||
* @param shaderName Shader名称
|
||||
|
|
|
|||
|
|
@ -4,7 +4,28 @@
|
|||
"version": "1.0",
|
||||
"description": "基本形状渲染Shader",
|
||||
"uniforms": {
|
||||
"u_viewProjection": { "type": "mat4", "description": "视图投影矩阵" }
|
||||
"u_viewProjection": {
|
||||
"type": "mat4",
|
||||
"default": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"description": "视图投影矩阵"
|
||||
}
|
||||
},
|
||||
"samplers": {},
|
||||
"backends": {
|
||||
|
|
|
|||
|
|
@ -4,12 +4,61 @@
|
|||
"version": "1.0",
|
||||
"description": "标准2D精灵渲染Shader",
|
||||
"uniforms": {
|
||||
"u_viewProjection": { "type": "mat4", "description": "视图投影矩阵" },
|
||||
"u_model": { "type": "mat4", "description": "模型矩阵" },
|
||||
"u_opacity": { "type": "float", "default": 1.0, "description": "透明度" }
|
||||
"u_viewProjection": {
|
||||
"type": "mat4",
|
||||
"default": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"description": "视图投影矩阵"
|
||||
},
|
||||
"u_model": {
|
||||
"type": "mat4",
|
||||
"default": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"description": "模型矩阵"
|
||||
},
|
||||
"u_opacity": {
|
||||
"type": "float",
|
||||
"default": 1.0,
|
||||
"description": "透明度"
|
||||
}
|
||||
},
|
||||
"samplers": {
|
||||
"u_texture": { "binding": 0, "description": "纹理采样器" }
|
||||
"u_texture": {
|
||||
"binding": 0,
|
||||
"description": "纹理采样器"
|
||||
}
|
||||
},
|
||||
"backends": {
|
||||
"opengl": {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include <extra2d/core/registry.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
#include <future>
|
||||
#include <queue>
|
||||
|
||||
namespace extra2d {
|
||||
|
|
@ -10,19 +11,79 @@ Registry &Registry::instance() {
|
|||
}
|
||||
|
||||
bool Registry::init() {
|
||||
auto sorted = topologicalSort();
|
||||
E2D_REGISTRY("Initializing {} modules...", sorted.size());
|
||||
auto levels = groupByLevel();
|
||||
E2D_REGISTRY("正在初始化 {} 个模块,共 {} 个层级...", modules_.size(),
|
||||
levels.size());
|
||||
|
||||
for (size_t level = 0; level < levels.size(); ++level) {
|
||||
auto &modules = levels[level];
|
||||
|
||||
// 检查当前层级是否有支持并行初始化的模块
|
||||
bool hasParallelModules = false;
|
||||
for (auto *module : modules) {
|
||||
if (module->allowParallelInit()) {
|
||||
hasParallelModules = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果只有一个模块或不支持并行,使用串行初始化
|
||||
if (modules.size() <= 1 || !hasParallelModules) {
|
||||
for (auto *module : modules) {
|
||||
E2D_REGISTRY("正在初始化模块: {} (层级 {})", module->name(), level);
|
||||
|
||||
for (auto *module : sorted) {
|
||||
E2D_REGISTRY("Initializing module: {}", module->name());
|
||||
if (!module->init()) {
|
||||
E2D_ERROR("Failed to initialize module: {}", module->name());
|
||||
E2D_ERROR("初始化模块失败: {}", module->name());
|
||||
return false;
|
||||
}
|
||||
E2D_REGISTRY("Module {} initialized successfully", module->name());
|
||||
|
||||
E2D_REGISTRY("模块 {} 初始化成功", module->name());
|
||||
}
|
||||
} else {
|
||||
// 并行初始化当前层级的模块
|
||||
E2D_REGISTRY("正在并行初始化 {} 个模块 (层级 {})...", modules.size(),
|
||||
level);
|
||||
|
||||
std::vector<std::future<std::pair<Module *, bool>>> futures;
|
||||
std::vector<Module *> serialModules;
|
||||
|
||||
// 分离支持并行和不支持并行的模块
|
||||
for (auto *module : modules) {
|
||||
if (module->allowParallelInit()) {
|
||||
futures.push_back(std::async(std::launch::async, [module]() {
|
||||
return std::make_pair(module, module->init());
|
||||
}));
|
||||
} else {
|
||||
serialModules.push_back(module);
|
||||
}
|
||||
}
|
||||
|
||||
E2D_REGISTRY("All modules initialized");
|
||||
// 等待并行模块完成
|
||||
for (auto &future : futures) {
|
||||
auto [module, success] = future.get();
|
||||
if (!success) {
|
||||
E2D_ERROR("初始化模块失败: {}", module->name());
|
||||
return false;
|
||||
}
|
||||
E2D_REGISTRY("模块 {} 初始化成功 (并行)", module->name());
|
||||
}
|
||||
|
||||
// 串行初始化不支持并行的模块
|
||||
for (auto *module : serialModules) {
|
||||
E2D_REGISTRY("正在初始化模块: {} (串行, 层级 {})", module->name(),
|
||||
level);
|
||||
if (!module->init()) {
|
||||
E2D_ERROR("初始化模块失败: {}", module->name());
|
||||
return false;
|
||||
}
|
||||
E2D_REGISTRY("模块 {} 初始化成功", module->name());
|
||||
}
|
||||
}
|
||||
|
||||
E2D_REGISTRY("层级 {} 初始化完成", level);
|
||||
}
|
||||
|
||||
E2D_REGISTRY("所有模块初始化完成");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -83,4 +144,63 @@ std::vector<Module *> Registry::topologicalSort() {
|
|||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::vector<Module *>> Registry::groupByLevel() {
|
||||
std::vector<std::vector<Module *>> levels;
|
||||
std::unordered_map<Module *, int> inDegree;
|
||||
std::unordered_map<Module *, std::vector<Module *>> adj;
|
||||
std::unordered_map<Module *, int> levelMap;
|
||||
|
||||
// 初始化入度
|
||||
for (auto &[typeIdx, module] : modules_) {
|
||||
inDegree[module.get()] = 0;
|
||||
}
|
||||
|
||||
// 构建依赖图
|
||||
for (auto &[typeIdx, module] : modules_) {
|
||||
for (auto &depType : module->deps()) {
|
||||
Module *dep = get(depType);
|
||||
if (dep) {
|
||||
adj[dep].push_back(module.get());
|
||||
inDegree[module.get()]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 使用 BFS 按层级分组
|
||||
std::queue<Module *> q;
|
||||
|
||||
// 找到所有入度为 0 的模块(第一层)
|
||||
for (auto &[mod, degree] : inDegree) {
|
||||
if (degree == 0) {
|
||||
q.push(mod);
|
||||
levelMap[mod] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// BFS 遍历
|
||||
while (!q.empty()) {
|
||||
Module *curr = q.front();
|
||||
q.pop();
|
||||
|
||||
int currLevel = levelMap[curr];
|
||||
|
||||
// 确保当前层级存在
|
||||
if (levels.size() <= static_cast<size_t>(currLevel)) {
|
||||
levels.resize(currLevel + 1);
|
||||
}
|
||||
levels[currLevel].push_back(curr);
|
||||
|
||||
// 处理依赖当前模块的其他模块
|
||||
for (Module *next : adj[curr]) {
|
||||
inDegree[next]--;
|
||||
if (inDegree[next] == 0) {
|
||||
q.push(next);
|
||||
levelMap[next] = currLevel + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return levels;
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ BackendFactory::registry() {
|
|||
void BackendFactory::reg(const std::string &name, BackendFn backend,
|
||||
const std::vector<std::string> &windowBackends) {
|
||||
registry()[name] = {backend, windowBackends};
|
||||
E2D_LOG_DEBUG("Registered graphics backend: {} (window backends: {})", name,
|
||||
E2D_LOG_DEBUG("已注册图形后端: {} (窗口后端数量: {})", name,
|
||||
windowBackends.size());
|
||||
}
|
||||
|
||||
|
|
@ -23,17 +23,17 @@ BackendFactory::createBackend(const std::string &name) {
|
|||
auto ® = registry();
|
||||
auto it = reg.find(name);
|
||||
if (it != reg.end() && it->second.createFn) {
|
||||
E2D_LOG_INFO("Creating graphics backend: {}", name);
|
||||
E2D_LOG_INFO("正在创建图形后端: {}", name);
|
||||
return it->second.createFn();
|
||||
}
|
||||
E2D_LOG_ERROR("Graphics backend '{}' not found", name);
|
||||
E2D_LOG_ERROR("未找到图形后端 '{}'", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UniquePtr<RenderBackend> BackendFactory::createDefaultBackend() {
|
||||
std::string recommended = getRecommendedBackend();
|
||||
if (recommended.empty()) {
|
||||
E2D_LOG_ERROR("No graphics backend available");
|
||||
E2D_LOG_ERROR("无可用的图形后端");
|
||||
return nullptr;
|
||||
}
|
||||
return createBackend(recommended);
|
||||
|
|
@ -43,8 +43,7 @@ UniquePtr<RenderBackend>
|
|||
BackendFactory::createBackendForWindow(const std::string &windowBackend) {
|
||||
std::string recommended = getRecommendedBackendForWindow(windowBackend);
|
||||
if (recommended.empty()) {
|
||||
E2D_LOG_ERROR("No compatible graphics backend for window backend: {}",
|
||||
windowBackend);
|
||||
E2D_LOG_ERROR("未找到与窗口后端 '{}' 兼容的图形后端", windowBackend);
|
||||
return nullptr;
|
||||
}
|
||||
return createBackend(recommended);
|
||||
|
|
@ -78,7 +77,7 @@ std::string BackendFactory::getRecommendedBackend() {
|
|||
return reg.begin()->first;
|
||||
}
|
||||
|
||||
E2D_LOG_WARN("No graphics backend registered");
|
||||
E2D_LOG_WARN("未注册任何图形后端");
|
||||
return "";
|
||||
}
|
||||
|
||||
|
|
@ -102,8 +101,7 @@ std::string BackendFactory::getRecommendedBackendForWindow(
|
|||
}
|
||||
}
|
||||
|
||||
E2D_LOG_WARN("No compatible graphics backend for window backend: {}",
|
||||
windowBackend);
|
||||
E2D_LOG_WARN("未找到与窗口后端 '{}' 兼容的图形后端", windowBackend);
|
||||
return "";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ bool GLBuffer::init(const BufferDesc &desc) {
|
|||
// 生成缓冲区
|
||||
glGenBuffers(1, &bufferID_);
|
||||
if (bufferID_ == 0) {
|
||||
E2D_LOG_ERROR("Failed to generate OpenGL buffer");
|
||||
E2D_LOG_ERROR("生成 OpenGL 缓冲区失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ bool GLBuffer::init(const BufferDesc &desc) {
|
|||
// 追踪显存使用
|
||||
VRAMMgr::get().allocBuffer(size_);
|
||||
|
||||
E2D_LOG_DEBUG("GLBuffer created: ID={}, Size={}, Type={}, Usage={}",
|
||||
E2D_LOG_DEBUG("GLBuffer 已创建: ID={}, 大小={}, 类型={}, 用途={}",
|
||||
bufferID_, size_, static_cast<int>(type_),
|
||||
static_cast<int>(usage_));
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ void GLBuffer::shutdown() {
|
|||
// 释放显存追踪
|
||||
VRAMMgr::get().freeBuffer(size_);
|
||||
glDeleteBuffers(1, &bufferID_);
|
||||
E2D_LOG_DEBUG("GLBuffer destroyed: ID={}", bufferID_);
|
||||
E2D_LOG_DEBUG("GLBuffer 已销毁: ID={}", bufferID_);
|
||||
bufferID_ = 0;
|
||||
}
|
||||
size_ = 0;
|
||||
|
|
@ -128,7 +128,7 @@ void *GLBuffer::map() {
|
|||
if (mappedPtr_) {
|
||||
mapped_ = true;
|
||||
} else {
|
||||
E2D_LOG_ERROR("Failed to map GLBuffer");
|
||||
E2D_LOG_ERROR("映射 GLBuffer 失败");
|
||||
}
|
||||
|
||||
return mappedPtr_;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ bool GLContext::init() {
|
|||
|
||||
// 加载扩展(GLAD 已在 glad.c 中完成)
|
||||
if (!loadExtensions()) {
|
||||
E2D_LOG_ERROR("Failed to load OpenGL extensions");
|
||||
E2D_LOG_ERROR("加载 OpenGL 扩展失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -33,12 +33,12 @@ bool GLContext::init() {
|
|||
// 标记 GPU 上下文为有效
|
||||
GPUContext::get().markValid();
|
||||
|
||||
E2D_LOG_INFO("OpenGL Context initialized");
|
||||
E2D_LOG_INFO(" Version: {}", getVersionString());
|
||||
E2D_LOG_INFO(" Vendor: {}", getVendor());
|
||||
E2D_LOG_INFO(" Renderer: {}", getRenderer());
|
||||
E2D_LOG_INFO(" Max Texture Size: {}", getMaxTextureSize());
|
||||
E2D_LOG_INFO(" Max Texture Units: {}", getMaxTextureUnits());
|
||||
E2D_LOG_INFO("OpenGL 上下文已初始化");
|
||||
E2D_LOG_INFO(" 版本: {}", getVersionString());
|
||||
E2D_LOG_INFO(" 供应商: {}", getVendor());
|
||||
E2D_LOG_INFO(" 渲染器: {}", getRenderer());
|
||||
E2D_LOG_INFO(" 最大纹理大小: {}", getMaxTextureSize());
|
||||
E2D_LOG_INFO(" 最大纹理单元数: {}", getMaxTextureUnits());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ GLFontAtlas::GLFontAtlas(const std::string &filepath, int fontSize, bool useSDF)
|
|||
|
||||
// 加载字体文件
|
||||
if (!initFont(filepath)) {
|
||||
E2D_LOG_ERROR("Failed to initialize font: {}", filepath);
|
||||
E2D_LOG_ERROR("初始化字体失败: {}", filepath);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ GLFontAtlas::GLFontAtlas(const std::string &filepath, int fontSize, bool useSDF)
|
|||
cacheGlyph(codepoint);
|
||||
}
|
||||
|
||||
E2D_LOG_INFO("Font atlas created: {} ({}px, {}x{})", filepath, fontSize_,
|
||||
E2D_LOG_INFO("字体图集已创建: {} ({}px, {}x{})", filepath, fontSize_,
|
||||
ATLAS_WIDTH, ATLAS_HEIGHT);
|
||||
}
|
||||
|
||||
|
|
@ -134,7 +134,7 @@ bool GLFontAtlas::initFont(const std::string &filepath) {
|
|||
// 读取字体文件到内存
|
||||
std::ifstream file(filepath, std::ios::binary | std::ios::ate);
|
||||
if (!file.is_open()) {
|
||||
E2D_LOG_ERROR("Failed to open font file: {}", filepath);
|
||||
E2D_LOG_ERROR("打开字体文件失败: {}", filepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -143,13 +143,13 @@ bool GLFontAtlas::initFont(const std::string &filepath) {
|
|||
|
||||
fontData_.resize(static_cast<size_t>(size));
|
||||
if (!file.read(reinterpret_cast<char *>(fontData_.data()), size)) {
|
||||
E2D_LOG_ERROR("Failed to read font file: {}", filepath);
|
||||
E2D_LOG_ERROR("读取字体文件失败: {}", filepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 初始化 STB 字体
|
||||
if (!stbtt_InitFont(&fontInfo_, fontData_.data(), 0)) {
|
||||
E2D_LOG_ERROR("Failed to initialize STB font: {}", filepath);
|
||||
E2D_LOG_ERROR("初始化 STB 字体失败: {}", filepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -224,7 +224,7 @@ void GLFontAtlas::cacheGlyph(char32_t codepoint) {
|
|||
|
||||
stbrp_pack_rects(&packContext_, &rect, 1);
|
||||
if (!rect.was_packed) {
|
||||
E2D_LOG_WARN("Font atlas is full, cannot cache codepoint: {}", codepoint);
|
||||
E2D_LOG_WARN("字体图集已满,无法缓存字符码点: {}", codepoint);
|
||||
stbtt_FreeSDF(sdf, nullptr);
|
||||
return;
|
||||
}
|
||||
|
|
@ -304,7 +304,7 @@ void GLFontAtlas::cacheGlyph(char32_t codepoint) {
|
|||
stbrp_pack_rects(&packContext_, &rect, 1);
|
||||
|
||||
if (!rect.was_packed) {
|
||||
E2D_LOG_WARN("Font atlas is full, cannot cache codepoint: {}", codepoint);
|
||||
E2D_LOG_WARN("字体图集已满,无法缓存字符码点: {}", codepoint);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,11 +33,11 @@ bool GLFramebuffer::init(const FramebufferDesc &desc) {
|
|||
// 生成 FBO
|
||||
glGenFramebuffers(1, &fboID_);
|
||||
if (fboID_ == 0) {
|
||||
E2D_LOG_ERROR("Failed to generate OpenGL framebuffer");
|
||||
E2D_LOG_ERROR("生成 OpenGL 帧缓冲区失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
E2D_LOG_DEBUG("GLFramebuffer created: ID={}, Size={}x{}, ColorAttachments={}",
|
||||
E2D_LOG_DEBUG("GLFramebuffer 已创建: ID={}, 大小={}x{}, 颜色附件={}",
|
||||
fboID_, width_, height_, numColorAttachments_);
|
||||
|
||||
return true;
|
||||
|
|
@ -46,7 +46,7 @@ bool GLFramebuffer::init(const FramebufferDesc &desc) {
|
|||
void GLFramebuffer::shutdown() {
|
||||
if (fboID_ != 0) {
|
||||
glDeleteFramebuffers(1, &fboID_);
|
||||
E2D_LOG_DEBUG("GLFramebuffer destroyed: ID={}", fboID_);
|
||||
E2D_LOG_DEBUG("GLFramebuffer 已销毁: ID={}", fboID_);
|
||||
fboID_ = 0;
|
||||
}
|
||||
|
||||
|
|
@ -234,31 +234,31 @@ bool GLFramebuffer::checkStatus() {
|
|||
case GL_FRAMEBUFFER_COMPLETE:
|
||||
return true;
|
||||
case GL_FRAMEBUFFER_UNDEFINED:
|
||||
E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_UNDEFINED");
|
||||
E2D_LOG_ERROR("帧缓冲区不完整: GL_FRAMEBUFFER_UNDEFINED");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||
E2D_LOG_ERROR(
|
||||
"Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
|
||||
"帧缓冲区不完整: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||
E2D_LOG_ERROR(
|
||||
"Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
|
||||
"帧缓冲区不完整: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
|
||||
break;
|
||||
#ifndef GL_ES_VERSION_2_0
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
|
||||
E2D_LOG_ERROR(
|
||||
"Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER");
|
||||
"帧缓冲区不完整: GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER");
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
|
||||
E2D_LOG_ERROR(
|
||||
"Framebuffer incomplete: GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER");
|
||||
"帧缓冲区不完整: GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER");
|
||||
break;
|
||||
#endif
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
E2D_LOG_ERROR("Framebuffer incomplete: GL_FRAMEBUFFER_UNSUPPORTED");
|
||||
E2D_LOG_ERROR("帧缓冲区不完整: GL_FRAMEBUFFER_UNSUPPORTED");
|
||||
break;
|
||||
default:
|
||||
E2D_LOG_ERROR("Framebuffer incomplete: Unknown error {}", status);
|
||||
E2D_LOG_ERROR("帧缓冲区不完整: 未知错误 {}", status);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,13 +51,13 @@ bool GLRenderer::init(IWindow *window) {
|
|||
// 初始化 OpenGL 上下文(Switch 平台已通过 SDL2 + EGL 初始化,GLContext
|
||||
// 会处理兼容性)
|
||||
if (!GLContext::get().init()) {
|
||||
E2D_LOG_ERROR("Failed to initialize OpenGL context");
|
||||
E2D_LOG_ERROR("初始化 OpenGL 上下文失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 初始化精灵批渲染器
|
||||
if (!spriteBatch_.init()) {
|
||||
E2D_LOG_ERROR("Failed to initialize sprite batch");
|
||||
E2D_LOG_ERROR("初始化精灵批处理失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ bool GLRenderer::init(IWindow *window) {
|
|||
pipelineDesc.depthTest = false;
|
||||
pipelineDesc.depthWrite = false;
|
||||
if (!pipeline_.init(pipelineDesc)) {
|
||||
E2D_LOG_ERROR("Failed to initialize GLPipeline");
|
||||
E2D_LOG_ERROR("初始化 GLPipeline 失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -80,8 +80,8 @@ bool GLRenderer::init(IWindow *window) {
|
|||
// 标记 GPU 上下文为有效
|
||||
GPUContext::get().markValid();
|
||||
|
||||
E2D_LOG_INFO("OpenGL Renderer initialized");
|
||||
E2D_LOG_INFO("OpenGL Version: {}", GLContext::get().getVersionString());
|
||||
E2D_LOG_INFO("OpenGL 渲染器初始化成功");
|
||||
E2D_LOG_INFO("OpenGL 版本: {}", GLContext::get().getVersionString());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -756,9 +756,9 @@ void GLRenderer::initShapeRendering() {
|
|||
// 从ShaderManager获取形状着色器
|
||||
shapeShader_ = ShaderManager::getInstance().getBuiltin("shape");
|
||||
if (!shapeShader_) {
|
||||
E2D_LOG_WARN("Failed to get builtin shape shader, loading from manager");
|
||||
E2D_LOG_WARN("获取内置形状着色器失败,尝试从管理器加载");
|
||||
if (!ShaderManager::getInstance().isInitialized()) {
|
||||
E2D_LOG_ERROR("ShaderManager not initialized, shape rendering may fail");
|
||||
E2D_LOG_ERROR("ShaderManager 未初始化,形状渲染可能失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -768,7 +768,7 @@ void GLRenderer::initShapeRendering() {
|
|||
shapeBufferDesc.usage = BufferUsage::Dynamic;
|
||||
shapeBufferDesc.size = MAX_SHAPE_VERTICES * sizeof(ShapeVertex);
|
||||
if (!shapeBuffer_.init(shapeBufferDesc)) {
|
||||
E2D_LOG_ERROR("Failed to initialize shape buffer");
|
||||
E2D_LOG_ERROR("初始化形状缓冲区失败");
|
||||
}
|
||||
|
||||
// 创建形状 VAO(手动管理,用于顶点属性配置)
|
||||
|
|
@ -794,7 +794,7 @@ void GLRenderer::initShapeRendering() {
|
|||
lineBufferDesc.usage = BufferUsage::Dynamic;
|
||||
lineBufferDesc.size = MAX_LINE_VERTICES * sizeof(ShapeVertex);
|
||||
if (!lineBuffer_.init(lineBufferDesc)) {
|
||||
E2D_LOG_ERROR("Failed to initialize line buffer");
|
||||
E2D_LOG_ERROR("初始化线条缓冲区失败");
|
||||
}
|
||||
|
||||
// 创建线条 VAO(手动管理,用于顶点属性配置)
|
||||
|
|
@ -889,7 +889,14 @@ void GLRenderer::flushShapeBatch() {
|
|||
|
||||
if (shapeShader_) {
|
||||
shapeShader_->bind();
|
||||
shapeShader_->setMat4("u_viewProjection", viewProjection_);
|
||||
|
||||
// 只提供需要动态计算的值,其他值使用JSON中定义的默认值
|
||||
UniformValueMap uniformValues;
|
||||
uniformValues["u_viewProjection"] = viewProjection_;
|
||||
|
||||
// 使用ShaderManager自动应用uniform值(未提供的值使用JSON中的默认值)
|
||||
// 使用着色器自己的名称(从JSON中解析的name字段)
|
||||
ShaderManager::getInstance().applyUniforms(shapeShader_, shapeShader_->getName(), uniformValues);
|
||||
}
|
||||
|
||||
// 使用 GLBuffer::updateData() 更新缓冲区数据
|
||||
|
|
@ -918,7 +925,14 @@ void GLRenderer::flushLineBatch() {
|
|||
glLineWidth(currentLineWidth_);
|
||||
if (shapeShader_) {
|
||||
shapeShader_->bind();
|
||||
shapeShader_->setMat4("u_viewProjection", viewProjection_);
|
||||
|
||||
// 只提供需要动态计算的值,其他值使用JSON中定义的默认值
|
||||
UniformValueMap uniformValues;
|
||||
uniformValues["u_viewProjection"] = viewProjection_;
|
||||
|
||||
// 使用ShaderManager自动应用uniform值(未提供的值使用JSON中的默认值)
|
||||
// 使用着色器自己的名称(从JSON中解析的name字段)
|
||||
ShaderManager::getInstance().applyUniforms(shapeShader_, shapeShader_->getName(), uniformValues);
|
||||
}
|
||||
|
||||
// 使用 GLBuffer::updateData() 更新缓冲区数据
|
||||
|
|
@ -941,7 +955,7 @@ void GLRenderer::flushLineBatch() {
|
|||
Ptr<GLFramebuffer> GLRenderer::createFramebuffer(const FramebufferDesc &desc) {
|
||||
auto framebuffer = makePtr<GLFramebuffer>();
|
||||
if (!framebuffer->init(desc)) {
|
||||
E2D_LOG_ERROR("Failed to create framebuffer");
|
||||
E2D_LOG_ERROR("创建帧缓冲区失败");
|
||||
return nullptr;
|
||||
}
|
||||
return framebuffer;
|
||||
|
|
@ -961,12 +975,12 @@ void GLRenderer::bindFramebuffer(GLFramebuffer *framebuffer) {
|
|||
// 绑定默认帧缓冲(ID 为 0)
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
currentFramebuffer_ = nullptr;
|
||||
E2D_LOG_TRACE("Bound default framebuffer (0)");
|
||||
E2D_LOG_TRACE("绑定默认帧缓冲区 (0)");
|
||||
} else {
|
||||
// 绑定自定义帧缓冲
|
||||
framebuffer->bind();
|
||||
currentFramebuffer_ = framebuffer;
|
||||
E2D_LOG_TRACE("Bound custom framebuffer (ID: {})", framebuffer->getFboID());
|
||||
E2D_LOG_TRACE("绑定自定义帧缓冲区 (ID: {})", framebuffer->getFboID());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ bool GLShader::compileFromSource(const char *vertexSource,
|
|||
if (!success) {
|
||||
char infoLog[512];
|
||||
glGetProgramInfoLog(programID_, 512, nullptr, infoLog);
|
||||
E2D_LOG_ERROR("Shader program linking failed: {}", infoLog);
|
||||
E2D_LOG_ERROR("着色器程序链接失败: {}", infoLog);
|
||||
glDeleteProgram(programID_);
|
||||
programID_ = 0;
|
||||
}
|
||||
|
|
@ -154,14 +154,14 @@ bool GLShader::compileFromSource(const char *vertexSource,
|
|||
*/
|
||||
bool GLShader::compileFromBinary(const std::vector<uint8_t> &binary) {
|
||||
if (binary.empty()) {
|
||||
E2D_LOG_ERROR("Binary data is empty");
|
||||
E2D_LOG_ERROR("二进制数据为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
GLint numFormats = 0;
|
||||
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numFormats);
|
||||
if (numFormats == 0) {
|
||||
E2D_LOG_ERROR("Program binary formats not supported");
|
||||
E2D_LOG_ERROR("不支持程序二进制格式");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -184,7 +184,7 @@ bool GLShader::compileFromBinary(const std::vector<uint8_t> &binary) {
|
|||
if (!success) {
|
||||
char infoLog[512];
|
||||
glGetProgramInfoLog(programID_, 512, nullptr, infoLog);
|
||||
E2D_LOG_ERROR("Failed to load shader from binary: {}", infoLog);
|
||||
E2D_LOG_ERROR("从二进制加载着色器失败: {}", infoLog);
|
||||
glDeleteProgram(programID_);
|
||||
programID_ = 0;
|
||||
return false;
|
||||
|
|
@ -200,17 +200,17 @@ bool GLShader::compileFromBinary(const std::vector<uint8_t> &binary) {
|
|||
*/
|
||||
bool GLShader::getBinary(std::vector<uint8_t> &outBinary) {
|
||||
if (programID_ == 0) {
|
||||
E2D_LOG_WARN("Cannot get binary: shader program is 0");
|
||||
E2D_LOG_WARN("无法获取二进制数据: 着色器程序为 0");
|
||||
return false;
|
||||
}
|
||||
|
||||
GLint binaryLength = 0;
|
||||
glGetProgramiv(programID_, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
|
||||
|
||||
E2D_LOG_DEBUG("Shader binary length: {}", binaryLength);
|
||||
E2D_LOG_DEBUG("着色器二进制数据长度: {}", binaryLength);
|
||||
|
||||
if (binaryLength <= 0) {
|
||||
E2D_LOG_WARN("Shader binary length is 0 or negative");
|
||||
E2D_LOG_WARN("着色器二进制数据长度为 0 或负数");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -223,13 +223,13 @@ bool GLShader::getBinary(std::vector<uint8_t> &outBinary) {
|
|||
|
||||
GLenum err = glGetError();
|
||||
if (err != GL_NO_ERROR) {
|
||||
E2D_LOG_ERROR("glGetProgramBinary failed with error: {}", err);
|
||||
E2D_LOG_ERROR("glGetProgramBinary 失败,错误码: {}", err);
|
||||
outBinary.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (actualLength == 0) {
|
||||
E2D_LOG_WARN("glGetProgramBinary returned 0 bytes");
|
||||
E2D_LOG_WARN("glGetProgramBinary 返回 0 字节");
|
||||
outBinary.clear();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -238,7 +238,7 @@ bool GLShader::getBinary(std::vector<uint8_t> &outBinary) {
|
|||
outBinary.resize(actualLength);
|
||||
}
|
||||
|
||||
E2D_LOG_DEBUG("Shader binary retrieved: {} bytes, format: {}", actualLength,
|
||||
E2D_LOG_DEBUG("着色器二进制数据已获取: {} 字节, 格式: {}", actualLength,
|
||||
binaryFormat);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -259,7 +259,7 @@ GLuint GLShader::compileShader(GLenum type, const char *source) {
|
|||
if (!success) {
|
||||
char infoLog[512];
|
||||
glGetShaderInfoLog(shader, 512, nullptr, infoLog);
|
||||
E2D_LOG_ERROR("Shader compilation failed: {}", infoLog);
|
||||
E2D_LOG_ERROR("着色器编译失败: {}", infoLog);
|
||||
glDeleteShader(shader);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -302,7 +302,7 @@ Ptr<IShader> GLShaderFactory::createFromSource(const std::string &name,
|
|||
shader->setName(name);
|
||||
|
||||
if (!shader->compileFromSource(vertSource.c_str(), fragSource.c_str())) {
|
||||
E2D_LOG_ERROR("Failed to compile shader from source: {}", name);
|
||||
E2D_LOG_ERROR("从源码编译着色器失败: {}", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -323,7 +323,7 @@ GLShaderFactory::createFromBinary(const std::string &name,
|
|||
shader->setName(name);
|
||||
|
||||
if (!shader->compileFromBinary(binary)) {
|
||||
E2D_LOG_ERROR("Failed to create shader from binary: {}", name);
|
||||
E2D_LOG_ERROR("从二进制创建着色器失败: {}", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -340,7 +340,7 @@ bool GLShaderFactory::getShaderBinary(const IShader &shader,
|
|||
std::vector<uint8_t> &outBinary) {
|
||||
const GLShader *glShader = dynamic_cast<const GLShader *>(&shader);
|
||||
if (!glShader) {
|
||||
E2D_LOG_ERROR("Shader is not a GLShader instance");
|
||||
E2D_LOG_ERROR("着色器不是 GLShader 实例");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
#include <extra2d/graphics/shader/shader_manager.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
GLSpriteBatch::GLSpriteBatch()
|
||||
|
|
@ -16,7 +15,7 @@ bool GLSpriteBatch::init() {
|
|||
// 从ShaderManager获取精灵着色器
|
||||
shader_ = ShaderManager::getInstance().getBuiltin("sprite");
|
||||
if (!shader_) {
|
||||
E2D_LOG_ERROR("Failed to get builtin sprite shader");
|
||||
E2D_LOG_ERROR("获取内置精灵着色器失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -31,7 +30,7 @@ bool GLSpriteBatch::init() {
|
|||
vboDesc.size = SpriteBatch::MAX_VERTICES * sizeof(SpriteVertex);
|
||||
vboDesc.initialData = nullptr;
|
||||
if (!vbo_.init(vboDesc)) {
|
||||
E2D_LOG_ERROR("Failed to initialize sprite batch VBO");
|
||||
E2D_LOG_ERROR("初始化精灵批处理 VBO 失败");
|
||||
return false;
|
||||
}
|
||||
vbo_.bind();
|
||||
|
|
@ -59,7 +58,7 @@ bool GLSpriteBatch::init() {
|
|||
eboDesc.size = batch_.getIndices().size() * sizeof(uint16_t);
|
||||
eboDesc.initialData = batch_.getIndices().data();
|
||||
if (!ebo_.init(eboDesc)) {
|
||||
E2D_LOG_ERROR("Failed to initialize sprite batch EBO");
|
||||
E2D_LOG_ERROR("初始化精灵批处理 EBO 失败");
|
||||
return false;
|
||||
}
|
||||
ebo_.bind();
|
||||
|
|
@ -108,7 +107,7 @@ void GLSpriteBatch::end() {
|
|||
void GLSpriteBatch::draw(const Texture &texture, const SpriteData &data) {
|
||||
const GLTexture *glTex = dynamic_cast<const GLTexture *>(&texture);
|
||||
if (!glTex) {
|
||||
E2D_LOG_WARN("Invalid texture type for sprite batch");
|
||||
E2D_LOG_WARN("精灵批处理纹理类型无效");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -128,7 +127,7 @@ void GLSpriteBatch::drawBatch(const Texture &texture,
|
|||
const std::vector<SpriteData> &sprites) {
|
||||
const GLTexture *glTex = dynamic_cast<const GLTexture *>(&texture);
|
||||
if (!glTex) {
|
||||
E2D_LOG_WARN("Invalid texture type for sprite batch");
|
||||
E2D_LOG_WARN("精灵批处理纹理类型无效");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -162,15 +161,18 @@ void GLSpriteBatch::submitBatch() {
|
|||
// 绑定着色器并设置uniform
|
||||
if (shader_) {
|
||||
shader_->bind();
|
||||
// 设置视图投影矩阵
|
||||
shader_->setMat4("u_viewProjection", viewProjection_);
|
||||
// 设置模型矩阵为单位矩阵(精灵位置已经在顶点生成时计算)
|
||||
glm::mat4 model(1.0f);
|
||||
shader_->setMat4("u_model", model);
|
||||
|
||||
// 只提供需要动态计算的值,其他值使用JSON中定义的默认值
|
||||
UniformValueMap uniformValues;
|
||||
uniformValues["u_viewProjection"] = viewProjection_;
|
||||
|
||||
// 使用ShaderManager自动应用uniform值(未提供的值使用JSON中的默认值)
|
||||
// 使用着色器自己的名称(从JSON中解析的name字段)
|
||||
ShaderManager::getInstance().applyUniforms(shader_, shader_->getName(),
|
||||
uniformValues);
|
||||
|
||||
// 设置纹理采样器
|
||||
shader_->setInt("u_texture", 0);
|
||||
// 设置透明度
|
||||
shader_->setFloat("u_opacity", 1.0f);
|
||||
}
|
||||
|
||||
// 上传顶点数据 - 使用 orphaning 策略优化动态缓冲区
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ GLTexture::GLTexture(const std::string &filepath)
|
|||
createTexture(data);
|
||||
stbi_image_free(data);
|
||||
} else {
|
||||
E2D_LOG_ERROR("Failed to load texture: {}", filepath);
|
||||
E2D_LOG_ERROR("加载纹理失败: {}", filepath);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -251,7 +251,7 @@ bool GLTexture::loadCompressed(const std::string &filepath) {
|
|||
if (ext == "dds" || ext == "DDS") {
|
||||
return loadDDS(filepath);
|
||||
}
|
||||
E2D_LOG_ERROR("Unsupported compressed texture format: {}", filepath);
|
||||
E2D_LOG_ERROR("不支持的压缩纹理格式: {}", filepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -263,20 +263,20 @@ bool GLTexture::loadCompressed(const std::string &filepath) {
|
|||
bool GLTexture::loadKTX(const std::string &filepath) {
|
||||
std::ifstream file(filepath, std::ios::binary);
|
||||
if (!file.is_open()) {
|
||||
E2D_LOG_ERROR("Failed to open KTX file: {}", filepath);
|
||||
E2D_LOG_ERROR("打开 KTX 文件失败: {}", filepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
KTXHeader header;
|
||||
file.read(reinterpret_cast<char *>(&header), sizeof(header));
|
||||
if (!file) {
|
||||
E2D_LOG_ERROR("Failed to read KTX header: {}", filepath);
|
||||
E2D_LOG_ERROR("读取 KTX 文件头失败: {}", filepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 验证标识符
|
||||
if (std::memcmp(header.identifier, KTX_IDENTIFIER, 12) != 0) {
|
||||
E2D_LOG_ERROR("Invalid KTX identifier: {}", filepath);
|
||||
E2D_LOG_ERROR("无效的 KTX 标识符: {}", filepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -304,7 +304,7 @@ bool GLTexture::loadKTX(const std::string &filepath) {
|
|||
format_ = PixelFormat::ASTC_8x8;
|
||||
break;
|
||||
default:
|
||||
E2D_LOG_ERROR("Unsupported KTX internal format: {:#06x}", glInternalFormat);
|
||||
E2D_LOG_ERROR("不支持的 KTX 内部格式: {:#06x}", glInternalFormat);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -315,14 +315,14 @@ bool GLTexture::loadKTX(const std::string &filepath) {
|
|||
uint32_t imageSize = 0;
|
||||
file.read(reinterpret_cast<char *>(&imageSize), sizeof(imageSize));
|
||||
if (!file || imageSize == 0) {
|
||||
E2D_LOG_ERROR("Failed to read KTX image size: {}", filepath);
|
||||
E2D_LOG_ERROR("读取 KTX 图像大小失败: {}", filepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> compressedData(imageSize);
|
||||
file.read(reinterpret_cast<char *>(compressedData.data()), imageSize);
|
||||
if (!file) {
|
||||
E2D_LOG_ERROR("Failed to read KTX image data: {}", filepath);
|
||||
E2D_LOG_ERROR("读取 KTX 图像数据失败: {}", filepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -336,7 +336,7 @@ bool GLTexture::loadKTX(const std::string &filepath) {
|
|||
|
||||
GLenum err = glGetError();
|
||||
if (err != GL_NO_ERROR) {
|
||||
E2D_LOG_ERROR("glCompressedTexImage2D failed for KTX: {:#06x}", err);
|
||||
E2D_LOG_ERROR("KTX 纹理上传失败: {:#06x}", err);
|
||||
glDeleteTextures(1, &textureID_);
|
||||
textureID_ = 0;
|
||||
return false;
|
||||
|
|
@ -351,7 +351,7 @@ bool GLTexture::loadKTX(const std::string &filepath) {
|
|||
dataSize_ = imageSize;
|
||||
VRAMMgr::get().allocTexture(dataSize_);
|
||||
|
||||
E2D_LOG_INFO("Loaded compressed KTX texture: {} ({}x{}, format={:#06x})",
|
||||
E2D_LOG_INFO("已加载 KTX 压缩纹理: {} ({}x{}, 格式={:#06x})",
|
||||
filepath, width_, height_, glInternalFormat);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -364,19 +364,19 @@ bool GLTexture::loadKTX(const std::string &filepath) {
|
|||
bool GLTexture::loadDDS(const std::string &filepath) {
|
||||
std::ifstream file(filepath, std::ios::binary);
|
||||
if (!file.is_open()) {
|
||||
E2D_LOG_ERROR("Failed to open DDS file: {}", filepath);
|
||||
E2D_LOG_ERROR("打开 DDS 文件失败: {}", filepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
DDSHeader header;
|
||||
file.read(reinterpret_cast<char *>(&header), sizeof(header));
|
||||
if (!file) {
|
||||
E2D_LOG_ERROR("Failed to read DDS header: {}", filepath);
|
||||
E2D_LOG_ERROR("读取 DDS 文件头失败: {}", filepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header.magic != DDS_MAGIC) {
|
||||
E2D_LOG_ERROR("Invalid DDS magic: {}", filepath);
|
||||
E2D_LOG_ERROR("无效的 DDS 魔数: {}", filepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -392,7 +392,7 @@ bool GLTexture::loadDDS(const std::string &filepath) {
|
|||
DDSHeaderDXT10 dx10Header;
|
||||
file.read(reinterpret_cast<char *>(&dx10Header), sizeof(dx10Header));
|
||||
if (!file) {
|
||||
E2D_LOG_ERROR("Failed to read DDS DX10 header: {}", filepath);
|
||||
E2D_LOG_ERROR("读取 DDS DX10 文件头失败: {}", filepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -408,11 +408,11 @@ bool GLTexture::loadDDS(const std::string &filepath) {
|
|||
format_ = PixelFormat::ETC2_RGBA8;
|
||||
break;
|
||||
default:
|
||||
E2D_LOG_ERROR("Unsupported DDS DX10 format: {}", dx10Header.dxgiFormat);
|
||||
E2D_LOG_ERROR("不支持的 DDS DX10 格式: {}", dx10Header.dxgiFormat);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
E2D_LOG_ERROR("DDS file does not use DX10 extension, unsupported: {}",
|
||||
E2D_LOG_ERROR("DDS 文件未使用 DX10 扩展,不支持: {}",
|
||||
filepath);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -426,7 +426,7 @@ bool GLTexture::loadDDS(const std::string &filepath) {
|
|||
std::vector<uint8_t> compressedData(imageSize);
|
||||
file.read(reinterpret_cast<char *>(compressedData.data()), imageSize);
|
||||
if (!file) {
|
||||
E2D_LOG_ERROR("Failed to read DDS image data: {}", filepath);
|
||||
E2D_LOG_ERROR("读取 DDS 图像数据失败: {}", filepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -440,7 +440,7 @@ bool GLTexture::loadDDS(const std::string &filepath) {
|
|||
|
||||
GLenum err = glGetError();
|
||||
if (err != GL_NO_ERROR) {
|
||||
E2D_LOG_ERROR("glCompressedTexImage2D failed for DDS: {:#06x}", err);
|
||||
E2D_LOG_ERROR("DDS 纹理上传失败: {:#06x}", err);
|
||||
glDeleteTextures(1, &textureID_);
|
||||
textureID_ = 0;
|
||||
return false;
|
||||
|
|
@ -455,21 +455,21 @@ bool GLTexture::loadDDS(const std::string &filepath) {
|
|||
dataSize_ = imageSize;
|
||||
VRAMMgr::get().allocTexture(dataSize_);
|
||||
|
||||
E2D_LOG_INFO("Loaded compressed DDS texture: {} ({}x{})", filepath, width_,
|
||||
E2D_LOG_INFO("已加载 DDS 压缩纹理: {} ({}x{})", filepath, width_,
|
||||
height_);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLTexture::generateAlphaMask() {
|
||||
if (pixelData_.empty() || width_ <= 0 || height_ <= 0) {
|
||||
E2D_LOG_WARN("Cannot generate alpha mask: no pixel data available");
|
||||
E2D_LOG_WARN("无法生成透明遮罩: 没有可用的像素数据");
|
||||
return;
|
||||
}
|
||||
|
||||
alphaMask_ = std::make_unique<AlphaMask>(AlphaMask::createFromPixels(
|
||||
pixelData_.data(), width_, height_, channels_));
|
||||
|
||||
E2D_LOG_DEBUG("Generated alpha mask for texture: {}x{}", width_, height_);
|
||||
E2D_LOG_DEBUG("已为纹理生成透明遮罩: {}x{}", width_, height_);
|
||||
}
|
||||
|
||||
PixelFormat GLTexture::getFormat() const { return format_; }
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ VulkanRenderer::VulkanRenderer() = default;
|
|||
VulkanRenderer::~VulkanRenderer() { shutdown(); }
|
||||
|
||||
bool VulkanRenderer::init(IWindow *window) {
|
||||
E2D_LOG_WARN("Vulkan renderer is not fully implemented yet");
|
||||
E2D_LOG_WARN("Vulkan 渲染器尚未完全实现");
|
||||
initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
#include <extra2d/graphics/shader/shader_manager.h>
|
||||
#include <extra2d/platform/window_module.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
#include <filesystem>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
@ -31,22 +30,13 @@ RenderModule::~RenderModule() {
|
|||
}
|
||||
}
|
||||
|
||||
static std::string getExecutableDir() {
|
||||
try {
|
||||
auto currentPath = std::filesystem::current_path();
|
||||
return currentPath.string() + "/";
|
||||
} catch (...) {
|
||||
return "./";
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderModule::init() {
|
||||
if (initialized_)
|
||||
return true;
|
||||
|
||||
auto *winMod = Registry::instance().get<WindowModule>();
|
||||
if (!winMod || !winMod->win()) {
|
||||
E2D_LOG_ERROR("WindowModule not available");
|
||||
E2D_LOG_ERROR("窗口模块不可用");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -58,44 +48,39 @@ bool RenderModule::init() {
|
|||
graphics::initVulkanBackend();
|
||||
#endif
|
||||
|
||||
// 使用ShaderManager的默认路径初始化
|
||||
if (!ShaderManager::getInstance().isInitialized()) {
|
||||
auto factory = makeShared<GLShaderFactory>();
|
||||
std::string shaderDir = getExecutableDir() + "shaders/";
|
||||
std::string cacheDir = getExecutableDir() + "shader_cache/";
|
||||
if (!ShaderManager::getInstance().init(shaderDir, cacheDir, factory)) {
|
||||
E2D_LOG_WARN("Failed to initialize ShaderManager with dir: {}",
|
||||
shaderDir);
|
||||
if (!ShaderManager::getInstance().init(factory)) {
|
||||
E2D_LOG_WARN("使用默认路径初始化 ShaderManager 失败");
|
||||
}
|
||||
}
|
||||
|
||||
std::string windowBackend = winMod->getWindowBackend();
|
||||
|
||||
if (cfg_.backend.empty()) {
|
||||
E2D_LOG_INFO(
|
||||
"No graphics backend specified, auto-selecting for window backend: {}",
|
||||
windowBackend);
|
||||
E2D_LOG_INFO("未指定图形后端,正在为窗口后端自动选择:{}", windowBackend);
|
||||
renderer_ = graphics::BackendFactory::createBackendForWindow(windowBackend);
|
||||
} else {
|
||||
if (!graphics::BackendFactory::isCompatible(cfg_.backend, windowBackend)) {
|
||||
E2D_LOG_WARN(
|
||||
"Graphics backend '{}' is not compatible with window backend '{}'",
|
||||
cfg_.backend, windowBackend);
|
||||
E2D_LOG_WARN("图形后端 '{}' 与窗口后端 '{}' 不兼容", cfg_.backend,
|
||||
windowBackend);
|
||||
}
|
||||
renderer_ = graphics::BackendFactory::createBackend(cfg_.backend);
|
||||
}
|
||||
|
||||
if (!renderer_) {
|
||||
E2D_LOG_ERROR("Failed to create render backend");
|
||||
E2D_LOG_ERROR("创建渲染后端失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!renderer_->init(winMod->win())) {
|
||||
E2D_LOG_ERROR("Failed to initialize render backend");
|
||||
E2D_LOG_ERROR("初始化渲染后端失败");
|
||||
renderer_.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
E2D_LOG_INFO("Render module initialized successfully");
|
||||
E2D_LOG_INFO("渲染模块初始化成功");
|
||||
initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ void VRAMMgr::allocTexture(size_t size) {
|
|||
peakTextureVRAM_ = std::max(peakTextureVRAM_, textureVRAM_);
|
||||
|
||||
if (isOverBudget()) {
|
||||
E2D_LOG_WARN("VRAM over budget! Used: {} MB / Budget: {} MB",
|
||||
E2D_LOG_WARN("显存超出预算! 已使用: {} MB / 预算: {} MB",
|
||||
getUsedVRAM() / (1024 * 1024), vramBudget_ / (1024 * 1024));
|
||||
}
|
||||
}
|
||||
|
|
@ -77,7 +77,7 @@ void VRAMMgr::allocBuffer(size_t size) {
|
|||
peakBufferVRAM_ = std::max(peakBufferVRAM_, bufferVRAM_);
|
||||
|
||||
if (isOverBudget()) {
|
||||
E2D_LOG_WARN("VRAM over budget! Used: {} MB / Budget: {} MB",
|
||||
E2D_LOG_WARN("显存超出预算! 已使用: {} MB / 预算: {} MB",
|
||||
getUsedVRAM() / (1024 * 1024), vramBudget_ / (1024 * 1024));
|
||||
}
|
||||
}
|
||||
|
|
@ -138,7 +138,7 @@ size_t VRAMMgr::getAvailableVRAM() const {
|
|||
void VRAMMgr::setVRAMBudget(size_t budget) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
vramBudget_ = budget;
|
||||
E2D_LOG_INFO("VRAM budget set to {} MB", budget / (1024 * 1024));
|
||||
E2D_LOG_INFO("显存预算设置为 {} MB", budget / (1024 * 1024));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -160,17 +160,17 @@ bool VRAMMgr::isOverBudget() const { return getUsedVRAM() > vramBudget_; }
|
|||
*/
|
||||
void VRAMMgr::printStats() const {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
E2D_LOG_INFO("=== VRAM Stats ===");
|
||||
E2D_LOG_INFO(" Texture VRAM: {} MB (peak: {} MB)",
|
||||
E2D_LOG_INFO("=== 显存统计 ===");
|
||||
E2D_LOG_INFO(" 纹理显存: {} MB (峰值: {} MB)",
|
||||
textureVRAM_ / (1024 * 1024), peakTextureVRAM_ / (1024 * 1024));
|
||||
E2D_LOG_INFO(" Buffer VRAM: {} MB (peak: {} MB)",
|
||||
E2D_LOG_INFO(" 缓冲显存: {} MB (峰值: {} MB)",
|
||||
bufferVRAM_ / (1024 * 1024), peakBufferVRAM_ / (1024 * 1024));
|
||||
E2D_LOG_INFO(" Total Used: {} MB / {} MB budget",
|
||||
E2D_LOG_INFO(" 总计使用: {} MB / {} MB 预算",
|
||||
(textureVRAM_ + bufferVRAM_) / (1024 * 1024),
|
||||
vramBudget_ / (1024 * 1024));
|
||||
E2D_LOG_INFO(" Texture allocs/frees: {} / {}", textureAllocCount_,
|
||||
E2D_LOG_INFO(" 纹理分配/释放次数: {} / {}", textureAllocCount_,
|
||||
textureFreeCount_);
|
||||
E2D_LOG_INFO(" Buffer allocs/frees: {} / {}", bufferAllocCount_,
|
||||
E2D_LOG_INFO(" 缓冲分配/释放次数: {} / {}", bufferAllocCount_,
|
||||
bufferFreeCount_);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,16 +29,16 @@ bool ShaderCache::init(const std::string &cacheDir) {
|
|||
cacheDir_ = cacheDir;
|
||||
|
||||
if (!ensureCacheDirectory()) {
|
||||
E2D_LOG_ERROR("Failed to create cache directory: {}", cacheDir);
|
||||
E2D_LOG_ERROR("创建缓存目录失败: {}", cacheDir);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!loadCacheIndex()) {
|
||||
E2D_LOG_WARN("Failed to load cache index, starting fresh");
|
||||
E2D_LOG_WARN("加载缓存索引失败,重新开始");
|
||||
}
|
||||
|
||||
initialized_ = true;
|
||||
E2D_LOG_INFO("Shader cache initialized at: {}", cacheDir);
|
||||
E2D_LOG_INFO("着色器缓存已初始化,位置: {}", cacheDir);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ void ShaderCache::shutdown() {
|
|||
saveCacheIndex();
|
||||
cacheMap_.clear();
|
||||
initialized_ = false;
|
||||
E2D_LOG_INFO("Shader cache shutdown");
|
||||
E2D_LOG_INFO("着色器缓存已关闭");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -86,7 +86,7 @@ Ptr<ShaderCacheEntry> ShaderCache::loadCache(const std::string &name) {
|
|||
std::string cachePath = getCachePath(name);
|
||||
std::ifstream file(cachePath, std::ios::binary);
|
||||
if (!file.is_open()) {
|
||||
E2D_LOG_WARN("Failed to open cache file: {}", cachePath);
|
||||
E2D_LOG_WARN("打开缓存文件失败: {}", cachePath);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -110,23 +110,23 @@ Ptr<ShaderCacheEntry> ShaderCache::loadCache(const std::string &name) {
|
|||
*/
|
||||
bool ShaderCache::saveCache(const ShaderCacheEntry &entry) {
|
||||
if (!initialized_) {
|
||||
E2D_LOG_WARN("ShaderCache not initialized, cannot save cache");
|
||||
E2D_LOG_WARN("着色器缓存未初始化,无法保存缓存");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entry.binary.empty()) {
|
||||
E2D_LOG_WARN("Shader binary is empty, skipping cache save for: {}",
|
||||
E2D_LOG_WARN("着色器二进制数据为空,跳过缓存保存: {}",
|
||||
entry.name);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string cachePath = getCachePath(entry.name);
|
||||
E2D_LOG_DEBUG("Saving shader cache to: {} ({} bytes)", cachePath,
|
||||
E2D_LOG_DEBUG("正在保存着色器缓存到: {} ({} 字节)", cachePath,
|
||||
entry.binary.size());
|
||||
|
||||
std::ofstream file(cachePath, std::ios::binary);
|
||||
if (!file.is_open()) {
|
||||
E2D_LOG_ERROR("Failed to create cache file: {}", cachePath);
|
||||
E2D_LOG_ERROR("创建缓存文件失败: {}", cachePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -137,7 +137,7 @@ bool ShaderCache::saveCache(const ShaderCacheEntry &entry) {
|
|||
cacheMap_[entry.name] = entry;
|
||||
saveCacheIndex();
|
||||
|
||||
E2D_LOG_INFO("Shader cache saved: {} ({} bytes)", entry.name,
|
||||
E2D_LOG_INFO("着色器缓存已保存: {} ({} 字节)", entry.name,
|
||||
entry.binary.size());
|
||||
return true;
|
||||
}
|
||||
|
|
@ -158,7 +158,7 @@ void ShaderCache::invalidate(const std::string &name) {
|
|||
cacheMap_.erase(it);
|
||||
saveCacheIndex();
|
||||
|
||||
E2D_LOG_DEBUG("Shader cache invalidated: {}", name);
|
||||
E2D_LOG_DEBUG("着色器缓存已失效: {}", name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -173,7 +173,7 @@ void ShaderCache::clearAll() {
|
|||
cacheMap_.clear();
|
||||
saveCacheIndex();
|
||||
|
||||
E2D_LOG_INFO("All shader caches cleared");
|
||||
E2D_LOG_INFO("所有着色器缓存已清除");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ bool ShaderHotReloader::init() {
|
|||
#endif
|
||||
|
||||
initialized_ = true;
|
||||
E2D_LOG_INFO("Shader hot reloader initialized");
|
||||
E2D_LOG_INFO("着色器热重载器已初始化");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ void ShaderHotReloader::shutdown() {
|
|||
watchMap_.clear();
|
||||
initialized_ = false;
|
||||
enabled_ = false;
|
||||
E2D_LOG_INFO("Shader hot reloader shutdown");
|
||||
E2D_LOG_INFO("着色器热重载器已关闭");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -67,7 +67,7 @@ void ShaderHotReloader::watch(const std::string &shaderName,
|
|||
const std::vector<std::string> &filePaths,
|
||||
FileChangeCallback callback) {
|
||||
if (!initialized_) {
|
||||
E2D_LOG_WARN("Hot reloader not initialized");
|
||||
E2D_LOG_WARN("热重载器未初始化");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ void ShaderHotReloader::watch(const std::string &shaderName,
|
|||
}
|
||||
|
||||
watchMap_[shaderName] = std::move(info);
|
||||
E2D_LOG_DEBUG("Watching shader: {} ({} files)", shaderName, filePaths.size());
|
||||
E2D_LOG_DEBUG("正在监视着色器: {} ({} 个文件)", shaderName, filePaths.size());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -91,7 +91,7 @@ void ShaderHotReloader::unwatch(const std::string &shaderName) {
|
|||
auto it = watchMap_.find(shaderName);
|
||||
if (it != watchMap_.end()) {
|
||||
watchMap_.erase(it);
|
||||
E2D_LOG_DEBUG("Stopped watching shader: {}", shaderName);
|
||||
E2D_LOG_DEBUG("停止监视着色器: {}", shaderName);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +112,7 @@ void ShaderHotReloader::update() {
|
|||
*/
|
||||
void ShaderHotReloader::setEnabled(bool enabled) {
|
||||
enabled_ = enabled;
|
||||
E2D_LOG_DEBUG("Hot reload {}", enabled ? "enabled" : "disabled");
|
||||
E2D_LOG_DEBUG("热重载已{}", enabled ? "启用" : "禁用");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -138,7 +138,7 @@ void ShaderHotReloader::pollChanges() {
|
|||
event.type = FileChangeEvent::Type::Modified;
|
||||
event.timestamp = now;
|
||||
|
||||
E2D_LOG_DEBUG("Shader file changed: {}", filePath);
|
||||
E2D_LOG_DEBUG("着色器文件已更改: {}", filePath);
|
||||
|
||||
if (info.callback) {
|
||||
info.callback(event);
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ ShaderLoader::processIncludes(const std::string &source,
|
|||
result += "\n";
|
||||
continue;
|
||||
} else {
|
||||
E2D_LOG_WARN("Include file not found: {}", includeName);
|
||||
E2D_LOG_WARN("未找到包含文件: {}", includeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@
|
|||
#include <extra2d/graphics/shader/shader_manager.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
|
||||
#include <filesystem>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace nl = nlohmann;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
@ -28,8 +29,8 @@ ShaderManager &ShaderManager::getInstance() {
|
|||
bool ShaderManager::init(Ptr<IShaderFactory> factory,
|
||||
const std::string &appName) {
|
||||
// 使用相对路径作为Shader目录
|
||||
std::string shaderDir = "shaders/";
|
||||
std::string cacheDir = "cache/shaders/";
|
||||
fs::path shaderDir = "shaders";
|
||||
fs::path cacheDir = "cache/shaders";
|
||||
|
||||
// 非Switch平台支持热重载
|
||||
#ifndef __SWITCH__
|
||||
|
|
@ -38,10 +39,10 @@ bool ShaderManager::init(Ptr<IShaderFactory> factory,
|
|||
hotReloadSupported_ = false;
|
||||
#endif
|
||||
|
||||
E2D_LOG_INFO("ShaderManager init (HotReload: {})",
|
||||
E2D_LOG_INFO("ShaderManager 初始化 (热重载: {})",
|
||||
hotReloadSupported_ ? "supported" : "not supported");
|
||||
|
||||
return init(shaderDir, cacheDir, factory);
|
||||
return init(shaderDir.string(), cacheDir.string(), factory);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -55,12 +56,12 @@ bool ShaderManager::init(const std::string &shaderDir,
|
|||
const std::string &cacheDir,
|
||||
Ptr<IShaderFactory> factory) {
|
||||
if (initialized_) {
|
||||
E2D_LOG_WARN("ShaderManager already initialized");
|
||||
E2D_LOG_WARN("ShaderManager 已初始化");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!factory) {
|
||||
E2D_LOG_ERROR("Shader factory is null");
|
||||
E2D_LOG_ERROR("Shader 工厂为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -77,28 +78,28 @@ bool ShaderManager::init(const std::string &shaderDir,
|
|||
|
||||
#ifdef __SWITCH__
|
||||
if (!ShaderCache::getInstance().init(cacheDir_)) {
|
||||
E2D_LOG_WARN("Failed to initialize shader cache on Switch");
|
||||
E2D_LOG_WARN("Switch 平台初始化着色器缓存失败");
|
||||
}
|
||||
#else
|
||||
if (!ShaderCache::getInstance().init(cacheDir_)) {
|
||||
E2D_LOG_WARN("Failed to initialize shader cache, caching disabled");
|
||||
E2D_LOG_WARN("初始化着色器缓存失败,已禁用缓存");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (hotReloadSupported_) {
|
||||
if (!ShaderHotReloader::getInstance().init()) {
|
||||
E2D_LOG_WARN("Failed to initialize hot reloader");
|
||||
E2D_LOG_WARN("初始化热重载器失败");
|
||||
}
|
||||
}
|
||||
|
||||
loader_.addIncludePath(shaderDir_ + "common");
|
||||
|
||||
initialized_ = true;
|
||||
E2D_LOG_INFO("ShaderManager initialized");
|
||||
E2D_LOG_INFO(" Shader directory: {}", shaderDir_);
|
||||
E2D_LOG_INFO(" Cache directory: {}", cacheDir_);
|
||||
E2D_LOG_INFO(" Hot reload: {}",
|
||||
hotReloadSupported_ ? "supported" : "not supported");
|
||||
E2D_LOG_INFO("ShaderManager 初始化成功");
|
||||
E2D_LOG_INFO(" 着色器目录: {}", shaderDir_);
|
||||
E2D_LOG_INFO(" 缓存目录: {}", cacheDir_);
|
||||
E2D_LOG_INFO(" 热重载: {}",
|
||||
hotReloadSupported_ ? "支持" : "不支持");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -120,7 +121,7 @@ void ShaderManager::shutdown() {
|
|||
factory_.reset();
|
||||
initialized_ = false;
|
||||
|
||||
E2D_LOG_INFO("ShaderManager shutdown");
|
||||
E2D_LOG_INFO("ShaderManager 已关闭");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -134,7 +135,7 @@ Ptr<IShader> ShaderManager::loadFromFiles(const std::string &name,
|
|||
const std::string &vertPath,
|
||||
const std::string &fragPath) {
|
||||
if (!initialized_) {
|
||||
E2D_LOG_ERROR("ShaderManager not initialized");
|
||||
E2D_LOG_ERROR("ShaderManager 未初始化");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -146,7 +147,7 @@ Ptr<IShader> ShaderManager::loadFromFiles(const std::string &name,
|
|||
ShaderLoadResult result =
|
||||
loader_.loadFromSeparateFiles(name, vertPath, fragPath);
|
||||
if (!result.success) {
|
||||
E2D_LOG_ERROR("Failed to load shader files: {} - {}", vertPath, fragPath);
|
||||
E2D_LOG_ERROR("加载着色器文件失败: {} - {}", vertPath, fragPath);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -156,18 +157,18 @@ Ptr<IShader> ShaderManager::loadFromFiles(const std::string &name,
|
|||
loadFromCache(name, sourceHash, result.vertSource, result.fragSource);
|
||||
|
||||
if (!shader) {
|
||||
E2D_LOG_DEBUG("No valid cache found, compiling shader from source: {}",
|
||||
E2D_LOG_DEBUG("未找到有效缓存,从源码编译着色器: {}",
|
||||
name);
|
||||
shader =
|
||||
factory_->createFromSource(name, result.vertSource, result.fragSource);
|
||||
if (!shader) {
|
||||
E2D_LOG_ERROR("Failed to create shader from source: {}", name);
|
||||
E2D_LOG_ERROR("从源码创建着色器失败: {}", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> binary;
|
||||
if (factory_->getShaderBinary(*shader, binary)) {
|
||||
E2D_LOG_DEBUG("Got shader binary, size: {} bytes", binary.size());
|
||||
E2D_LOG_DEBUG("获取到着色器二进制数据,大小: {} 字节", binary.size());
|
||||
ShaderCacheEntry entry;
|
||||
entry.name = name;
|
||||
entry.sourceHash = sourceHash;
|
||||
|
|
@ -175,7 +176,7 @@ Ptr<IShader> ShaderManager::loadFromFiles(const std::string &name,
|
|||
entry.dependencies = result.dependencies;
|
||||
ShaderCache::getInstance().saveCache(entry);
|
||||
} else {
|
||||
E2D_LOG_WARN("Failed to get shader binary for: {}", name);
|
||||
E2D_LOG_WARN("获取着色器二进制数据失败: {}", name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -201,7 +202,7 @@ Ptr<IShader> ShaderManager::loadFromFiles(const std::string &name,
|
|||
callback);
|
||||
}
|
||||
|
||||
E2D_LOG_DEBUG("Shader loaded: {}", name);
|
||||
E2D_LOG_DEBUG("着色器已加载: {}", name);
|
||||
return shader;
|
||||
}
|
||||
|
||||
|
|
@ -212,7 +213,7 @@ Ptr<IShader> ShaderManager::loadFromFiles(const std::string &name,
|
|||
*/
|
||||
Ptr<IShader> ShaderManager::loadFromCombinedFile(const std::string &path) {
|
||||
if (!initialized_) {
|
||||
E2D_LOG_ERROR("ShaderManager not initialized");
|
||||
E2D_LOG_ERROR("ShaderManager 未初始化");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -226,7 +227,7 @@ Ptr<IShader> ShaderManager::loadFromCombinedFile(const std::string &path) {
|
|||
|
||||
ShaderLoadResult result = loader_.loadFromCombinedFile(path);
|
||||
if (!result.success) {
|
||||
E2D_LOG_ERROR("Failed to load combined shader file: {}", path);
|
||||
E2D_LOG_ERROR("加载组合着色器文件失败: {}", path);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -241,13 +242,13 @@ Ptr<IShader> ShaderManager::loadFromCombinedFile(const std::string &path) {
|
|||
shader =
|
||||
factory_->createFromSource(name, result.vertSource, result.fragSource);
|
||||
if (!shader) {
|
||||
E2D_LOG_ERROR("Failed to create shader from source: {}", name);
|
||||
E2D_LOG_ERROR("从源码创建着色器失败: {}", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> binary;
|
||||
if (factory_->getShaderBinary(*shader, binary)) {
|
||||
E2D_LOG_DEBUG("Got shader binary, size: {} bytes", binary.size());
|
||||
E2D_LOG_DEBUG("获取到着色器二进制数据,大小: {} 字节", binary.size());
|
||||
ShaderCacheEntry entry;
|
||||
entry.name = name;
|
||||
entry.sourceHash = sourceHash;
|
||||
|
|
@ -255,7 +256,7 @@ Ptr<IShader> ShaderManager::loadFromCombinedFile(const std::string &path) {
|
|||
entry.dependencies = result.dependencies;
|
||||
ShaderCache::getInstance().saveCache(entry);
|
||||
} else {
|
||||
E2D_LOG_WARN("Failed to get shader binary for: {}", name);
|
||||
E2D_LOG_WARN("获取着色器二进制数据失败: {}", name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -278,7 +279,7 @@ Ptr<IShader> ShaderManager::loadFromCombinedFile(const std::string &path) {
|
|||
callback);
|
||||
}
|
||||
|
||||
E2D_LOG_DEBUG("Shader loaded from combined file: {}", name);
|
||||
E2D_LOG_DEBUG("从组合文件加载着色器成功: {}", name);
|
||||
return shader;
|
||||
}
|
||||
|
||||
|
|
@ -293,7 +294,7 @@ Ptr<IShader> ShaderManager::loadFromSource(const std::string &name,
|
|||
const std::string &vertSource,
|
||||
const std::string &fragSource) {
|
||||
if (!initialized_) {
|
||||
E2D_LOG_ERROR("ShaderManager not initialized");
|
||||
E2D_LOG_ERROR("ShaderManager 未初始化");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -305,7 +306,7 @@ Ptr<IShader> ShaderManager::loadFromSource(const std::string &name,
|
|||
Ptr<IShader> shader =
|
||||
factory_->createFromSource(name, vertSource, fragSource);
|
||||
if (!shader) {
|
||||
E2D_LOG_ERROR("Failed to create shader from source: {}", name);
|
||||
E2D_LOG_ERROR("从源码创建着色器失败: {}", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -317,7 +318,7 @@ Ptr<IShader> ShaderManager::loadFromSource(const std::string &name,
|
|||
|
||||
shaders_[name] = std::move(info);
|
||||
|
||||
E2D_LOG_DEBUG("Shader loaded from source: {}", name);
|
||||
E2D_LOG_DEBUG("从源码加载着色器成功: {}", name);
|
||||
return shader;
|
||||
}
|
||||
|
||||
|
|
@ -352,7 +353,7 @@ void ShaderManager::remove(const std::string &name) {
|
|||
if (it != shaders_.end()) {
|
||||
ShaderHotReloader::getInstance().unwatch(name);
|
||||
shaders_.erase(it);
|
||||
E2D_LOG_DEBUG("Shader removed: {}", name);
|
||||
E2D_LOG_DEBUG("着色器已移除: {}", name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -366,7 +367,7 @@ void ShaderManager::clear() {
|
|||
}
|
||||
}
|
||||
shaders_.clear();
|
||||
E2D_LOG_DEBUG("All shaders cleared");
|
||||
E2D_LOG_DEBUG("所有着色器已清除");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -388,12 +389,12 @@ void ShaderManager::setReloadCallback(const std::string &name,
|
|||
*/
|
||||
void ShaderManager::setHotReloadEnabled(bool enabled) {
|
||||
if (!hotReloadSupported_) {
|
||||
E2D_LOG_WARN("Hot reload not supported on this platform");
|
||||
E2D_LOG_WARN("当前平台不支持热重载");
|
||||
return;
|
||||
}
|
||||
hotReloadEnabled_ = enabled;
|
||||
ShaderHotReloader::getInstance().setEnabled(enabled);
|
||||
E2D_LOG_INFO("Hot reload {}", enabled ? "enabled" : "disabled");
|
||||
E2D_LOG_INFO("热重载已{}", enabled ? "启用" : "禁用");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -421,7 +422,7 @@ void ShaderManager::update() {
|
|||
bool ShaderManager::reload(const std::string &name) {
|
||||
auto it = shaders_.find(name);
|
||||
if (it == shaders_.end()) {
|
||||
E2D_LOG_WARN("Shader not found for reload: {}", name);
|
||||
E2D_LOG_WARN("未找到要重载的着色器: {}", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -449,7 +450,7 @@ bool ShaderManager::reload(const std::string &name) {
|
|||
Ptr<IShader> newShader =
|
||||
factory_->createFromSource(name, vertSource, fragSource);
|
||||
if (!newShader) {
|
||||
E2D_LOG_ERROR("Failed to reload shader: {}", name);
|
||||
E2D_LOG_ERROR("重载着色器失败: {}", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -461,7 +462,7 @@ bool ShaderManager::reload(const std::string &name) {
|
|||
info.reloadCallback(newShader);
|
||||
}
|
||||
|
||||
E2D_LOG_INFO("Shader reloaded: {}", name);
|
||||
E2D_LOG_INFO("着色器重载成功: {}", name);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -476,15 +477,15 @@ Ptr<IShader> ShaderManager::getBuiltin(const std::string &name) {
|
|||
return shader;
|
||||
}
|
||||
|
||||
// 尝试从新的多后端JSON元数据加载
|
||||
std::string jsonPath = shaderDir_ + "shared/builtin/" + name + ".json";
|
||||
if (loader_.fileExists(jsonPath)) {
|
||||
return loadFromMetadata(jsonPath, name);
|
||||
// 从JSON元数据文件加载内置着色器
|
||||
fs::path jsonPath =
|
||||
fs::path(shaderDir_) / "shared" / "builtin" / (name + ".json");
|
||||
if (loader_.fileExists(jsonPath.string())) {
|
||||
return loadFromMetadata(jsonPath.string(), name);
|
||||
}
|
||||
|
||||
// 回退到旧的组合文件格式
|
||||
std::string path = shaderDir_ + "builtin/" + name + ".shader";
|
||||
return loadFromCombinedFile(path);
|
||||
E2D_LOG_ERROR("未找到内置着色器: {}", jsonPath.string());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -496,7 +497,7 @@ Ptr<IShader> ShaderManager::getBuiltin(const std::string &name) {
|
|||
Ptr<IShader> ShaderManager::loadFromMetadata(const std::string &jsonPath,
|
||||
const std::string &name) {
|
||||
if (!initialized_) {
|
||||
E2D_LOG_ERROR("ShaderManager not initialized");
|
||||
E2D_LOG_ERROR("ShaderManager 未初始化");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -509,7 +510,7 @@ Ptr<IShader> ShaderManager::loadFromMetadata(const std::string &jsonPath,
|
|||
// 读取JSON文件
|
||||
std::string jsonContent = loader_.readFile(jsonPath);
|
||||
if (jsonContent.empty()) {
|
||||
E2D_LOG_ERROR("Failed to read shader metadata: {}", jsonPath);
|
||||
E2D_LOG_ERROR("读取着色器元数据失败: {}", jsonPath);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -517,15 +518,80 @@ Ptr<IShader> ShaderManager::loadFromMetadata(const std::string &jsonPath,
|
|||
// 使用nlohmann/json解析
|
||||
nl::json j = nl::json::parse(jsonContent);
|
||||
|
||||
// 解析基本元数据
|
||||
ShaderMetadata metadata;
|
||||
metadata.name = name;
|
||||
|
||||
if (j.contains("category")) {
|
||||
metadata.category = j["category"].get<std::string>();
|
||||
}
|
||||
if (j.contains("version")) {
|
||||
metadata.version = j["version"].get<std::string>();
|
||||
}
|
||||
if (j.contains("description")) {
|
||||
metadata.description = j["description"].get<std::string>();
|
||||
}
|
||||
|
||||
// 解析 uniforms 详细定义
|
||||
if (j.contains("uniforms")) {
|
||||
for (auto &[key, value] : j["uniforms"].items()) {
|
||||
ShaderUniformDef def;
|
||||
if (value.contains("type")) {
|
||||
def.type = value["type"].get<std::string>();
|
||||
}
|
||||
if (value.contains("description")) {
|
||||
def.description = value["description"].get<std::string>();
|
||||
}
|
||||
// 解析默认值
|
||||
if (value.contains("default")) {
|
||||
def.hasDefault = true;
|
||||
if (def.type == "float") {
|
||||
def.defaultValue = value["default"].get<float>();
|
||||
} else if (def.type == "int") {
|
||||
def.defaultInt = value["default"].get<int>();
|
||||
} else if (def.type == "bool") {
|
||||
def.defaultBool = value["default"].get<bool>();
|
||||
} else if (def.type == "vec4" && value["default"].is_array()) {
|
||||
auto arr = value["default"].get<std::vector<float>>();
|
||||
for (size_t i = 0; i < arr.size() && i < 4; ++i) {
|
||||
def.defaultVec4[i] = arr[i];
|
||||
}
|
||||
} else if (def.type == "mat4" && value["default"].is_array()) {
|
||||
auto arr = value["default"].get<std::vector<float>>();
|
||||
for (size_t i = 0; i < arr.size() && i < 16; ++i) {
|
||||
def.defaultMat4[i] = arr[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
metadata.uniformDefs[key] = def;
|
||||
// 同时填充旧的uniforms映射以保持兼容性
|
||||
metadata.uniforms[key] = def.type;
|
||||
}
|
||||
}
|
||||
|
||||
// 解析 samplers 定义
|
||||
if (j.contains("samplers")) {
|
||||
for (auto &[key, value] : j["samplers"].items()) {
|
||||
ShaderSamplerDef def;
|
||||
if (value.contains("type")) {
|
||||
def.type = value["type"].get<std::string>();
|
||||
}
|
||||
if (value.contains("description")) {
|
||||
def.description = value["description"].get<std::string>();
|
||||
}
|
||||
metadata.samplerDefs[key] = def;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取OpenGL后端路径
|
||||
if (!j.contains("backends") || !j["backends"].contains("opengl")) {
|
||||
E2D_LOG_ERROR("No OpenGL backend found in shader metadata: {}", jsonPath);
|
||||
E2D_LOG_ERROR("着色器元数据中未找到 OpenGL 后端: {}", jsonPath);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto &opengl = j["backends"]["opengl"];
|
||||
if (!opengl.contains("vertex") || !opengl.contains("fragment")) {
|
||||
E2D_LOG_ERROR("Missing vertex or fragment path in shader metadata: {}",
|
||||
E2D_LOG_ERROR("着色器元数据中缺少顶点或片段路径: {}",
|
||||
jsonPath);
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -533,18 +599,26 @@ Ptr<IShader> ShaderManager::loadFromMetadata(const std::string &jsonPath,
|
|||
std::string vertRelativePath = opengl["vertex"].get<std::string>();
|
||||
std::string fragRelativePath = opengl["fragment"].get<std::string>();
|
||||
|
||||
// 构建完整路径
|
||||
std::string vertPath = shaderDir_ + vertRelativePath;
|
||||
std::string fragPath = shaderDir_ + fragRelativePath;
|
||||
// 使用C++17文件系统构建完整路径
|
||||
fs::path vertPath = fs::path(shaderDir_) / vertRelativePath;
|
||||
fs::path fragPath = fs::path(shaderDir_) / fragRelativePath;
|
||||
|
||||
E2D_LOG_DEBUG("Loading shader from metadata: {} -> vert: {}, frag: {}",
|
||||
name, vertPath, fragPath);
|
||||
E2D_LOG_DEBUG("从元数据加载着色器: {} -> 顶点: {}, 片段: {}",
|
||||
name, vertPath.string(), fragPath.string());
|
||||
|
||||
// 使用分离文件加载
|
||||
return loadFromFiles(name, vertPath, fragPath);
|
||||
Ptr<IShader> shader =
|
||||
loadFromFiles(name, vertPath.string(), fragPath.string());
|
||||
|
||||
// 更新着色器元数据
|
||||
if (shader && shaders_.find(name) != shaders_.end()) {
|
||||
shaders_[name].metadata = metadata;
|
||||
}
|
||||
|
||||
return shader;
|
||||
|
||||
} catch (const nl::json::exception &e) {
|
||||
E2D_LOG_ERROR("Failed to parse shader metadata {}: {}", jsonPath, e.what());
|
||||
E2D_LOG_ERROR("解析着色器元数据 {} 失败: {}", jsonPath, e.what());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
|
@ -555,7 +629,7 @@ Ptr<IShader> ShaderManager::loadFromMetadata(const std::string &jsonPath,
|
|||
*/
|
||||
bool ShaderManager::loadBuiltinShaders() {
|
||||
if (!initialized_) {
|
||||
E2D_LOG_ERROR("ShaderManager not initialized");
|
||||
E2D_LOG_ERROR("ShaderManager 未初始化");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -565,21 +639,17 @@ bool ShaderManager::loadBuiltinShaders() {
|
|||
"font"};
|
||||
|
||||
for (const char *name : builtinNames) {
|
||||
// 首先尝试新的多后端JSON格式
|
||||
std::string jsonPath = shaderDir_ + "shared/builtin/" + name + ".json";
|
||||
fs::path jsonPath = fs::path(shaderDir_) / "shared" / "builtin" /
|
||||
(std::string(name) + ".json");
|
||||
std::string shaderName = std::string("builtin_") + name;
|
||||
|
||||
Ptr<IShader> shader = nullptr;
|
||||
if (loader_.fileExists(jsonPath)) {
|
||||
shader = loadFromMetadata(jsonPath, name);
|
||||
} else {
|
||||
// 回退到旧的组合文件格式
|
||||
std::string path = shaderDir_ + "builtin/" + name + ".shader";
|
||||
shader = loadFromCombinedFile(path);
|
||||
if (loader_.fileExists(jsonPath.string())) {
|
||||
shader = loadFromMetadata(jsonPath.string(), name);
|
||||
}
|
||||
|
||||
if (!shader) {
|
||||
E2D_LOG_ERROR("Failed to load builtin {} shader", name);
|
||||
E2D_LOG_ERROR("加载内置 {} 着色器失败", name);
|
||||
allSuccess = false;
|
||||
} else {
|
||||
// 同时注册带 builtin_ 前缀的名称
|
||||
|
|
@ -591,7 +661,7 @@ bool ShaderManager::loadBuiltinShaders() {
|
|||
}
|
||||
|
||||
if (allSuccess) {
|
||||
E2D_LOG_INFO("All builtin shaders loaded");
|
||||
E2D_LOG_INFO("所有内置着色器加载成功");
|
||||
}
|
||||
|
||||
return allSuccess;
|
||||
|
|
@ -624,7 +694,7 @@ Ptr<IShader> ShaderManager::loadFromCache(const std::string &name,
|
|||
|
||||
Ptr<IShader> shader = factory_->createFromBinary(name, entry->binary);
|
||||
if (shader) {
|
||||
E2D_LOG_DEBUG("Shader loaded from cache: {}", name);
|
||||
E2D_LOG_DEBUG("从缓存加载着色器成功: {}", name);
|
||||
}
|
||||
|
||||
return shader;
|
||||
|
|
@ -637,8 +707,136 @@ Ptr<IShader> ShaderManager::loadFromCache(const std::string &name,
|
|||
*/
|
||||
void ShaderManager::handleFileChange(const std::string &shaderName,
|
||||
const FileChangeEvent &event) {
|
||||
E2D_LOG_DEBUG("Shader file changed: {} -> {}", shaderName, event.filepath);
|
||||
E2D_LOG_DEBUG("着色器文件已更改: {} -> {}", shaderName, event.filepath);
|
||||
reload(shaderName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取Shader元数据
|
||||
* @param name Shader名称
|
||||
* @return Shader元数据,不存在返回空元数据
|
||||
*/
|
||||
ShaderMetadata ShaderManager::getMetadata(const std::string &name) const {
|
||||
auto it = shaders_.find(name);
|
||||
if (it != shaders_.end()) {
|
||||
return it->second.metadata;
|
||||
}
|
||||
return ShaderMetadata{};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取Shader的uniform定义
|
||||
* @param name Shader名称
|
||||
* @return uniform定义映射,不存在返回空映射
|
||||
*/
|
||||
std::unordered_map<std::string, ShaderUniformDef>
|
||||
ShaderManager::getUniformDefs(const std::string &name) const {
|
||||
auto it = shaders_.find(name);
|
||||
if (it != shaders_.end()) {
|
||||
return it->second.metadata.uniformDefs;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取Shader的sampler定义
|
||||
* @param name Shader名称
|
||||
* @return sampler定义映射,不存在返回空映射
|
||||
*/
|
||||
std::unordered_map<std::string, ShaderSamplerDef>
|
||||
ShaderManager::getSamplerDefs(const std::string &name) const {
|
||||
auto it = shaders_.find(name);
|
||||
if (it != shaders_.end()) {
|
||||
return it->second.metadata.samplerDefs;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 自动应用uniform值到着色器
|
||||
* 根据JSON元数据中的uniform定义,自动设置对应的uniform值
|
||||
* 如果值映射表中不存在该uniform,则使用JSON中定义的默认值
|
||||
* @param shader 目标着色器
|
||||
* @param shaderName Shader名称(用于查找元数据)
|
||||
* @param values uniform值映射表(可选,用于覆盖默认值)
|
||||
*/
|
||||
void ShaderManager::applyUniforms(Ptr<IShader> shader,
|
||||
const std::string &shaderName,
|
||||
const UniformValueMap &values) {
|
||||
if (!shader)
|
||||
return;
|
||||
|
||||
auto uniformDefs = getUniformDefs(shaderName);
|
||||
for (const auto &[name, def] : uniformDefs) {
|
||||
auto it = values.find(name);
|
||||
|
||||
if (it != values.end()) {
|
||||
// 使用提供的值
|
||||
const auto &value = it->second;
|
||||
if (def.type == "float" &&
|
||||
value.type == ShaderUniformValue::Type::Float) {
|
||||
shader->setFloat(name, value.data.f[0]);
|
||||
} else if (def.type == "int" &&
|
||||
value.type == ShaderUniformValue::Type::Int) {
|
||||
shader->setInt(name, value.data.i);
|
||||
} else if (def.type == "bool" &&
|
||||
value.type == ShaderUniformValue::Type::Bool) {
|
||||
shader->setBool(name, value.data.b);
|
||||
} else if (def.type == "vec2" &&
|
||||
value.type == ShaderUniformValue::Type::Vec2) {
|
||||
shader->setVec2(name, glm::vec2(value.data.f[0], value.data.f[1]));
|
||||
} else if (def.type == "vec3" &&
|
||||
value.type == ShaderUniformValue::Type::Vec3) {
|
||||
shader->setVec3(
|
||||
name, glm::vec3(value.data.f[0], value.data.f[1], value.data.f[2]));
|
||||
} else if (def.type == "vec4" &&
|
||||
value.type == ShaderUniformValue::Type::Vec4) {
|
||||
shader->setVec4(name, glm::vec4(value.data.f[0], value.data.f[1],
|
||||
value.data.f[2], value.data.f[3]));
|
||||
} else if (def.type == "mat4" &&
|
||||
value.type == ShaderUniformValue::Type::Mat4) {
|
||||
glm::mat4 mat;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
for (int j = 0; j < 4; ++j)
|
||||
mat[i][j] = value.data.f[i * 4 + j];
|
||||
shader->setMat4(name, mat);
|
||||
}
|
||||
} else if (def.hasDefault) {
|
||||
// 使用JSON中定义的默认值
|
||||
if (def.type == "float") {
|
||||
shader->setFloat(name, def.defaultValue);
|
||||
} else if (def.type == "int") {
|
||||
shader->setInt(name, def.defaultInt);
|
||||
} else if (def.type == "bool") {
|
||||
shader->setBool(name, def.defaultBool);
|
||||
} else if (def.type == "vec4") {
|
||||
shader->setVec4(name,
|
||||
glm::vec4(def.defaultVec4[0], def.defaultVec4[1],
|
||||
def.defaultVec4[2], def.defaultVec4[3]));
|
||||
} else if (def.type == "mat4") {
|
||||
glm::mat4 mat;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
for (int j = 0; j < 4; ++j)
|
||||
mat[i][j] = def.defaultMat4[i * 4 + j];
|
||||
shader->setMat4(name, mat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 自动应用sampler绑定到着色器
|
||||
* 根据JSON元数据中的sampler定义,自动设置对应的纹理单元
|
||||
* @param shader 目标着色器
|
||||
* @param shaderName Shader名称(用于查找元数据)
|
||||
*/
|
||||
void ShaderManager::applySamplers(Ptr<IShader> shader,
|
||||
const std::string &shaderName) {
|
||||
if (!shader)
|
||||
return;
|
||||
|
||||
// TODO: 从JSON中解析binding并设置
|
||||
// 目前sampler绑定在submitBatch中通过setInt设置
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ namespace extra2d {
|
|||
Ptr<IShader> ShaderPreset::Water(const WaterParams ¶ms) {
|
||||
Ptr<IShader> shader = ShaderManager::getInstance().get("water");
|
||||
if (!shader) {
|
||||
E2D_LOG_ERROR("Failed to get water shader");
|
||||
E2D_LOG_ERROR("获取水波纹着色器失败");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ Ptr<IShader> ShaderPreset::Water(const WaterParams ¶ms) {
|
|||
Ptr<IShader> ShaderPreset::Outline(const OutlineParams ¶ms) {
|
||||
Ptr<IShader> shader = ShaderManager::getInstance().get("outline");
|
||||
if (!shader) {
|
||||
E2D_LOG_ERROR("Failed to get outline shader");
|
||||
E2D_LOG_ERROR("获取描边着色器失败");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ Ptr<IShader> ShaderPreset::Outline(const OutlineParams ¶ms) {
|
|||
Ptr<IShader> ShaderPreset::Distortion(const DistortionParams ¶ms) {
|
||||
Ptr<IShader> shader = ShaderManager::getInstance().get("distortion");
|
||||
if (!shader) {
|
||||
E2D_LOG_ERROR("Failed to get distortion shader");
|
||||
E2D_LOG_ERROR("获取扭曲效果着色器失败");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ Ptr<IShader> ShaderPreset::Distortion(const DistortionParams ¶ms) {
|
|||
Ptr<IShader> ShaderPreset::Pixelate(const PixelateParams ¶ms) {
|
||||
Ptr<IShader> shader = ShaderManager::getInstance().get("pixelate");
|
||||
if (!shader) {
|
||||
E2D_LOG_ERROR("Failed to get pixelate shader");
|
||||
E2D_LOG_ERROR("获取像素化着色器失败");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -87,7 +87,7 @@ Ptr<IShader> ShaderPreset::Pixelate(const PixelateParams ¶ms) {
|
|||
Ptr<IShader> ShaderPreset::Invert(const InvertParams ¶ms) {
|
||||
Ptr<IShader> shader = ShaderManager::getInstance().get("invert");
|
||||
if (!shader) {
|
||||
E2D_LOG_ERROR("Failed to get invert shader");
|
||||
E2D_LOG_ERROR("获取反相着色器失败");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -104,7 +104,7 @@ Ptr<IShader> ShaderPreset::Invert(const InvertParams ¶ms) {
|
|||
Ptr<IShader> ShaderPreset::Grayscale(const GrayscaleParams ¶ms) {
|
||||
Ptr<IShader> shader = ShaderManager::getInstance().get("grayscale");
|
||||
if (!shader) {
|
||||
E2D_LOG_ERROR("Failed to get grayscale shader");
|
||||
E2D_LOG_ERROR("获取灰度着色器失败");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -121,7 +121,7 @@ Ptr<IShader> ShaderPreset::Grayscale(const GrayscaleParams ¶ms) {
|
|||
Ptr<IShader> ShaderPreset::Blur(const BlurParams ¶ms) {
|
||||
Ptr<IShader> shader = ShaderManager::getInstance().get("blur");
|
||||
if (!shader) {
|
||||
E2D_LOG_ERROR("Failed to get blur shader");
|
||||
E2D_LOG_ERROR("获取模糊着色器失败");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -140,13 +140,13 @@ Ptr<IShader>
|
|||
ShaderPreset::GrayscaleOutline(const GrayscaleParams &grayParams,
|
||||
const OutlineParams &outlineParams) {
|
||||
std::string shaderDir = ShaderManager::getInstance().getShaderDir();
|
||||
std::string shaderPath = shaderDir + "effects/grayscale_outline.shader";
|
||||
std::string jsonPath = shaderDir + "effects/grayscale_outline.json";
|
||||
|
||||
Ptr<IShader> shader =
|
||||
ShaderManager::getInstance().loadFromCombinedFile(shaderPath);
|
||||
ShaderManager::getInstance().loadFromMetadata(jsonPath, "grayscale_outline");
|
||||
if (!shader) {
|
||||
E2D_LOG_ERROR("Failed to load grayscale_outline shader from: {}",
|
||||
shaderPath);
|
||||
E2D_LOG_ERROR("从 {} 加载灰度描边组合着色器失败",
|
||||
jsonPath);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -168,12 +168,12 @@ ShaderPreset::GrayscaleOutline(const GrayscaleParams &grayParams,
|
|||
Ptr<IShader> ShaderPreset::PixelateInvert(const PixelateParams &pixParams,
|
||||
const InvertParams &invParams) {
|
||||
std::string shaderDir = ShaderManager::getInstance().getShaderDir();
|
||||
std::string shaderPath = shaderDir + "effects/pixelate_invert.shader";
|
||||
std::string jsonPath = shaderDir + "effects/pixelate_invert.json";
|
||||
|
||||
Ptr<IShader> shader =
|
||||
ShaderManager::getInstance().loadFromCombinedFile(shaderPath);
|
||||
ShaderManager::getInstance().loadFromMetadata(jsonPath, "pixelate_invert");
|
||||
if (!shader) {
|
||||
E2D_LOG_ERROR("Failed to load pixelate_invert shader from: {}", shaderPath);
|
||||
E2D_LOG_ERROR("从 {} 加载像素化反相组合着色器失败", jsonPath);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ TextureAtlasPage::TextureAtlasPage(int width, int height)
|
|||
// 初始化矩形打包根节点
|
||||
root_ = std::make_unique<PackNode>(0, 0, width, height);
|
||||
|
||||
E2D_LOG_INFO("Created texture atlas page: {}x{}", width, height);
|
||||
E2D_LOG_INFO("已创建纹理图集页面: {}x{}", width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -92,7 +92,7 @@ bool TextureAtlasPage::tryAddTexture(const std::string &name, int texWidth,
|
|||
entries_[name] = std::move(entry);
|
||||
usedArea_ += paddedWidth * paddedHeight;
|
||||
|
||||
E2D_LOG_DEBUG("Added texture '{}' to atlas: {}x{} at ({}, {})", name,
|
||||
E2D_LOG_DEBUG("已将纹理 '{}' 添加到图集: {}x{} 位置 ({}, {})", name,
|
||||
texWidth, texHeight, node->x, node->y);
|
||||
|
||||
return true;
|
||||
|
|
@ -233,7 +233,7 @@ TextureAtlas::~TextureAtlas() = default;
|
|||
void TextureAtlas::init(int pageSize) {
|
||||
pageSize_ = pageSize;
|
||||
initialized_ = true;
|
||||
E2D_LOG_INFO("TextureAtlas initialized with page size: {}", pageSize);
|
||||
E2D_LOG_INFO("纹理图集已初始化,页面大小: {}", pageSize);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -259,7 +259,7 @@ bool TextureAtlas::addTexture(const std::string &name, int width, int height,
|
|||
|
||||
// 检查纹理大小
|
||||
if (width > sizeThreshold_ || height > sizeThreshold_) {
|
||||
E2D_LOG_DEBUG("Texture '{}' too large for atlas ({}x{} > {}), skipping",
|
||||
E2D_LOG_DEBUG("纹理 '{}' 太大无法加入图集 ({}x{} > {}),跳过",
|
||||
name, width, height, sizeThreshold_);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -281,7 +281,7 @@ bool TextureAtlas::addTexture(const std::string &name, int width, int height,
|
|||
return true;
|
||||
}
|
||||
|
||||
E2D_LOG_WARN("Failed to add texture '{}' to atlas", name);
|
||||
E2D_LOG_WARN("添加纹理 '{}' 到图集失败", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -365,7 +365,7 @@ float TextureAtlas::getTotalUsageRatio() const {
|
|||
void TextureAtlas::clear() {
|
||||
pages_.clear();
|
||||
entryToPage_.clear();
|
||||
E2D_LOG_INFO("TextureAtlas cleared");
|
||||
E2D_LOG_INFO("纹理图集已清空");
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ TexturePool::TexturePool(Scene* scene, size_t maxMemoryUsage)
|
|||
, cacheHits_(0)
|
||||
, cacheMisses_(0)
|
||||
, evictionCount_(0) {
|
||||
E2D_LOG_INFO("TexturePool created with max memory: {} bytes", maxMemoryUsage);
|
||||
E2D_LOG_INFO("TexturePool 已创建,最大内存: {} 字节", maxMemoryUsage);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -52,7 +52,7 @@ TexturePool::TexturePool(Scene* scene, size_t maxMemoryUsage)
|
|||
void TexturePool::init(Scene* scene, size_t maxMemoryUsage) {
|
||||
scene_ = scene;
|
||||
maxMemoryUsage_ = maxMemoryUsage;
|
||||
E2D_LOG_INFO("TexturePool initialized with max memory: {} bytes", maxMemoryUsage);
|
||||
E2D_LOG_INFO("TexturePool 已初始化,最大内存: {} 字节", maxMemoryUsage);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -62,7 +62,7 @@ void TexturePool::init(Scene* scene, size_t maxMemoryUsage) {
|
|||
*/
|
||||
TexturePool::~TexturePool() {
|
||||
clear();
|
||||
E2D_LOG_INFO("TexturePool destroyed");
|
||||
E2D_LOG_INFO("TexturePool 已销毁");
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -104,7 +104,7 @@ TextureRef TexturePool::load(const std::string& path, const Rect& region,
|
|||
it->second.refCount.fetch_add(1, std::memory_order_relaxed);
|
||||
cacheHits_.fetch_add(1, std::memory_order_relaxed);
|
||||
|
||||
E2D_LOG_DEBUG("Texture cache hit: {}", path);
|
||||
E2D_LOG_DEBUG("纹理缓存命中: {}", path);
|
||||
return TextureRef(it->second.texture, &it->second, &mutex_);
|
||||
}
|
||||
|
||||
|
|
@ -120,14 +120,14 @@ TextureRef TexturePool::load(const std::string& path, const Rect& region,
|
|||
}
|
||||
|
||||
if (!backend) {
|
||||
E2D_LOG_ERROR("TexturePool: RenderBackend not available");
|
||||
E2D_LOG_ERROR("TexturePool: 渲染后端不可用");
|
||||
return TextureRef();
|
||||
}
|
||||
|
||||
// 加载纹理
|
||||
Ptr<Texture> texture = backend->loadTexture(path);
|
||||
if (!texture) {
|
||||
E2D_LOG_ERROR("TexturePool: Failed to load texture: {}", path);
|
||||
E2D_LOG_ERROR("TexturePool: 加载纹理失败: {}", path);
|
||||
return TextureRef();
|
||||
}
|
||||
|
||||
|
|
@ -141,7 +141,7 @@ TextureRef TexturePool::load(const std::string& path, const Rect& region,
|
|||
|
||||
// 再次检查
|
||||
if (currentMemoryUsage_ + memorySize > maxMemoryUsage_) {
|
||||
E2D_LOG_WARN("TexturePool: Memory limit exceeded, cannot load texture: {}", path);
|
||||
E2D_LOG_WARN("TexturePool: 内存限制超出,无法加载纹理: {}", path);
|
||||
return TextureRef();
|
||||
}
|
||||
}
|
||||
|
|
@ -154,7 +154,7 @@ TextureRef TexturePool::load(const std::string& path, const Rect& region,
|
|||
result.first->second.refCount.store(1, std::memory_order_relaxed);
|
||||
result.first->second.touch();
|
||||
currentMemoryUsage_ += memorySize;
|
||||
E2D_LOG_INFO("TexturePool: Loaded texture: {} ({} bytes)", path, memorySize);
|
||||
E2D_LOG_INFO("TexturePool: 已加载纹理: {} ({} 字节)", path, memorySize);
|
||||
return TextureRef(texture, &result.first->second, &mutex_);
|
||||
}
|
||||
|
||||
|
|
@ -196,14 +196,14 @@ TextureRef TexturePool::loadFromMemory(const uint8_t* data, int width, int heigh
|
|||
}
|
||||
|
||||
if (!backend) {
|
||||
E2D_LOG_ERROR("TexturePool: RenderBackend not available");
|
||||
E2D_LOG_ERROR("TexturePool: 渲染后端不可用");
|
||||
return TextureRef();
|
||||
}
|
||||
|
||||
// 创建纹理
|
||||
Ptr<Texture> texture = backend->createTexture(width, height, data, channels);
|
||||
if (!texture) {
|
||||
E2D_LOG_ERROR("TexturePool: Failed to create texture from memory");
|
||||
E2D_LOG_ERROR("TexturePool: 从内存创建纹理失败");
|
||||
return TextureRef();
|
||||
}
|
||||
|
||||
|
|
@ -215,7 +215,7 @@ TextureRef TexturePool::loadFromMemory(const uint8_t* data, int width, int heigh
|
|||
evictLRU(currentMemoryUsage_ + memorySize - maxMemoryUsage_);
|
||||
|
||||
if (currentMemoryUsage_ + memorySize > maxMemoryUsage_) {
|
||||
E2D_LOG_WARN("TexturePool: Memory limit exceeded");
|
||||
E2D_LOG_WARN("TexturePool: 内存限制超出");
|
||||
return TextureRef();
|
||||
}
|
||||
}
|
||||
|
|
@ -228,7 +228,7 @@ TextureRef TexturePool::loadFromMemory(const uint8_t* data, int width, int heigh
|
|||
result.first->second.refCount.store(1, std::memory_order_relaxed);
|
||||
result.first->second.touch();
|
||||
currentMemoryUsage_ += memorySize;
|
||||
E2D_LOG_INFO("TexturePool: Created texture from memory ({} bytes)", memorySize);
|
||||
E2D_LOG_INFO("TexturePool: 已从内存创建纹理 ({} 字节)", memorySize);
|
||||
return TextureRef(texture, &result.first->second, &mutex_);
|
||||
}
|
||||
|
||||
|
|
@ -283,13 +283,13 @@ TextureRef TexturePool::getOrLoad(const std::string& path, const Rect& region,
|
|||
}
|
||||
|
||||
if (!backend) {
|
||||
E2D_LOG_ERROR("TexturePool: RenderBackend not available");
|
||||
E2D_LOG_ERROR("TexturePool: 渲染后端不可用");
|
||||
return TextureRef();
|
||||
}
|
||||
|
||||
Ptr<Texture> texture = backend->loadTexture(path);
|
||||
if (!texture) {
|
||||
E2D_LOG_ERROR("TexturePool: Failed to load texture: {}", path);
|
||||
E2D_LOG_ERROR("TexturePool: 加载纹理失败: {}", path);
|
||||
return TextureRef();
|
||||
}
|
||||
|
||||
|
|
@ -299,7 +299,7 @@ TextureRef TexturePool::getOrLoad(const std::string& path, const Rect& region,
|
|||
evictLRU(currentMemoryUsage_ + memorySize - maxMemoryUsage_);
|
||||
|
||||
if (currentMemoryUsage_ + memorySize > maxMemoryUsage_) {
|
||||
E2D_LOG_WARN("TexturePool: Memory limit exceeded");
|
||||
E2D_LOG_WARN("TexturePool: 内存限制超出");
|
||||
return TextureRef();
|
||||
}
|
||||
}
|
||||
|
|
@ -405,7 +405,7 @@ bool TexturePool::removeFromCache(const TextureKey& key) {
|
|||
if (it != cache_.end()) {
|
||||
currentMemoryUsage_ -= it->second.memorySize;
|
||||
cache_.erase(it);
|
||||
E2D_LOG_DEBUG("TexturePool: Removed texture from cache");
|
||||
E2D_LOG_DEBUG("TexturePool: 已从缓存移除纹理");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -432,7 +432,7 @@ size_t TexturePool::collectGarbage() {
|
|||
}
|
||||
|
||||
if (removed > 0) {
|
||||
E2D_LOG_INFO("TexturePool: Garbage collected {} textures", removed);
|
||||
E2D_LOG_INFO("TexturePool: 垃圾回收 {} 个纹理", removed);
|
||||
}
|
||||
|
||||
return removed;
|
||||
|
|
@ -449,7 +449,7 @@ void TexturePool::clear() {
|
|||
cache_.clear();
|
||||
currentMemoryUsage_ = 0;
|
||||
|
||||
E2D_LOG_INFO("TexturePool: Cleared all textures");
|
||||
E2D_LOG_INFO("TexturePool: 已清除所有纹理");
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -482,7 +482,7 @@ void TexturePool::setMaxMemoryUsage(size_t maxMemory) {
|
|||
evictLRU(maxMemoryUsage_);
|
||||
}
|
||||
|
||||
E2D_LOG_INFO("TexturePool: Max memory set to {} bytes", maxMemory);
|
||||
E2D_LOG_INFO("TexturePool: 最大内存设置为 {} 字节", maxMemory);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -532,7 +532,7 @@ size_t TexturePool::evictLRU(size_t targetMemory) {
|
|||
|
||||
if (evicted > 0) {
|
||||
evictionCount_.fetch_add(evicted, std::memory_order_relaxed);
|
||||
E2D_LOG_INFO("TexturePool: LRU evicted {} textures", evicted);
|
||||
E2D_LOG_INFO("TexturePool: LRU 淘汰 {} 个纹理", evicted);
|
||||
}
|
||||
|
||||
return evicted;
|
||||
|
|
|
|||
|
|
@ -184,13 +184,13 @@ GLFWInput::GLFWInput() {
|
|||
GLFWInput::~GLFWInput() { shutdown(); }
|
||||
|
||||
void GLFWInput::init() {
|
||||
E2D_LOG_INFO("GLFWInput initialized");
|
||||
E2D_LOG_INFO("GLFWInput 已初始化");
|
||||
openGamepad();
|
||||
}
|
||||
|
||||
void GLFWInput::shutdown() {
|
||||
closeGamepad();
|
||||
E2D_LOG_INFO("GLFWInput shutdown");
|
||||
E2D_LOG_INFO("GLFWInput 已关闭");
|
||||
}
|
||||
|
||||
void GLFWInput::update() {
|
||||
|
|
@ -394,13 +394,13 @@ void GLFWInput::handleScrollEvent(double xoffset, double yoffset) {
|
|||
|
||||
void GLFWInput::handleJoystickEvent(int jid, int event) {
|
||||
if (event == GLFW_CONNECTED) {
|
||||
E2D_LOG_INFO("Gamepad connected: {}", jid);
|
||||
E2D_LOG_INFO("游戏手柄已连接: {}", jid);
|
||||
if (gamepadId_ == -1) {
|
||||
openGamepad();
|
||||
}
|
||||
} else if (event == GLFW_DISCONNECTED) {
|
||||
if (jid == gamepadId_) {
|
||||
E2D_LOG_INFO("Gamepad disconnected: {}", jid);
|
||||
E2D_LOG_INFO("游戏手柄已断开: {}", jid);
|
||||
closeGamepad();
|
||||
}
|
||||
}
|
||||
|
|
@ -463,7 +463,7 @@ void GLFWInput::openGamepad() {
|
|||
for (int jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; ++jid) {
|
||||
if (glfwJoystickPresent(jid) && glfwJoystickIsGamepad(jid)) {
|
||||
gamepadId_ = jid;
|
||||
E2D_LOG_INFO("Gamepad opened: {}", glfwGetGamepadName(jid));
|
||||
E2D_LOG_INFO("游戏手柄已打开: {}", glfwGetGamepadName(jid));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
#include <extra2d/services/logger_service.h>
|
||||
#include <glad/glad.h>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
GLFWWindow::GLFWWindow() {}
|
||||
|
|
@ -42,7 +41,7 @@ bool GLFWWindow::create(const std::string &title, int width, int height,
|
|||
glfwCreateWindow(width, height, title.c_str(), monitor, nullptr);
|
||||
|
||||
if (!glfwWindow_) {
|
||||
E2D_LOG_ERROR("Failed to create GLFW window");
|
||||
E2D_LOG_ERROR("创建 GLFW 窗口失败");
|
||||
deinitGLFW();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -66,7 +65,7 @@ bool GLFWWindow::create(const std::string &title, int width, int height,
|
|||
glfwMakeContextCurrent(glfwWindow_);
|
||||
|
||||
if (!gladLoadGLES2Loader((GLADloadproc)glfwGetProcAddress)) {
|
||||
E2D_LOG_ERROR("Failed to initialize GLAD GLES2");
|
||||
E2D_LOG_ERROR("初始化 GLAD GLES2 失败");
|
||||
glfwDestroyWindow(glfwWindow_);
|
||||
glfwWindow_ = nullptr;
|
||||
deinitGLFW();
|
||||
|
|
@ -94,8 +93,7 @@ bool GLFWWindow::create(const std::string &title, int width, int height,
|
|||
input_->setWindow(glfwWindow_);
|
||||
input_->init();
|
||||
|
||||
E2D_LOG_INFO("GLFW window created: {}x{}", width_, height_);
|
||||
E2D_LOG_INFO(" Platform: OpenGL ES 3.2");
|
||||
E2D_LOG_INFO("GLFW 窗口创建成功: {}x{}", width_, height_);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -326,7 +324,7 @@ bool GLFWWindow::initGLFW() {
|
|||
static int glfwInitCount = 0;
|
||||
if (glfwInitCount == 0) {
|
||||
if (!glfwInit()) {
|
||||
E2D_LOG_ERROR("Failed to initialize GLFW");
|
||||
E2D_LOG_ERROR("初始化 GLFW 失败");
|
||||
return false;
|
||||
}
|
||||
glfwInitCount++;
|
||||
|
|
|
|||
|
|
@ -18,10 +18,10 @@ SDL2Input::SDL2Input() {
|
|||
SDL2Input::~SDL2Input() { shutdown(); }
|
||||
|
||||
void SDL2Input::init() {
|
||||
E2D_LOG_INFO("SDL2Input initialized");
|
||||
E2D_LOG_INFO("SDL2Input 已初始化");
|
||||
|
||||
if (SDL_Init(SDL_INIT_GAMECONTROLLER) != 0) {
|
||||
E2D_LOG_WARN("Failed to init gamecontroller subsystem: {}", SDL_GetError());
|
||||
E2D_LOG_WARN("初始化游戏手柄子系统失败: {}", SDL_GetError());
|
||||
}
|
||||
|
||||
openGamepad();
|
||||
|
|
@ -29,7 +29,7 @@ void SDL2Input::init() {
|
|||
|
||||
void SDL2Input::shutdown() {
|
||||
closeGamepad();
|
||||
E2D_LOG_INFO("SDL2Input shutdown");
|
||||
E2D_LOG_INFO("SDL2Input 已关闭");
|
||||
}
|
||||
|
||||
void SDL2Input::update() {
|
||||
|
|
@ -131,7 +131,7 @@ void SDL2Input::handleSDLEvent(const SDL_Event &event) {
|
|||
}
|
||||
|
||||
case SDL_CONTROLLERDEVICEADDED:
|
||||
E2D_LOG_INFO("Gamepad connected: index {}", event.cdevice.which);
|
||||
E2D_LOG_INFO("游戏手柄已连接: 索引 {}", event.cdevice.which);
|
||||
openGamepad();
|
||||
break;
|
||||
|
||||
|
|
@ -139,7 +139,7 @@ void SDL2Input::handleSDLEvent(const SDL_Event &event) {
|
|||
if (gamepad_ &&
|
||||
event.cdevice.which ==
|
||||
SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(gamepad_))) {
|
||||
E2D_LOG_INFO("Gamepad disconnected");
|
||||
E2D_LOG_INFO("游戏手柄已断开");
|
||||
closeGamepad();
|
||||
}
|
||||
break;
|
||||
|
|
@ -354,7 +354,7 @@ void SDL2Input::openGamepad() {
|
|||
gamepad_ = SDL_GameControllerOpen(i);
|
||||
if (gamepad_) {
|
||||
gamepadIndex_ = i;
|
||||
E2D_LOG_INFO("Gamepad opened: {}", SDL_GameControllerName(gamepad_));
|
||||
E2D_LOG_INFO("游戏手柄已打开: {}", SDL_GameControllerName(gamepad_));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,14 +39,14 @@ bool SDL2Window::create(const std::string &title, int width, int height,
|
|||
SDL_WINDOWPOS_CENTERED, width, height, flags);
|
||||
|
||||
if (!sdlWindow_) {
|
||||
E2D_LOG_ERROR("Failed to create SDL window: {}", SDL_GetError());
|
||||
E2D_LOG_ERROR("创建 SDL 窗口失败: {}", SDL_GetError());
|
||||
deinitSDL();
|
||||
return false;
|
||||
}
|
||||
|
||||
glContext_ = SDL_GL_CreateContext(sdlWindow_);
|
||||
if (!glContext_) {
|
||||
E2D_LOG_ERROR("Failed to create OpenGL context: {}", SDL_GetError());
|
||||
E2D_LOG_ERROR("创建 OpenGL 上下文失败: {}", SDL_GetError());
|
||||
SDL_DestroyWindow(sdlWindow_);
|
||||
sdlWindow_ = nullptr;
|
||||
deinitSDL();
|
||||
|
|
@ -54,7 +54,7 @@ bool SDL2Window::create(const std::string &title, int width, int height,
|
|||
}
|
||||
|
||||
if (!gladLoadGLES2Loader((GLADloadproc)SDL_GL_GetProcAddress)) {
|
||||
E2D_LOG_ERROR("Failed to initialize GLAD GLES2");
|
||||
E2D_LOG_ERROR("初始化 GLAD GLES2 失败");
|
||||
SDL_GL_DeleteContext(glContext_);
|
||||
glContext_ = nullptr;
|
||||
SDL_DestroyWindow(sdlWindow_);
|
||||
|
|
@ -77,8 +77,8 @@ bool SDL2Window::create(const std::string &title, int width, int height,
|
|||
input_ = makeUnique<SDL2Input>();
|
||||
input_->init();
|
||||
|
||||
E2D_LOG_INFO("SDL2 window created: {}x{}", width_, height_);
|
||||
E2D_LOG_INFO(" Platform: OpenGL ES 3.2");
|
||||
E2D_LOG_INFO("SDL2 窗口创建成功: {}x{}", width_, height_);
|
||||
E2D_LOG_INFO(" 平台: OpenGL ES 3.2");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -270,7 +270,7 @@ bool SDL2Window::initSDL() {
|
|||
if (sdlInitCount == 0) {
|
||||
Uint32 initFlags = SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER;
|
||||
if (SDL_Init(initFlags) != 0) {
|
||||
E2D_LOG_ERROR("Failed to initialize SDL: {}", SDL_GetError());
|
||||
E2D_LOG_ERROR("初始化 SDL 失败: {}", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
sdlInitCount++;
|
||||
|
|
|
|||
|
|
@ -41,24 +41,24 @@ bool WindowModule::init() {
|
|||
#error "No window backend defined"
|
||||
#endif
|
||||
|
||||
E2D_LOG_INFO("Window backend initialized");
|
||||
E2D_LOG_INFO("窗口后端已初始化");
|
||||
|
||||
E2D_LOG_INFO("Creating window with size {}x{}", cfg_.w, cfg_.h);
|
||||
E2D_LOG_INFO("正在创建窗口,尺寸 {}x{}", cfg_.w, cfg_.h);
|
||||
|
||||
// 创建窗口(使用配置的后端)
|
||||
win_ = platform::BackendFactory::createWindow(cfg_.backend);
|
||||
if (!win_) {
|
||||
E2D_LOG_ERROR("Failed to create window backend: {}", cfg_.backend);
|
||||
E2D_LOG_ERROR("创建窗口后端失败: {}", cfg_.backend);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!win_->create(cfg_.title, cfg_.w, cfg_.h, cfg_.vsync)) {
|
||||
E2D_LOG_ERROR("Failed to create window");
|
||||
E2D_LOG_ERROR("创建窗口失败");
|
||||
shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
E2D_LOG_INFO("Window created successfully");
|
||||
E2D_LOG_INFO("窗口创建成功");
|
||||
initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ void SceneManager::runWithScene(Ptr<Scene> scene) {
|
|||
}
|
||||
|
||||
if (!sceneStack_.empty()) {
|
||||
E2D_LOG_WARN("SceneManager: runWithScene should only be called once");
|
||||
E2D_LOG_WARN("SceneManager: runWithScene 应该只被调用一次");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -575,15 +575,15 @@ void SceneManager::render(RenderBackend &renderer) {
|
|||
clearColor = sceneStack_.top()->getBackgroundColor();
|
||||
}
|
||||
|
||||
E2D_LOG_TRACE("SceneManager::render - beginFrame with color({}, {}, {})",
|
||||
E2D_LOG_TRACE("SceneManager::render - beginFrame 颜色({}, {}, {})",
|
||||
clearColor.r, clearColor.g, clearColor.b);
|
||||
renderer.beginFrame(clearColor);
|
||||
|
||||
if (!sceneStack_.empty()) {
|
||||
E2D_LOG_TRACE("SceneManager::render - rendering scene content");
|
||||
E2D_LOG_TRACE("SceneManager::render - 正在渲染场景内容");
|
||||
sceneStack_.top()->renderContent(renderer);
|
||||
} else {
|
||||
E2D_LOG_WARN("SceneManager::render - no scene to render");
|
||||
E2D_LOG_WARN("SceneManager::render - 没有场景可渲染");
|
||||
}
|
||||
|
||||
renderer.endFrame();
|
||||
|
|
|
|||
Loading…
Reference in New Issue