From 579aa2dd0d3ecddb90bf47b39687cfdc4ff9f26e Mon Sep 17 00:00:00 2001 From: ChestnutYueyue <952134128@qq.com> Date: Tue, 3 Mar 2026 21:23:54 +0800 Subject: [PATCH] =?UTF-8?q?refactor(logger):=20=E6=9B=BF=E6=8D=A2=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E7=B3=BB=E7=BB=9F=E4=B8=BAspdlog=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 重构日志系统,使用spdlog替代原有实现,提供更强大的格式化功能和性能优化 移除自定义日志格式化和级别处理代码,统一使用spdlog接口 更新所有日志调用点,移除E2D_LOG_前缀宏,简化为E2D_前缀 添加spdlog为第三方依赖,更新构建配置 --- .claude/settings.local.json | 7 - include/renderer/rhi/opengl/gl_utils.h | 578 +++++++++++++------- include/utils/logger.h | 321 ++++-------- src/app/application.cpp | 33 +- src/assets/assets_module.cpp | 132 +++-- src/assets/loaders/shader_loader.cpp | 19 +- src/assets/loaders/texture_loader.cpp | 11 +- src/platform/file_module.cpp | 14 +- src/platform/window_module.cpp | 18 +- src/renderer/command_queue.cpp | 86 +-- src/renderer/material.cpp | 257 ++++----- src/renderer/mesh.cpp | 24 +- src/renderer/render_graph.cpp | 12 +- src/renderer/renderer_module.cpp | 38 +- src/renderer/rhi/opengl/gl_context.cpp | 8 +- src/renderer/rhi/opengl/gl_device.cpp | 54 +- src/renderer/rhi_module.cpp | 45 +- src/renderer/shader.cpp | 20 +- src/renderer/texture.cpp | 436 +++++++++------- src/renderer/texture_atlas.cpp | 610 +++++++++++----------- src/renderer/uniform_buffer.cpp | 34 +- src/scene/components/camera_component.cpp | 4 +- src/scene/director.cpp | 2 +- src/utils/logger.cpp | 164 +++--- xmake/engine.lua | 6 +- 25 files changed, 1500 insertions(+), 1433 deletions(-) delete mode 100644 .claude/settings.local.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index 25655fa..0000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(git diff:*)" - ] - } -} diff --git a/include/renderer/rhi/opengl/gl_utils.h b/include/renderer/rhi/opengl/gl_utils.h index 3afbc25..1787032 100644 --- a/include/renderer/rhi/opengl/gl_utils.h +++ b/include/renderer/rhi/opengl/gl_utils.h @@ -1,7 +1,7 @@ #pragma once -#include #include +#include #include namespace extra2d { @@ -9,299 +9,485 @@ namespace extra2d { /** * @brief OpenGL 错误检查宏 */ -#define GL_CHECK(call) do { \ - call; \ - GLenum err = glGetError(); \ - if (err != GL_NO_ERROR) { \ - E2D_LOG_ERROR("OpenGL 错误在 {}: {} ({})", #call, getGLErrorString(err), err); \ - } \ -} while(0) +#define GL_CHECK(call) \ + do { \ + call; \ + GLenum err = glGetError(); \ + if (err != GL_NO_ERROR) { \ + E2D_ERROR("OpenGL 错误在 {}: {} ({})", #call, getGLErrorString(err), \ + err); \ + } \ + } while (0) /** * @brief 获取 OpenGL 错误字符串 * @param error OpenGL 错误码 * @return 错误描述字符串 */ -inline const char* getGLErrorString(GLenum error) { - switch (error) { - case GL_NO_ERROR: return "GL_NO_ERROR"; - case GL_INVALID_ENUM: return "GL_INVALID_ENUM"; - case GL_INVALID_VALUE: return "GL_INVALID_VALUE"; - case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION"; - case GL_STACK_OVERFLOW: return "GL_STACK_OVERFLOW"; - case GL_STACK_UNDERFLOW: return "GL_STACK_UNDERFLOW"; - case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY"; - case GL_INVALID_FRAMEBUFFER_OPERATION: return "GL_INVALID_FRAMEBUFFER_OPERATION"; - default: return "Unknown Error"; - } +inline const char *getGLErrorString(GLenum error) { + switch (error) { + case GL_NO_ERROR: + return "GL_NO_ERROR"; + case GL_INVALID_ENUM: + return "GL_INVALID_ENUM"; + case GL_INVALID_VALUE: + return "GL_INVALID_VALUE"; + case GL_INVALID_OPERATION: + return "GL_INVALID_OPERATION"; + case GL_STACK_OVERFLOW: + return "GL_STACK_OVERFLOW"; + case GL_STACK_UNDERFLOW: + return "GL_STACK_UNDERFLOW"; + case GL_OUT_OF_MEMORY: + return "GL_OUT_OF_MEMORY"; + case GL_INVALID_FRAMEBUFFER_OPERATION: + return "GL_INVALID_FRAMEBUFFER_OPERATION"; + default: + return "Unknown Error"; + } } /** * @brief 将 BufferType 转换为 OpenGL 缓冲区目标 */ inline GLenum bufferTypeToGL(BufferType type) { - switch (type) { - case BufferType::Vertex: return GL_ARRAY_BUFFER; - case BufferType::Index: return GL_ELEMENT_ARRAY_BUFFER; - case BufferType::Uniform: return GL_UNIFORM_BUFFER; - case BufferType::Storage: return GL_SHADER_STORAGE_BUFFER; - case BufferType::Staging: return GL_ARRAY_BUFFER; - default: return GL_ARRAY_BUFFER; - } + switch (type) { + case BufferType::Vertex: + return GL_ARRAY_BUFFER; + case BufferType::Index: + return GL_ELEMENT_ARRAY_BUFFER; + case BufferType::Uniform: + return GL_UNIFORM_BUFFER; + case BufferType::Storage: + return GL_SHADER_STORAGE_BUFFER; + case BufferType::Staging: + return GL_ARRAY_BUFFER; + default: + return GL_ARRAY_BUFFER; + } } /** * @brief 将 BufferUsage 转换为 OpenGL 使用模式 */ inline GLenum bufferUsageToGL(BufferUsage usage) { - switch (usage) { - case BufferUsage::Static: return GL_STATIC_DRAW; - case BufferUsage::Dynamic: return GL_DYNAMIC_DRAW; - case BufferUsage::Stream: return GL_STREAM_DRAW; - default: return GL_STATIC_DRAW; - } + switch (usage) { + case BufferUsage::Static: + return GL_STATIC_DRAW; + case BufferUsage::Dynamic: + return GL_DYNAMIC_DRAW; + case BufferUsage::Stream: + return GL_STREAM_DRAW; + default: + return GL_STATIC_DRAW; + } } /** * @brief 将 TextureFormat 转换为 OpenGL 内部格式 */ inline GLenum textureFormatToGLInternal(TextureFormat format) { - switch (format) { - case TextureFormat::R8: return GL_R8; - case TextureFormat::RG8: return GL_RG8; - case TextureFormat::RGB8: return GL_RGB8; - case TextureFormat::RGBA8: return GL_RGBA8; - case TextureFormat::RGBA8_SRGB: return GL_SRGB8_ALPHA8; - case TextureFormat::Depth16: return GL_DEPTH_COMPONENT16; - case TextureFormat::Depth24: return GL_DEPTH_COMPONENT24; - case TextureFormat::Depth32F: return GL_DEPTH_COMPONENT32F; - case TextureFormat::Depth24Stencil8: return GL_DEPTH24_STENCIL8; - case TextureFormat::Depth32FStencil8:return GL_DEPTH32F_STENCIL8; - case TextureFormat::BC1: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - case TextureFormat::BC3: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - case TextureFormat::BC5: return 0x8DBD; // GL_COMPRESSED_RG_RGTC2 - default: return GL_RGBA8; - } + switch (format) { + case TextureFormat::R8: + return GL_R8; + case TextureFormat::RG8: + return GL_RG8; + case TextureFormat::RGB8: + return GL_RGB8; + case TextureFormat::RGBA8: + return GL_RGBA8; + case TextureFormat::RGBA8_SRGB: + return GL_SRGB8_ALPHA8; + case TextureFormat::Depth16: + return GL_DEPTH_COMPONENT16; + case TextureFormat::Depth24: + return GL_DEPTH_COMPONENT24; + case TextureFormat::Depth32F: + return GL_DEPTH_COMPONENT32F; + case TextureFormat::Depth24Stencil8: + return GL_DEPTH24_STENCIL8; + case TextureFormat::Depth32FStencil8: + return GL_DEPTH32F_STENCIL8; + case TextureFormat::BC1: + return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + case TextureFormat::BC3: + return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + case TextureFormat::BC5: + return 0x8DBD; // GL_COMPRESSED_RG_RGTC2 + default: + return GL_RGBA8; + } } /** * @brief 将 TextureFormat 转换为 OpenGL 格式 */ inline GLenum textureFormatToGLFormat(TextureFormat format) { - switch (format) { - case TextureFormat::R8: return GL_RED; - case TextureFormat::RG8: return GL_RG; - case TextureFormat::RGB8: return GL_RGB; - case TextureFormat::RGBA8: - case TextureFormat::RGBA8_SRGB: return GL_RGBA; - case TextureFormat::Depth16: - case TextureFormat::Depth24: - case TextureFormat::Depth32F: return GL_DEPTH_COMPONENT; - case TextureFormat::Depth24Stencil8: - case TextureFormat::Depth32FStencil8:return GL_DEPTH_STENCIL; - default: return GL_RGBA; - } + switch (format) { + case TextureFormat::R8: + return GL_RED; + case TextureFormat::RG8: + return GL_RG; + case TextureFormat::RGB8: + return GL_RGB; + case TextureFormat::RGBA8: + case TextureFormat::RGBA8_SRGB: + return GL_RGBA; + case TextureFormat::Depth16: + case TextureFormat::Depth24: + case TextureFormat::Depth32F: + return GL_DEPTH_COMPONENT; + case TextureFormat::Depth24Stencil8: + case TextureFormat::Depth32FStencil8: + return GL_DEPTH_STENCIL; + default: + return GL_RGBA; + } } /** * @brief 将 TextureFormat 转换为 OpenGL 数据类型 */ inline GLenum textureFormatToGLType(TextureFormat format) { - switch (format) { - case TextureFormat::R8: - case TextureFormat::RG8: - case TextureFormat::RGB8: - case TextureFormat::RGBA8: - case TextureFormat::RGBA8_SRGB: return GL_UNSIGNED_BYTE; - case TextureFormat::Depth16: return GL_UNSIGNED_SHORT; - case TextureFormat::Depth24: return GL_UNSIGNED_INT; - case TextureFormat::Depth32F: return GL_FLOAT; - case TextureFormat::Depth24Stencil8: return GL_UNSIGNED_INT_24_8; - case TextureFormat::Depth32FStencil8:return GL_FLOAT_32_UNSIGNED_INT_24_8_REV; - default: return GL_UNSIGNED_BYTE; - } + switch (format) { + case TextureFormat::R8: + case TextureFormat::RG8: + case TextureFormat::RGB8: + case TextureFormat::RGBA8: + case TextureFormat::RGBA8_SRGB: + return GL_UNSIGNED_BYTE; + case TextureFormat::Depth16: + return GL_UNSIGNED_SHORT; + case TextureFormat::Depth24: + return GL_UNSIGNED_INT; + case TextureFormat::Depth32F: + return GL_FLOAT; + case TextureFormat::Depth24Stencil8: + return GL_UNSIGNED_INT_24_8; + case TextureFormat::Depth32FStencil8: + return GL_FLOAT_32_UNSIGNED_INT_24_8_REV; + default: + return GL_UNSIGNED_BYTE; + } } /** * @brief 将 TextureFilter 转换为 OpenGL 过滤模式 */ inline GLenum textureFilterToGLMin(TextureFilter filter) { - switch (filter) { - case TextureFilter::Nearest: return GL_NEAREST; - case TextureFilter::Linear: return GL_LINEAR; - case TextureFilter::NearestMipmapNearest: return GL_NEAREST_MIPMAP_NEAREST; - case TextureFilter::LinearMipmapNearest: return GL_LINEAR_MIPMAP_NEAREST; - case TextureFilter::NearestMipmapLinear: return GL_NEAREST_MIPMAP_LINEAR; - case TextureFilter::LinearMipmapLinear: return GL_LINEAR_MIPMAP_LINEAR; - default: return GL_LINEAR; - } + switch (filter) { + case TextureFilter::Nearest: + return GL_NEAREST; + case TextureFilter::Linear: + return GL_LINEAR; + case TextureFilter::NearestMipmapNearest: + return GL_NEAREST_MIPMAP_NEAREST; + case TextureFilter::LinearMipmapNearest: + return GL_LINEAR_MIPMAP_NEAREST; + case TextureFilter::NearestMipmapLinear: + return GL_NEAREST_MIPMAP_LINEAR; + case TextureFilter::LinearMipmapLinear: + return GL_LINEAR_MIPMAP_LINEAR; + default: + return GL_LINEAR; + } } inline GLenum textureFilterToGLMag(TextureFilter filter) { - // Mag filter doesn't support mipmaps - switch (filter) { - case TextureFilter::Nearest: - case TextureFilter::NearestMipmapNearest: - case TextureFilter::NearestMipmapLinear: - return GL_NEAREST; - case TextureFilter::Linear: - case TextureFilter::LinearMipmapNearest: - case TextureFilter::LinearMipmapLinear: - default: - return GL_LINEAR; - } + // Mag filter doesn't support mipmaps + switch (filter) { + case TextureFilter::Nearest: + case TextureFilter::NearestMipmapNearest: + case TextureFilter::NearestMipmapLinear: + return GL_NEAREST; + case TextureFilter::Linear: + case TextureFilter::LinearMipmapNearest: + case TextureFilter::LinearMipmapLinear: + default: + return GL_LINEAR; + } } /** * @brief 将 TextureWrap 转换为 OpenGL 环绕模式 */ inline GLenum textureWrapToGL(TextureWrap wrap) { - switch (wrap) { - case TextureWrap::Repeat: return GL_REPEAT; - case TextureWrap::ClampToEdge: return GL_CLAMP_TO_EDGE; - case TextureWrap::ClampToBorder: return GL_CLAMP_TO_BORDER; - case TextureWrap::MirroredRepeat: return GL_MIRRORED_REPEAT; - default: return GL_REPEAT; - } + switch (wrap) { + case TextureWrap::Repeat: + return GL_REPEAT; + case TextureWrap::ClampToEdge: + return GL_CLAMP_TO_EDGE; + case TextureWrap::ClampToBorder: + return GL_CLAMP_TO_BORDER; + case TextureWrap::MirroredRepeat: + return GL_MIRRORED_REPEAT; + default: + return GL_REPEAT; + } } /** * @brief 将 VertexFormat 转换为 OpenGL 格式 */ -inline void vertexFormatToGL(VertexFormat format, GLint& components, GLenum& type, GLboolean& normalized) { - switch (format) { - case VertexFormat::Float1: components = 1; type = GL_FLOAT; normalized = GL_FALSE; break; - case VertexFormat::Float2: components = 2; type = GL_FLOAT; normalized = GL_FALSE; break; - case VertexFormat::Float3: components = 3; type = GL_FLOAT; normalized = GL_FALSE; break; - case VertexFormat::Float4: components = 4; type = GL_FLOAT; normalized = GL_FALSE; break; - case VertexFormat::Int1: components = 1; type = GL_INT; normalized = GL_FALSE; break; - case VertexFormat::Int2: components = 2; type = GL_INT; normalized = GL_FALSE; break; - case VertexFormat::Int3: components = 3; type = GL_INT; normalized = GL_FALSE; break; - case VertexFormat::Int4: components = 4; type = GL_INT; normalized = GL_FALSE; break; - case VertexFormat::UInt1: components = 1; type = GL_UNSIGNED_INT; normalized = GL_FALSE; break; - case VertexFormat::UInt2: components = 2; type = GL_UNSIGNED_INT; normalized = GL_FALSE; break; - case VertexFormat::UInt3: components = 3; type = GL_UNSIGNED_INT; normalized = GL_FALSE; break; - case VertexFormat::UInt4: components = 4; type = GL_UNSIGNED_INT; normalized = GL_FALSE; break; - case VertexFormat::Byte4: components = 4; type = GL_BYTE; normalized = GL_FALSE; break; - case VertexFormat::Byte4Normalized: components = 4; type = GL_BYTE; normalized = GL_TRUE; break; - case VertexFormat::UByte4: components = 4; type = GL_UNSIGNED_BYTE; normalized = GL_FALSE; break; - case VertexFormat::UByte4Normalized:components = 4; type = GL_UNSIGNED_BYTE; normalized = GL_TRUE; break; - default: components = 4; type = GL_FLOAT; normalized = GL_FALSE; break; - } +inline void vertexFormatToGL(VertexFormat format, GLint &components, + GLenum &type, GLboolean &normalized) { + switch (format) { + case VertexFormat::Float1: + components = 1; + type = GL_FLOAT; + normalized = GL_FALSE; + break; + case VertexFormat::Float2: + components = 2; + type = GL_FLOAT; + normalized = GL_FALSE; + break; + case VertexFormat::Float3: + components = 3; + type = GL_FLOAT; + normalized = GL_FALSE; + break; + case VertexFormat::Float4: + components = 4; + type = GL_FLOAT; + normalized = GL_FALSE; + break; + case VertexFormat::Int1: + components = 1; + type = GL_INT; + normalized = GL_FALSE; + break; + case VertexFormat::Int2: + components = 2; + type = GL_INT; + normalized = GL_FALSE; + break; + case VertexFormat::Int3: + components = 3; + type = GL_INT; + normalized = GL_FALSE; + break; + case VertexFormat::Int4: + components = 4; + type = GL_INT; + normalized = GL_FALSE; + break; + case VertexFormat::UInt1: + components = 1; + type = GL_UNSIGNED_INT; + normalized = GL_FALSE; + break; + case VertexFormat::UInt2: + components = 2; + type = GL_UNSIGNED_INT; + normalized = GL_FALSE; + break; + case VertexFormat::UInt3: + components = 3; + type = GL_UNSIGNED_INT; + normalized = GL_FALSE; + break; + case VertexFormat::UInt4: + components = 4; + type = GL_UNSIGNED_INT; + normalized = GL_FALSE; + break; + case VertexFormat::Byte4: + components = 4; + type = GL_BYTE; + normalized = GL_FALSE; + break; + case VertexFormat::Byte4Normalized: + components = 4; + type = GL_BYTE; + normalized = GL_TRUE; + break; + case VertexFormat::UByte4: + components = 4; + type = GL_UNSIGNED_BYTE; + normalized = GL_FALSE; + break; + case VertexFormat::UByte4Normalized: + components = 4; + type = GL_UNSIGNED_BYTE; + normalized = GL_TRUE; + break; + default: + components = 4; + type = GL_FLOAT; + normalized = GL_FALSE; + break; + } } /** * @brief 将 IndexType 转换为 OpenGL 类型 */ inline GLenum indexTypeToGL(IndexType type) { - switch (type) { - case IndexType::UInt16: return GL_UNSIGNED_SHORT; - case IndexType::UInt32: return GL_UNSIGNED_INT; - default: return GL_UNSIGNED_SHORT; - } + switch (type) { + case IndexType::UInt16: + return GL_UNSIGNED_SHORT; + case IndexType::UInt32: + return GL_UNSIGNED_INT; + default: + return GL_UNSIGNED_SHORT; + } } /** * @brief 将 PrimitiveType 转换为 OpenGL 图元类型 */ inline GLenum primitiveTypeToGL(PrimitiveType type) { - switch (type) { - case PrimitiveType::Points: return GL_POINTS; - case PrimitiveType::Lines: return GL_LINES; - case PrimitiveType::LineStrip: return GL_LINE_STRIP; - case PrimitiveType::Triangles: return GL_TRIANGLES; - case PrimitiveType::TriangleStrip: return GL_TRIANGLE_STRIP; - case PrimitiveType::TriangleFan: return GL_TRIANGLE_FAN; - default: return GL_TRIANGLES; - } + switch (type) { + case PrimitiveType::Points: + return GL_POINTS; + case PrimitiveType::Lines: + return GL_LINES; + case PrimitiveType::LineStrip: + return GL_LINE_STRIP; + case PrimitiveType::Triangles: + return GL_TRIANGLES; + case PrimitiveType::TriangleStrip: + return GL_TRIANGLE_STRIP; + case PrimitiveType::TriangleFan: + return GL_TRIANGLE_FAN; + default: + return GL_TRIANGLES; + } } /** * @brief 将 BlendFactor 转换为 OpenGL 混合因子 */ inline GLenum blendFactorToGL(BlendFactor factor) { - switch (factor) { - case BlendFactor::Zero: return GL_ZERO; - case BlendFactor::One: return GL_ONE; - case BlendFactor::SrcColor: return GL_SRC_COLOR; - case BlendFactor::OneMinusSrcColor: return GL_ONE_MINUS_SRC_COLOR; - case BlendFactor::DstColor: return GL_DST_COLOR; - case BlendFactor::OneMinusDstColor: return GL_ONE_MINUS_DST_COLOR; - case BlendFactor::SrcAlpha: return GL_SRC_ALPHA; - case BlendFactor::OneMinusSrcAlpha: return GL_ONE_MINUS_SRC_ALPHA; - case BlendFactor::DstAlpha: return GL_DST_ALPHA; - case BlendFactor::OneMinusDstAlpha: return GL_ONE_MINUS_DST_ALPHA; - default: return GL_ONE; - } + switch (factor) { + case BlendFactor::Zero: + return GL_ZERO; + case BlendFactor::One: + return GL_ONE; + case BlendFactor::SrcColor: + return GL_SRC_COLOR; + case BlendFactor::OneMinusSrcColor: + return GL_ONE_MINUS_SRC_COLOR; + case BlendFactor::DstColor: + return GL_DST_COLOR; + case BlendFactor::OneMinusDstColor: + return GL_ONE_MINUS_DST_COLOR; + case BlendFactor::SrcAlpha: + return GL_SRC_ALPHA; + case BlendFactor::OneMinusSrcAlpha: + return GL_ONE_MINUS_SRC_ALPHA; + case BlendFactor::DstAlpha: + return GL_DST_ALPHA; + case BlendFactor::OneMinusDstAlpha: + return GL_ONE_MINUS_DST_ALPHA; + default: + return GL_ONE; + } } /** * @brief 将 BlendOp 转换为 OpenGL 混合操作 */ inline GLenum blendOpToGL(BlendOp op) { - switch (op) { - case BlendOp::Add: return GL_FUNC_ADD; - case BlendOp::Subtract: return GL_FUNC_SUBTRACT; - case BlendOp::ReverseSubtract: return GL_FUNC_REVERSE_SUBTRACT; - case BlendOp::Min: return GL_MIN; - case BlendOp::Max: return GL_MAX; - default: return GL_FUNC_ADD; - } + switch (op) { + case BlendOp::Add: + return GL_FUNC_ADD; + case BlendOp::Subtract: + return GL_FUNC_SUBTRACT; + case BlendOp::ReverseSubtract: + return GL_FUNC_REVERSE_SUBTRACT; + case BlendOp::Min: + return GL_MIN; + case BlendOp::Max: + return GL_MAX; + default: + return GL_FUNC_ADD; + } } /** * @brief 将 CompareFunc 转换为 OpenGL 比较函数 */ inline GLenum compareFuncToGL(CompareFunc func) { - switch (func) { - case CompareFunc::Never: return GL_NEVER; - case CompareFunc::Less: return GL_LESS; - case CompareFunc::Equal: return GL_EQUAL; - case CompareFunc::LessEqual: return GL_LEQUAL; - case CompareFunc::Greater: return GL_GREATER; - case CompareFunc::NotEqual: return GL_NOTEQUAL; - case CompareFunc::GreaterEqual: return GL_GEQUAL; - case CompareFunc::Always: return GL_ALWAYS; - default: return GL_LESS; - } + switch (func) { + case CompareFunc::Never: + return GL_NEVER; + case CompareFunc::Less: + return GL_LESS; + case CompareFunc::Equal: + return GL_EQUAL; + case CompareFunc::LessEqual: + return GL_LEQUAL; + case CompareFunc::Greater: + return GL_GREATER; + case CompareFunc::NotEqual: + return GL_NOTEQUAL; + case CompareFunc::GreaterEqual: + return GL_GEQUAL; + case CompareFunc::Always: + return GL_ALWAYS; + default: + return GL_LESS; + } } /** * @brief 将 ShaderType 转换为 OpenGL 着色器类型 */ inline GLenum shaderTypeToGL(ShaderType type) { - switch (type) { - case ShaderType::Vertex: return GL_VERTEX_SHADER; - case ShaderType::Fragment: return GL_FRAGMENT_SHADER; - case ShaderType::Geometry: return GL_GEOMETRY_SHADER; - case ShaderType::Compute: return GL_COMPUTE_SHADER; - default: return GL_VERTEX_SHADER; - } + switch (type) { + case ShaderType::Vertex: + return GL_VERTEX_SHADER; + case ShaderType::Fragment: + return GL_FRAGMENT_SHADER; + case ShaderType::Geometry: + return GL_GEOMETRY_SHADER; + case ShaderType::Compute: + return GL_COMPUTE_SHADER; + default: + return GL_VERTEX_SHADER; + } } /** * @brief 获取 VertexFormat 的大小(字节) */ inline uint32_t getVertexFormatSize(VertexFormat format) { - switch (format) { - case VertexFormat::Float1: return sizeof(float) * 1; - case VertexFormat::Float2: return sizeof(float) * 2; - case VertexFormat::Float3: return sizeof(float) * 3; - case VertexFormat::Float4: return sizeof(float) * 4; - case VertexFormat::Int1: return sizeof(int32_t) * 1; - case VertexFormat::Int2: return sizeof(int32_t) * 2; - case VertexFormat::Int3: return sizeof(int32_t) * 3; - case VertexFormat::Int4: return sizeof(int32_t) * 4; - case VertexFormat::UInt1: return sizeof(uint32_t) * 1; - case VertexFormat::UInt2: return sizeof(uint32_t) * 2; - case VertexFormat::UInt3: return sizeof(uint32_t) * 3; - case VertexFormat::UInt4: return sizeof(uint32_t) * 4; - case VertexFormat::Byte4: - case VertexFormat::Byte4Normalized: return sizeof(int8_t) * 4; - case VertexFormat::UByte4: - case VertexFormat::UByte4Normalized: return sizeof(uint8_t) * 4; - default: return sizeof(float) * 4; - } + switch (format) { + case VertexFormat::Float1: + return sizeof(float) * 1; + case VertexFormat::Float2: + return sizeof(float) * 2; + case VertexFormat::Float3: + return sizeof(float) * 3; + case VertexFormat::Float4: + return sizeof(float) * 4; + case VertexFormat::Int1: + return sizeof(int32_t) * 1; + case VertexFormat::Int2: + return sizeof(int32_t) * 2; + case VertexFormat::Int3: + return sizeof(int32_t) * 3; + case VertexFormat::Int4: + return sizeof(int32_t) * 4; + case VertexFormat::UInt1: + return sizeof(uint32_t) * 1; + case VertexFormat::UInt2: + return sizeof(uint32_t) * 2; + case VertexFormat::UInt3: + return sizeof(uint32_t) * 3; + case VertexFormat::UInt4: + return sizeof(uint32_t) * 4; + case VertexFormat::Byte4: + case VertexFormat::Byte4Normalized: + return sizeof(int8_t) * 4; + case VertexFormat::UByte4: + case VertexFormat::UByte4Normalized: + return sizeof(uint8_t) * 4; + default: + return sizeof(float) * 4; + } } } // namespace extra2d diff --git a/include/utils/logger.h b/include/utils/logger.h index 5cb6d16..15d3903 100644 --- a/include/utils/logger.h +++ b/include/utils/logger.h @@ -1,172 +1,37 @@ #pragma once -#include -#include +#include #include -#include -#include +#include + +#include +#include -// Switch 平台支持 #ifdef __SWITCH__ - #include -#endif - -#ifndef TEST_BUILD -// SDL2 日志头文件(测试构建时不使用) -#include +#include #endif namespace extra2d { -// ============================================================================ -// 日志级别枚举 -// ============================================================================ +/** + * @brief 日志级别枚举 + */ enum class LogLevel { -#ifdef TEST_BUILD - Trace = 0, - Debug = 1, - Info = 2, - Warn = 3, - Error = 4, - Fatal = 5, - Off = 6 -#else - Trace = SDL_LOG_PRIORITY_VERBOSE, // SDL 详细日志 - Debug = SDL_LOG_PRIORITY_DEBUG, // SDL 调试日志 - Info = SDL_LOG_PRIORITY_INFO, // SDL 信息日志 - Warn = SDL_LOG_PRIORITY_WARN, // SDL 警告日志 - Error = SDL_LOG_PRIORITY_ERROR, // SDL 错误日志 - Fatal = SDL_LOG_PRIORITY_CRITICAL, // SDL 严重日志 - Off = SDL_LOG_PRIORITY_CRITICAL + 1 // 关闭日志 -#endif + Trace = spdlog::level::trace, + Debug = spdlog::level::debug, + Info = spdlog::level::info, + Warn = spdlog::level::warn, + Error = spdlog::level::err, + Fatal = spdlog::level::critical, + Off = spdlog::level::off }; -// ============================================================================ -// 简单的 fmt-style {} 格式化器 -// ============================================================================ -namespace detail { - -// 将单个参数转为字符串 -template inline std::string to_string_arg(const T &value) { - if constexpr (std::is_same_v) { - return value; - } else if constexpr (std::is_same_v || - std::is_same_v) { - return value ? std::string(value) : std::string("(null)"); - } else if constexpr (std::is_same_v) { - return value ? "true" : "false"; - } else if constexpr (std::is_arithmetic_v) { - // 对浮点数使用特殊格式 - if constexpr (std::is_floating_point_v) { - char buf[64]; - snprintf(buf, sizeof(buf), "%.2f", static_cast(value)); - return buf; - } else { - return std::to_string(value); - } - } else { - std::ostringstream oss; - oss << value; - return oss.str(); - } -} - -// 格式化基础情况:没有更多参数 -inline std::string format_impl(const char *fmt) { - std::string result; - while (*fmt) { - if (*fmt == '{' && *(fmt + 1) == '}') { - result += "{}"; // 无参数可替换,保留原样 - fmt += 2; - } else { - result += *fmt; - ++fmt; - } - } - return result; -} - -// 格式化递归:替换第一个 {} 并递归处理剩余 -template -inline std::string format_impl(const char *fmt, const T &first, - const Args &...rest) { - std::string result; - while (*fmt) { - if (*fmt == '{') { - // 检查 {:#x} 等格式说明符 - if (*(fmt + 1) == '}') { - result += to_string_arg(first); - fmt += 2; - result += format_impl(fmt, rest...); - return result; - } else if (*(fmt + 1) == ':') { - // 跳过格式说明符直到 } - const char *end = fmt + 2; - while (*end && *end != '}') - ++end; - if (*end == '}') { - // 检查是否是十六进制格式 - std::string spec(fmt + 2, end); - if (spec.find('x') != std::string::npos || - spec.find('X') != std::string::npos) { - if constexpr (std::is_integral_v) { - char buf[32]; - snprintf(buf, sizeof(buf), "0x%x", - static_cast(first)); - result += buf; - } else { - result += to_string_arg(first); - } - } else if (spec.find('f') != std::string::npos || - spec.find('.') != std::string::npos) { - if constexpr (std::is_arithmetic_v) { - // 解析精度 - int precision = 2; - auto dot = spec.find('.'); - if (dot != std::string::npos) { - precision = 0; - for (size_t i = dot + 1; - i < spec.size() && spec[i] >= '0' && spec[i] <= '9'; ++i) { - precision = precision * 10 + (spec[i] - '0'); - } - } - char fmtbuf[16]; - snprintf(fmtbuf, sizeof(fmtbuf), "%%.%df", precision); - char buf[64]; - snprintf(buf, sizeof(buf), fmtbuf, static_cast(first)); - result += buf; - } else { - result += to_string_arg(first); - } - } else { - result += to_string_arg(first); - } - fmt = end + 1; - result += format_impl(fmt, rest...); - return result; - } - } - } - result += *fmt; - ++fmt; - } - return result; -} - -} // namespace detail - -// 顶层格式化函数 -template -inline std::string e2d_format(const char *fmt, const Args &...args) { - return detail::format_impl(fmt, args...); -} - -// 无参数版本 -inline std::string e2d_format(const char *fmt) { return std::string(fmt); } - -// ============================================================================ -// Logger 类 - 使用 SDL2 日志系统 -// ============================================================================ +/** + * @brief 日志系统管理类 + * + * 提供统一的日志记录接口,支持控制台和文件输出 + * 通过 setLevel() 在运行时控制日志级别 + */ class Logger { public: /** @@ -186,14 +51,14 @@ public: static void setLevel(LogLevel level); /** - * @brief 设置是否输出到控制台 + * @brief 启用/禁用控制台输出 * @param enable 是否启用 */ static void setConsoleOutput(bool enable); /** - * @brief 设置日志输出到文件 - * @param filename 日志文件名 + * @brief 设置文件输出 + * @param filename 日志文件路径 */ static void setFileOutput(const std::string &filename); @@ -201,94 +66,84 @@ public: * @brief 获取当前日志级别 * @return 当前日志级别 */ - static LogLevel getLevel() { return level_; } + static LogLevel getLevel(); /** - * @brief 日志记录模板函数 + * @brief 记录日志(格式化版本) + * @tparam Args 参数类型 * @param level 日志级别 - * @param fmt 格式化字符串 - * @param args 可变参数 + * @param fmt 格式字符串 + * @param args 格式化参数 */ template - static void log(LogLevel level, const char *fmt, const Args &...args) { - if (static_cast(level) < static_cast(level_)) + static void log(LogLevel level, fmt::format_string fmt, + Args &&...args) { + if (!logger_) { return; - std::string msg = e2d_format(fmt, args...); -#ifdef TEST_BUILD - printf("[%s] %s\n", getLevelString(level), msg.c_str()); -#else - SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, - static_cast(level), "[%s] %s", - getLevelString(level), msg.c_str()); -#endif + } + auto spdLevel = static_cast(level); + logger_->log(spdLevel, fmt, std::forward(args)...); } /** - * @brief 日志记录无参数版本 + * @brief 记录日志(字符串版本) * @param level 日志级别 * @param msg 日志消息 */ - static void log(LogLevel level, const char *msg) { - if (static_cast(level) < static_cast(level_)) - return; -#ifdef TEST_BUILD - printf("[%s] %s\n", getLevelString(level), msg); -#else - SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, - static_cast(level), "[%s] %s", - getLevelString(level), msg); -#endif - } - -private: - static LogLevel level_; // 当前日志级别 - static bool initialized_; // 是否已初始化 - static bool consoleOutput_; // 是否输出到控制台 - static bool fileOutput_; // 是否输出到文件 - static std::string logFile_; // 日志文件路径 + static void log(LogLevel level, const char *msg); /** - * @brief 获取日志级别字符串 - * @param level 日志级别 - * @return 级别字符串 + * @brief 获取内部 spdlog 日志器 + * @return spdlog 日志器实例 */ - static const char *getLevelString(LogLevel level); + static std::shared_ptr getLogger() { return logger_; } + +private: + static std::shared_ptr logger_; + static bool initialized_; + static bool consoleOutput_; + static bool fileOutput_; + static std::string logFile_; }; -// ============================================================================ -// 日志宏 -// ============================================================================ - -#ifdef E2D_DEBUG -#define E2D_LOG_TRACE(...) \ - ::extra2d::Logger::log(::extra2d::LogLevel::Trace, __VA_ARGS__) -#define E2D_LOG_DEBUG(...) \ - ::extra2d::Logger::log(::extra2d::LogLevel::Debug, __VA_ARGS__) -#else -#define E2D_LOG_TRACE(...) -#define E2D_LOG_DEBUG(...) -#endif - -#define E2D_LOG_INFO(...) \ - ::extra2d::Logger::log(::extra2d::LogLevel::Info, __VA_ARGS__) -#define E2D_LOG_WARN(...) \ - ::extra2d::Logger::log(::extra2d::LogLevel::Warn, __VA_ARGS__) -#define E2D_LOG_ERROR(...) \ - ::extra2d::Logger::log(::extra2d::LogLevel::Error, __VA_ARGS__) -#define E2D_LOG_FATAL(...) \ - ::extra2d::Logger::log(::extra2d::LogLevel::Fatal, __VA_ARGS__) - -// 简化的日志宏 -#define E2D_INFO(...) E2D_LOG_INFO(__VA_ARGS__) -#define E2D_WARN(...) E2D_LOG_WARN(__VA_ARGS__) -#define E2D_ERROR(...) E2D_LOG_ERROR(__VA_ARGS__) -#define E2D_FATAL(...) E2D_LOG_FATAL(__VA_ARGS__) -#ifdef E2D_DEBUG -#define E2D_DEBUG_LOG(...) E2D_LOG_DEBUG(__VA_ARGS__) -#define E2D_TRACE(...) E2D_LOG_TRACE(__VA_ARGS__) -#else -#define E2D_DEBUG_LOG(...) -#define E2D_TRACE(...) -#endif - } // namespace extra2d + +// ============================================ +// 日志宏定义 - 简化统一版本 +// ============================================ + +/** + * @brief 追踪日志 - 最详细的调试信息 + */ +#define E2D_TRACE(...) \ + ::extra2d::Logger::log(::extra2d::LogLevel::Trace, __VA_ARGS__) + +/** + * @brief 调试日志 - 调试信息 + */ +#define E2D_DEBUG(...) \ + ::extra2d::Logger::log(::extra2d::LogLevel::Debug, __VA_ARGS__) + +/** + * @brief 信息日志 - 一般信息 + */ +#define E2D_INFO(...) \ + ::extra2d::Logger::log(::extra2d::LogLevel::Info, __VA_ARGS__) + +/** + * @brief 警告日志 - 警告信息 + */ +#define E2D_WARN(...) \ + ::extra2d::Logger::log(::extra2d::LogLevel::Warn, __VA_ARGS__) + +/** + * @brief 错误日志 - 错误信息 + */ +#define E2D_ERROR(...) \ + ::extra2d::Logger::log(::extra2d::LogLevel::Error, __VA_ARGS__) + +/** + * @brief 致命错误日志 - 严重错误 + */ +#define E2D_FATAL(...) \ + ::extra2d::Logger::log(::extra2d::LogLevel::Fatal, __VA_ARGS__) diff --git a/src/app/application.cpp b/src/app/application.cpp index 0747197..c9239cb 100644 --- a/src/app/application.cpp +++ b/src/app/application.cpp @@ -23,22 +23,24 @@ Application &Application::operator=(Application &&) noexcept = default; bool Application::init(const AppConfig &config) { if (initialized_) { - E2D_LOG_WARN("应用程序已经初始化"); return true; } config_ = config; + // 初始化日志系统(必须在所有日志调用之前) + Logger::init(); + // 创建引擎上下文 context_ = Context::create(); if (!context_) { - E2D_LOG_ERROR("创建上下文失败"); + E2D_ERROR("创建上下文失败"); return false; } // 初始化引擎 if (!context_->init()) { - E2D_LOG_ERROR("初始化上下文失败"); + E2D_ERROR("初始化上下文失败"); return false; } @@ -53,9 +55,9 @@ bool Application::init(const AppConfig &config) { events::OnInit::emit(); - E2D_LOG_INFO("应用程序初始化成功"); - E2D_LOG_INFO("窗口: {}x{}, 全屏: {}", config.width, - config.height, config.fullscreen); + E2D_INFO("应用程序初始化成功"); + E2D_INFO("窗口: {}x{}, 全屏: {}", config.width, config.height, + config.fullscreen); return true; } @@ -71,10 +73,10 @@ void Application::initModules() { // 初始化所有模块 for (auto &module : modules_) { if (!module->init()) { - E2D_LOG_ERROR("初始化模块失败: {}", module->getName()); + E2D_ERROR("初始化模块失败: {}", module->getName()); } else { - E2D_LOG_INFO("模块已初始化: {} (优先级: {})", module->getName(), - module->getPriority()); + E2D_INFO("模块已初始化: {} (优先级: {})", module->getName(), + module->getPriority()); } } } @@ -85,7 +87,7 @@ void Application::shutdown() { events::OnShutdown::emit(); - E2D_LOG_INFO("正在关闭应用程序..."); + E2D_INFO("正在关闭应用程序..."); // 按相反顺序销毁模块 for (auto it = modules_.rbegin(); it != modules_.rend(); ++it) { @@ -99,12 +101,15 @@ void Application::shutdown() { initialized_ = false; running_ = false; - E2D_LOG_INFO("应用程序关闭完成"); + E2D_INFO("应用程序关闭完成"); + + // 关闭日志系统(在所有日志调用之后) + Logger::shutdown(); } void Application::run() { if (!initialized_) { - E2D_LOG_ERROR("应用程序未初始化"); + E2D_ERROR("应用程序未初始化"); return; } @@ -159,7 +164,7 @@ void Application::pause() { if (!paused_) { paused_ = true; events::OnPause::emit(); - E2D_LOG_INFO("应用程序已暂停"); + E2D_INFO("应用程序已暂停"); } } @@ -167,7 +172,7 @@ void Application::resume() { if (paused_) { paused_ = false; events::OnResume::emit(); - E2D_LOG_INFO("应用程序已恢复"); + E2D_INFO("应用程序已恢复"); } } diff --git a/src/assets/assets_module.cpp b/src/assets/assets_module.cpp index 5c855c7..835bf5d 100644 --- a/src/assets/assets_module.cpp +++ b/src/assets/assets_module.cpp @@ -75,7 +75,7 @@ AssetsModule::~AssetsModule() { } bool AssetsModule::init() { - E2D_LOG_INFO("资源模块正在初始化..."); + E2D_INFO("资源模块正在初始化..."); textureLoader_ = std::make_unique(); shaderLoader_ = std::make_unique(); @@ -84,8 +84,7 @@ bool AssetsModule::init() { onShowListener_ = std::make_unique(); onShowListener_->bind([this]() { this->onGLContextReady(); }); - E2D_LOG_INFO( - "资源模块初始化成功 (等待 GL 上下文)"); + E2D_INFO("资源模块初始化成功 (等待 GL 上下文)"); return true; } @@ -94,19 +93,19 @@ void AssetsModule::onGLContextReady() { return; } - E2D_LOG_INFO("OpenGL 上下文就绪,正在创建默认资源..."); + E2D_INFO("OpenGL 上下文就绪,正在创建默认资源..."); if (!createDefaultResources()) { - E2D_LOG_ERROR("创建默认资源失败"); + E2D_ERROR("创建默认资源失败"); return; } defaultResourcesCreated_ = true; - E2D_LOG_INFO("默认资源创建成功"); + E2D_INFO("默认资源创建成功"); } void AssetsModule::shutdown() { - E2D_LOG_INFO("资源模块正在关闭..."); + E2D_INFO("资源模块正在关闭..."); // 关闭异步加载系统 shutdownAsyncLoader(); @@ -141,7 +140,7 @@ void AssetsModule::shutdown() { defaultResourcesCreated_ = false; - E2D_LOG_INFO("资源模块关闭完成"); + E2D_INFO("资源模块关闭完成"); } AssetsModule *getAssets() { return g_assetsModule; } @@ -164,13 +163,13 @@ Handle AssetsModule::load(const std::string &path) { } if (!textureLoader_) { - E2D_LOG_ERROR("纹理加载器未注册"); + E2D_ERROR("纹理加载器未注册"); return Handle::invalid(); } Ptr texture = textureLoader_->load(path); if (!texture) { - E2D_LOG_ERROR("加载纹理失败: {}", path); + E2D_ERROR("加载纹理失败: {}", path); return Handle::invalid(); } @@ -189,7 +188,7 @@ Handle AssetsModule::load(const std::string &path) { texturePathCache_[path] = handle; } - E2D_LOG_DEBUG("已加载纹理: {} -> 句柄索引 {}", path, handle.index()); + E2D_DEBUG("已加载纹理: {} -> 句柄索引 {}", path, handle.index()); // 如果启用了热重载,添加文件监控 if (hotReloadEnabled_) { @@ -212,13 +211,13 @@ Handle AssetsModule::loadFromMemory(const std::string &key, } if (!textureLoader_) { - E2D_LOG_ERROR("纹理加载器未注册"); + E2D_ERROR("纹理加载器未注册"); return Handle::invalid(); } Ptr texture = textureLoader_->loadFromMemory(data, size); if (!texture) { - E2D_LOG_ERROR("从内存加载纹理失败: {}", key); + E2D_ERROR("从内存加载纹理失败: {}", key); return Handle::invalid(); } @@ -245,13 +244,13 @@ template <> Handle AssetsModule::load(const std::string &path) { } if (!shaderLoader_) { - E2D_LOG_ERROR("着色器加载器未注册"); + E2D_ERROR("着色器加载器未注册"); return Handle::invalid(); } Ptr shader = shaderLoader_->load(path); if (!shader) { - E2D_LOG_ERROR("加载着色器失败: {}", path); + E2D_ERROR("加载着色器失败: {}", path); return Handle::invalid(); } @@ -270,7 +269,7 @@ template <> Handle AssetsModule::load(const std::string &path) { shaderPathCache_[path] = handle; } - E2D_LOG_DEBUG("已加载着色器: {} -> 句柄索引 {}", path, handle.index()); + E2D_DEBUG("已加载着色器: {} -> 句柄索引 {}", path, handle.index()); // 如果启用了热重载,添加文件监控 if (hotReloadEnabled_) { @@ -297,14 +296,14 @@ Handle AssetsModule::load(const std::string &vertPath, } if (!shaderLoader_) { - E2D_LOG_ERROR("着色器加载器未注册"); + E2D_ERROR("着色器加载器未注册"); return Handle::invalid(); } ShaderLoader *shaderLoader = static_cast(shaderLoader_.get()); Ptr shader = shaderLoader->load(vertPath, fragPath); if (!shader) { - E2D_LOG_ERROR("加载着色器失败: {} + {}", vertPath, fragPath); + E2D_ERROR("加载着色器失败: {} + {}", vertPath, fragPath); return Handle::invalid(); } @@ -323,8 +322,8 @@ Handle AssetsModule::load(const std::string &vertPath, shaderPathCache_[cacheKey] = handle; } - E2D_LOG_DEBUG("已加载着色器: {} + {} -> 句柄索引 {}", vertPath, fragPath, - handle.index()); + E2D_DEBUG("已加载着色器: {} + {} -> 句柄索引 {}", vertPath, fragPath, + handle.index()); // 如果启用了热重载,添加文件监控 if (hotReloadEnabled_) { @@ -348,7 +347,7 @@ AssetsModule::loadDir(const std::string &directory, try { std::filesystem::path dirPath(directory); if (!fileExists(directory)) { - E2D_LOG_WARN("目录未找到: {}", directory); + E2D_WARN("目录未找到: {}", directory); return handles; } @@ -382,10 +381,10 @@ AssetsModule::loadDir(const std::string &directory, } } } catch (const std::exception &e) { - E2D_LOG_ERROR("加载目录 {} 时出错: {}", directory, e.what()); + E2D_ERROR("加载目录 {} 时出错: {}", directory, e.what()); } - E2D_LOG_DEBUG("已从 {} 加载 {} 个纹理", directory, handles.size()); + E2D_DEBUG("已从 {} 加载 {} 个纹理", directory, handles.size()); return handles; } @@ -455,11 +454,11 @@ bool AssetsModule::createDefaultResources() { Ptr texture = makePtr(); uint8_t whitePixel[] = {255, 255, 255, 255}; if (!texture->loadFromMemory(whitePixel, 1, 1, TextureFormat::RGBA8)) { - E2D_LOG_ERROR("创建默认纹理失败"); + E2D_ERROR("创建默认纹理失败"); return false; } defaultTexture_ = textures_.insert(texture); - E2D_LOG_DEBUG("已创建默认纹理"); + E2D_DEBUG("已创建默认纹理"); } { @@ -474,8 +473,7 @@ bool AssetsModule::createDefaultResources() { : "shader/default.frag"; if (!fileExists(vertPath) || !fileExists(fragPath)) { - E2D_LOG_ERROR("默认着色器文件未找到: {}, {}", vertPath, - fragPath); + E2D_ERROR("默认着色器文件未找到: {}, {}", vertPath, fragPath); return false; } @@ -483,22 +481,19 @@ bool AssetsModule::createDefaultResources() { std::string vsSource = readFileToString(vertPath); std::string fsSource = readFileToString(fragPath); if (vsSource.empty() || fsSource.empty()) { - E2D_LOG_ERROR("读取默认着色器文件失败: {}, {}", vertPath, - fragPath); + E2D_ERROR("读取默认着色器文件失败: {}, {}", vertPath, fragPath); return false; } // 从源码加载着色器 Ptr shader = makePtr(); if (!shader->loadFromSource(vsSource, fsSource)) { - E2D_LOG_ERROR("编译默认着色器失败: {}, {}", vertPath, - fragPath); + E2D_ERROR("编译默认着色器失败: {}, {}", vertPath, fragPath); return false; } defaultShader_ = shaders_.insert(shader); - E2D_LOG_DEBUG("已从文件加载默认着色器: {}, {}", vertPath, - fragPath); + E2D_DEBUG("已从文件加载默认着色器: {}, {}", vertPath, fragPath); } { @@ -527,17 +522,17 @@ bool AssetsModule::createDefaultResources() { // 添加默认纹理到材质 material->setTexture("uTexture", getPtr(defaultTexture_), 0); defaultMaterial_ = materials_.insert(material); - E2D_LOG_DEBUG("已创建默认材质,使用默认纹理和布局"); + E2D_DEBUG("已创建默认材质,使用默认纹理和布局"); } { Ptr mesh = Mesh::createQuad(Vec2(1.0f, 1.0f)); if (!mesh) { - E2D_LOG_ERROR("创建默认四边形网格失败"); + E2D_ERROR("创建默认四边形网格失败"); return false; } defaultQuad_ = meshes_.insert(mesh); - E2D_LOG_DEBUG("已创建默认四边形网格"); + E2D_DEBUG("已创建默认四边形网格"); } return true; @@ -584,9 +579,9 @@ Mesh *AssetsModule::getDefaultQuadPtr() { return meshes_.get(defaultQuad_); } void AssetsModule::enableHotReload(bool enable) { hotReloadEnabled_ = enable; if (enable) { - E2D_LOG_INFO("热重载已启用"); + E2D_INFO("热重载已启用"); } else { - E2D_LOG_INFO("热重载已禁用"); + E2D_INFO("热重载已禁用"); } } @@ -594,7 +589,8 @@ void AssetsModule::setHotReloadInterval(float interval) { hotReloadInterval_ = interval; } -void AssetsModule::addFileWatchInternal(const std::string &path, FileWatchInfo &&info) { +void AssetsModule::addFileWatchInternal(const std::string &path, + FileWatchInfo &&info) { try { if (!fileExists(path)) { return; @@ -606,20 +602,22 @@ void AssetsModule::addFileWatchInternal(const std::string &path, FileWatchInfo & std::unique_lock lock(mutex_); fileWatchList_.push_back(std::move(info)); const char *type = fileWatchList_.back().isTexture ? "纹理" : "着色器"; - E2D_LOG_DEBUG("正在监控 {} 文件: {}", type, path); + E2D_DEBUG("正在监控 {} 文件: {}", type, path); } catch (const std::exception &e) { - E2D_LOG_ERROR("添加文件监控失败 {}: {}", path, e.what()); + E2D_ERROR("添加文件监控失败 {}: {}", path, e.what()); } } -void AssetsModule::addFileWatch(const std::string &path, Handle handle) { +void AssetsModule::addFileWatch(const std::string &path, + Handle handle) { FileWatchInfo info; info.textureHandle = handle; info.isTexture = true; addFileWatchInternal(path, std::move(info)); } -void AssetsModule::addFileWatch(const std::string &path, Handle handle) { +void AssetsModule::addFileWatch(const std::string &path, + Handle handle) { FileWatchInfo info; info.shaderHandle = handle; info.isTexture = false; @@ -631,22 +629,22 @@ void AssetsModule::reloadTexture(const FileWatchInfo &info) { return; } - E2D_LOG_INFO("正在重载纹理: {}", info.path); + E2D_INFO("正在重载纹理: {}", info.path); // 获取旧纹理指针 Texture *oldTexture = textures_.get(info.textureHandle); if (!oldTexture) { - E2D_LOG_ERROR("未找到要重载的旧纹理: {}", info.path); + E2D_ERROR("未找到要重载的旧纹理: {}", info.path); return; } // 直接在原有纹理对象上重新加载 if (!oldTexture->reloadFromFile(info.path)) { - E2D_LOG_ERROR("重载纹理失败: {}", info.path); + E2D_ERROR("重载纹理失败: {}", info.path); return; } - E2D_LOG_INFO("纹理重载成功: {}", info.path); + E2D_INFO("纹理重载成功: {}", info.path); notifyTextureReloaded(info.textureHandle); } @@ -655,12 +653,12 @@ void AssetsModule::reloadShader(const FileWatchInfo &info) { return; } - E2D_LOG_INFO("正在重载着色器: {}", info.path); + E2D_INFO("正在重载着色器: {}", info.path); // 获取旧着色器指针 Shader *oldShader = shaders_.get(info.shaderHandle); if (!oldShader) { - E2D_LOG_ERROR("未找到要重载的旧着色器: {}", info.path); + E2D_ERROR("未找到要重载的旧着色器: {}", info.path); return; } @@ -677,7 +675,7 @@ void AssetsModule::reloadShader(const FileWatchInfo &info) { } if (cacheKey.empty()) { - E2D_LOG_WARN("未找到着色器缓存键: {}", info.path); + E2D_WARN("未找到着色器缓存键: {}", info.path); return; } @@ -685,7 +683,7 @@ void AssetsModule::reloadShader(const FileWatchInfo &info) { size_t sepPos = cacheKey.find('|'); if (sepPos == std::string::npos) { // 单文件模式 - 这里暂不支持,因为 ShaderLoader 目前只支持双文件 - E2D_LOG_WARN("不支持单文件着色器重载: {}", info.path); + E2D_WARN("不支持单文件着色器重载: {}", info.path); } else { // 双文件模式 std::string vertPath = cacheKey.substr(0, sepPos); @@ -695,18 +693,18 @@ void AssetsModule::reloadShader(const FileWatchInfo &info) { std::string vsSource = readFileToString(vertPath); std::string fsSource = readFileToString(fragPath); if (vsSource.empty() || fsSource.empty()) { - E2D_LOG_ERROR("读取着色器文件失败: {}, {}", vertPath, fragPath); + E2D_ERROR("读取着色器文件失败: {}, {}", vertPath, fragPath); return; } // 直接在原有着色器对象上重新加载 if (!oldShader->reloadFromSource(vsSource, fsSource)) { - E2D_LOG_ERROR("重载着色器失败: {} + {}", vertPath, fragPath); + E2D_ERROR("重载着色器失败: {} + {}", vertPath, fragPath); return; } } - E2D_LOG_INFO("着色器重载成功: {}", info.path); + E2D_INFO("着色器重载成功: {}", info.path); notifyShaderReloaded(info.shaderHandle); } @@ -744,7 +742,7 @@ void AssetsModule::checkForChanges() { lock.lock(); } } catch (const std::exception &e) { - E2D_LOG_ERROR("检查文件 {} 时出错: {}", info.path, e.what()); + E2D_ERROR("检查文件 {} 时出错: {}", info.path, e.what()); } } } @@ -768,7 +766,7 @@ void AssetsModule::initAsyncLoader(uint32_t threadCount) { workerThreads_.emplace_back(&AssetsModule::workerThreadLoop, this); } - E2D_LOG_INFO("异步加载器已初始化,使用 {} 个线程", threadCount); + E2D_INFO("异步加载器已初始化,使用 {} 个线程", threadCount); } void AssetsModule::shutdownAsyncLoader() { @@ -790,7 +788,7 @@ void AssetsModule::shutdownAsyncLoader() { std::lock_guard lock(queueMutex_); loadQueue_.clear(); - E2D_LOG_INFO("异步加载器已关闭"); + E2D_INFO("异步加载器已关闭"); } void AssetsModule::submitLoadTask(const LoadTask &task) { @@ -890,8 +888,7 @@ void AssetsModule::registerMaterialDependency(Handle material, info.dependentMaterials.end(), material); if (it == info.dependentMaterials.end()) { info.dependentMaterials.push_back(material); - E2D_LOG_DEBUG("已注册材质 {} 对纹理 {} 的依赖", - material.index(), textureIndex); + E2D_DEBUG("已注册材质 {} 对纹理 {} 的依赖", material.index(), textureIndex); } } @@ -912,8 +909,8 @@ void AssetsModule::registerMaterialDependency(Handle material, info.dependentMaterials.end(), material); if (it == info.dependentMaterials.end()) { info.dependentMaterials.push_back(material); - E2D_LOG_DEBUG("已注册材质 {} 对着色器 {} 的依赖", - material.index(), shaderIndex); + E2D_DEBUG("已注册材质 {} 对着色器 {} 的依赖", material.index(), + shaderIndex); } } @@ -927,8 +924,7 @@ void AssetsModule::notifyTextureReloaded(Handle texture) { uint32_t textureIndex = texture.index(); auto it = textureDependencies_.find(textureIndex); if (it != textureDependencies_.end()) { - E2D_LOG_INFO("通知 {} 个材质纹理已重载", - it->second.dependentMaterials.size()); + E2D_INFO("通知 {} 个材质纹理已重载", it->second.dependentMaterials.size()); // 材质需要更新纹理引用 // 这里可以触发材质更新事件 @@ -936,8 +932,7 @@ void AssetsModule::notifyTextureReloaded(Handle texture) { Material *material = materials_.get(materialHandle); if (material) { // 材质自动使用新的纹理数据 - E2D_LOG_DEBUG("材质 {} 已更新为重载后的纹理", - materialHandle.index()); + E2D_DEBUG("材质 {} 已更新为重载后的纹理", materialHandle.index()); } } } @@ -953,16 +948,15 @@ void AssetsModule::notifyShaderReloaded(Handle shader) { uint32_t shaderIndex = shader.index(); auto it = shaderDependencies_.find(shaderIndex); if (it != shaderDependencies_.end()) { - E2D_LOG_INFO("通知 {} 个材质着色器已重载", - it->second.dependentMaterials.size()); + E2D_INFO("通知 {} 个材质着色器已重载", + it->second.dependentMaterials.size()); for (const auto &materialHandle : it->second.dependentMaterials) { Material *material = materials_.get(materialHandle); if (material) { // 更新材质的着色器引用 material->setShader(getPtr(shader)); - E2D_LOG_DEBUG("材质 {} 已更新为重载后的着色器", - materialHandle.index()); + E2D_DEBUG("材质 {} 已更新为重载后的着色器", materialHandle.index()); } } } diff --git a/src/assets/loaders/shader_loader.cpp b/src/assets/loaders/shader_loader.cpp index 8b2d328..82fd6d4 100644 --- a/src/assets/loaders/shader_loader.cpp +++ b/src/assets/loaders/shader_loader.cpp @@ -11,9 +11,7 @@ namespace { /** * @brief 获取 FileModule 实例 */ -FileModule *getFileModule() { - return getModule(); -} +FileModule *getFileModule() { return getModule(); } /** * @brief 检查文件是否存在(使用 FileModule) @@ -65,31 +63,30 @@ Ptr ShaderLoader::load(const std::string &vertPath, // 读取顶点着色器文件 std::string vsSource = readFileToString(vertPath); if (vsSource.empty()) { - E2D_LOG_ERROR("ShaderLoader: 读取顶点着色器失败: {}", vertPath); + E2D_ERROR("ShaderLoader: 读取顶点着色器失败: {}", vertPath); return Ptr(); } // 读取片段着色器文件 std::string fsSource = readFileToString(fragPath); if (fsSource.empty()) { - E2D_LOG_ERROR("ShaderLoader: 读取片段着色器失败: {}", fragPath); + E2D_ERROR("ShaderLoader: 读取片段着色器失败: {}", fragPath); return Ptr(); } // 从源码加载着色器 Ptr shader = makePtr(); if (!shader->loadFromSource(vsSource, fsSource)) { - E2D_LOG_ERROR("ShaderLoader: 编译着色器失败 {} + {}", vertPath, - fragPath); + E2D_ERROR("ShaderLoader: 编译着色器失败 {} + {}", vertPath, fragPath); return Ptr(); } - E2D_LOG_DEBUG("ShaderLoader: 已加载着色器 {} + {}", vertPath, fragPath); + E2D_DEBUG("ShaderLoader: 已加载着色器 {} + {}", vertPath, fragPath); return shader; } Ptr ShaderLoader::loadFromMemory(const uint8_t *data, size_t size) { - E2D_LOG_ERROR("ShaderLoader: loadFromMemory 不支持着色器"); + E2D_ERROR("ShaderLoader: loadFromMemory 不支持着色器"); return Ptr(); } @@ -98,11 +95,11 @@ Ptr ShaderLoader::loadFromSource(const std::string &vsSource, Ptr shader = makePtr(); if (!shader->loadFromSource(vsSource, fsSource)) { - E2D_LOG_ERROR("ShaderLoader: 从源码编译着色器失败"); + E2D_ERROR("ShaderLoader: 从源码编译着色器失败"); return Ptr(); } - E2D_LOG_DEBUG("ShaderLoader: 已从源码编译着色器"); + E2D_DEBUG("ShaderLoader: 已从源码编译着色器"); return shader; } diff --git a/src/assets/loaders/texture_loader.cpp b/src/assets/loaders/texture_loader.cpp index d5d7d89..b705aad 100644 --- a/src/assets/loaders/texture_loader.cpp +++ b/src/assets/loaders/texture_loader.cpp @@ -10,11 +10,11 @@ Ptr TextureLoader::load(const std::string &path) { Ptr texture = makePtr(); if (!texture->loadFromFile(path)) { - E2D_LOG_ERROR("TextureLoader: 从 {} 加载纹理失败", path); + E2D_ERROR("TextureLoader: 从 {} 加载纹理失败", path); return Ptr(); } - E2D_LOG_DEBUG("TextureLoader: 已加载纹理 {}", path); + E2D_DEBUG("TextureLoader: 已加载纹理 {}", path); return texture; } @@ -26,7 +26,7 @@ Ptr TextureLoader::loadFromMemory(const uint8_t *data, size_t size) { &width, &height, &channels, 0); if (!imageData) { - E2D_LOG_ERROR("TextureLoader: 从内存解码图像失败"); + E2D_ERROR("TextureLoader: 从内存解码图像失败"); return Ptr(); } @@ -54,12 +54,11 @@ Ptr TextureLoader::loadFromMemory(const uint8_t *data, size_t size) { stbi_image_free(imageData); if (!success) { - E2D_LOG_ERROR("TextureLoader: 从内存创建纹理失败"); + E2D_ERROR("TextureLoader: 从内存创建纹理失败"); return Ptr(); } - E2D_LOG_DEBUG("TextureLoader: 已从内存创建纹理 ({}x{})", width, - height); + E2D_DEBUG("TextureLoader: 已从内存创建纹理 ({}x{})", width, height); return texture; } diff --git a/src/platform/file_module.cpp b/src/platform/file_module.cpp index 03daeec..fb5c5d9 100644 --- a/src/platform/file_module.cpp +++ b/src/platform/file_module.cpp @@ -30,11 +30,11 @@ bool FileModule::init() { // 初始化 Switch 的 RomFS Result rc = romfsInit(); if (R_SUCCEEDED(rc)) { - E2D_LOG_INFO("RomFS 初始化成功"); + E2D_INFO("RomFS 初始化成功"); // 在 Switch 上设置资源根目录为 RomFS assetRoot_ = "romfs:/"; } else { - E2D_LOG_WARN("RomFS 初始化失败: {:#08X}", rc); + E2D_WARN("RomFS 初始化失败: {:#08X}", rc); // RomFS 初始化失败,使用当前目录 assetRoot_ = "./"; } @@ -43,7 +43,7 @@ bool FileModule::init() { assetRoot_ = "./"; #endif - E2D_LOG_INFO("资源根目录设置为: {}", assetRoot_); + E2D_INFO("资源根目录设置为: {}", assetRoot_); return true; } @@ -102,7 +102,7 @@ bool FileModule::write(const std::string &path, const void *data, size_t size) const { // RomFS 是只读的,不允许写入 if (isRomfsPath(path)) { - E2D_LOG_WARN("无法写入 RomFS 路径: {}", path); + E2D_WARN("无法写入 RomFS 路径: {}", path); return false; } @@ -124,7 +124,7 @@ bool FileModule::append(const std::string &path, const void *data, size_t size) const { // RomFS 是只读的,不允许写入 if (isRomfsPath(path)) { - E2D_LOG_WARN("无法追加到 RomFS 路径: {}", path); + E2D_WARN("无法追加到 RomFS 路径: {}", path); return false; } @@ -140,7 +140,7 @@ bool FileModule::append(const std::string &path, const void *data, bool FileModule::remove(const std::string &path) const { // RomFS 是只读的,不允许删除 if (isRomfsPath(path)) { - E2D_LOG_WARN("无法删除 RomFS 路径: {}", path); + E2D_WARN("无法删除 RomFS 路径: {}", path); return false; } return fs::remove(path); @@ -149,7 +149,7 @@ bool FileModule::remove(const std::string &path) const { bool FileModule::mkdir(const std::string &path) const { // RomFS 是只读的,不允许创建目录 if (isRomfsPath(path)) { - E2D_LOG_WARN("无法在 RomFS 中创建目录: {}", path); + E2D_WARN("无法在 RomFS 中创建目录: {}", path); return false; } diff --git a/src/platform/window_module.cpp b/src/platform/window_module.cpp index 964b345..3842555 100644 --- a/src/platform/window_module.cpp +++ b/src/platform/window_module.cpp @@ -12,7 +12,7 @@ WindowModule::~WindowModule() { shutdown(); } bool WindowModule::init() { if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) { - E2D_LOG_ERROR("初始化 SDL 视频子系统失败: {}", SDL_GetError()); + E2D_ERROR("初始化 SDL 视频子系统失败: {}", SDL_GetError()); return false; } @@ -58,11 +58,11 @@ bool WindowModule::create(const WindowCfg &cfg) { SDL_WINDOWPOS_CENTERED, cfg.width, cfg.height, flags); if (!window_) { - E2D_LOG_ERROR("创建窗口失败: {}", SDL_GetError()); + E2D_ERROR("创建窗口失败: {}", SDL_GetError()); return false; } - E2D_LOG_INFO("窗口已创建: {}x{}", cfg.width, cfg.height); + E2D_INFO("窗口已创建: {}x{}", cfg.width, cfg.height); return true; } @@ -71,7 +71,7 @@ bool WindowModule::pollEvents() { while (SDL_PollEvent(&evt)) { switch (evt.type) { case SDL_QUIT: - E2D_LOG_INFO("收到 SDL_QUIT 事件"); + E2D_INFO("收到 SDL_QUIT 事件"); shouldClose_ = true; // 发送窗口关闭事件 events::OnClose::emit(); @@ -139,10 +139,8 @@ void WindowModule::onModuleConfig(const AppConfig &config) { cfg.resizable = config.resizable; if (create(cfg)) { - // 发送窗口显示事件 + // 先显示窗口,setVisible 会触发 OnShow 事件 // RHI 模块会监听此事件并创建 OpenGL 上下文 - events::OnShow::emit(); - setVisible(true); } } @@ -193,12 +191,10 @@ void WindowModule::setVisible(bool visible) { if (window_) { if (visible) { SDL_ShowWindow(window_); - // 发送窗口显示事件 - events::OnShow::emit(); + // SDL_WINDOWEVENT_SHOWN 事件会触发 OnShow,这里不需要手动触发 } else { SDL_HideWindow(window_); - // 发送窗口隐藏事件 - events::OnHide::emit(); + // SDL_WINDOWEVENT_HIDDEN 事件会触发 OnHide,这里不需要手动触发 } } } diff --git a/src/renderer/command_queue.cpp b/src/renderer/command_queue.cpp index 76b8dde..9e3c6ea 100644 --- a/src/renderer/command_queue.cpp +++ b/src/renderer/command_queue.cpp @@ -1,15 +1,15 @@ #include #include -#include #include #include #include -#include #include #include +#include #include #include #include +#include #include #include @@ -28,14 +28,14 @@ CommandSorter::CommandSorter() { CommandSorter::~CommandSorter() = default; -CommandSorter::CommandSorter(CommandSorter&& other) noexcept +CommandSorter::CommandSorter(CommandSorter &&other) noexcept : commands_(std::move(other.commands_)), sortedIndices_(std::move(other.sortedIndices_)), commandCount_(other.commandCount_) { other.commandCount_ = 0; } -CommandSorter& CommandSorter::operator=(CommandSorter&& other) noexcept { +CommandSorter &CommandSorter::operator=(CommandSorter &&other) noexcept { if (this != &other) { commands_ = std::move(other.commands_); sortedIndices_ = std::move(other.sortedIndices_); @@ -62,17 +62,17 @@ uint32_t CommandSorter::addCommand(const DrawCommand &cmd) { } void CommandSorter::sort() { - if (commandCount_ == 0) return; + if (commandCount_ == 0) + return; // 只排序有效范围的索引 auto indicesBegin = sortedIndices_.begin(); auto indicesEnd = sortedIndices_.begin() + commandCount_; // 使用稳定排序保持相同键的命令顺序 - std::stable_sort(indicesBegin, indicesEnd, - [this](uint32_t a, uint32_t b) { - return commands_[a].key < commands_[b].key; - }); + std::stable_sort(indicesBegin, indicesEnd, [this](uint32_t a, uint32_t b) { + return commands_[a].key < commands_[b].key; + }); } void CommandSorter::clear() { @@ -198,40 +198,40 @@ bool CommandQueue::initialize() { // 获取 RHI 模块 auto *rhiModule = RHIModule::get(); if (!rhiModule) { - E2D_LOG_ERROR("RHIModule not available"); + E2D_ERROR("RHIModule not available"); return false; } auto *device = rhiModule->getDevice(); if (!device) { - E2D_LOG_ERROR("RHIDevice not available"); + E2D_ERROR("RHIDevice not available"); return false; } context_ = rhiModule->getContext(); if (!context_) { - E2D_LOG_ERROR("RHIContext not available"); + E2D_ERROR("RHIContext not available"); return false; } // 创建命令列表 commandList_ = device->createCommandList(); if (!commandList_) { - E2D_LOG_ERROR("Failed to create command list"); + E2D_ERROR("Failed to create command list"); return false; } // 初始化 UBO 管理器 uboManager_ = std::make_unique(); if (!uboManager_->initialize()) { - E2D_LOG_ERROR("Failed to initialize UniformBufferManager"); + E2D_ERROR("Failed to initialize UniformBufferManager"); return false; } // 预分配材质 UBO 数据缓冲区 materialUBOData_.reserve(1024 * 1024); // 1MB - E2D_LOG_INFO("命令队列已初始化"); + E2D_INFO("命令队列已初始化"); return true; } @@ -240,7 +240,7 @@ void CommandQueue::shutdown() { commandList_.reset(); context_ = nullptr; materialUBOData_.clear(); - E2D_LOG_INFO("命令队列已关闭"); + E2D_INFO("命令队列已关闭"); } void CommandQueue::beginFrame() { @@ -285,7 +285,8 @@ uint32_t CommandQueue::getMaterialId(Material *material) { return id; } -std::pair CommandQueue::allocateMaterialUBO(uint32_t size) { +std::pair +CommandQueue::allocateMaterialUBO(uint32_t size) { if (!uboManager_ || size == 0) { return {nullptr, 0}; } @@ -314,7 +315,8 @@ std::pair CommandQueue::allocateMaterialUBO(uint32_t s materialUBOBufferOffset_ = offset + alignedSize; - return {nullptr, offset}; // 返回 nullptr 表示使用 CPU 缓冲区,offset 是 CPU 缓冲区偏移 + return {nullptr, + offset}; // 返回 nullptr 表示使用 CPU 缓冲区,offset 是 CPU 缓冲区偏移 } void CommandQueue::flushMaterialUBOToGPU() { @@ -323,20 +325,22 @@ void CommandQueue::flushMaterialUBOToGPU() { } // 获取一个足够大的 UBO - currentMaterialUBO_ = uboManager_->acquireMaterialUBO(materialUBOBufferOffset_); + currentMaterialUBO_ = + uboManager_->acquireMaterialUBO(materialUBOBufferOffset_); if (!currentMaterialUBO_) { - E2D_LOG_ERROR("获取材质 UBO 失败"); + E2D_ERROR("获取材质 UBO 失败"); return; } // 批量更新到 GPU - currentMaterialUBO_->update(materialUBOData_.data(), materialUBOBufferOffset_, 0); + currentMaterialUBO_->update(materialUBOData_.data(), materialUBOBufferOffset_, + 0); // 重置 CPU 缓冲区偏移 materialUBOBufferOffset_ = 0; } -UniformBuffer* CommandQueue::getCurrentMaterialUBO() const { +UniformBuffer *CommandQueue::getCurrentMaterialUBO() const { return currentMaterialUBO_; } @@ -386,14 +390,16 @@ void CommandQueue::submitDraw(Ptr material, Ptr mesh, // 复制材质数据到 CPU 缓冲区,并修改颜色 if (offset + materialDataSize <= materialUBOData_.size()) { - std::memcpy(materialUBOData_.data() + offset, material->getData(), materialDataSize); + std::memcpy(materialUBOData_.data() + offset, material->getData(), + materialDataSize); // 将实例颜色应用到 UBO 数据中的 uColor 参数 auto layout = material->getLayout(); if (layout) { - const auto* param = layout->getParam("uColor"); + const auto *param = layout->getParam("uColor"); if (param && param->type == MaterialParamType::Color) { - std::memcpy(materialUBOData_.data() + offset + param->offset, &color.r, sizeof(float) * 4); + std::memcpy(materialUBOData_.data() + offset + param->offset, + &color.r, sizeof(float) * 4); } } @@ -431,31 +437,34 @@ void CommandQueue::setViewport(int32_t x, int32_t y, int32_t width, commandList_->setViewport(viewport); } -void CommandQueue::updateGlobalUBO(const Mat4& viewProjection, float deltaTime, - uint32_t screenWidth, uint32_t screenHeight, uint32_t frameIndex) { +void CommandQueue::updateGlobalUBO(const Mat4 &viewProjection, float deltaTime, + uint32_t screenWidth, uint32_t screenHeight, + uint32_t frameIndex) { if (!uboManager_) { - E2D_LOG_WARN("CommandQueue::updateGlobalUBO: uboManager 为空"); + E2D_WARN("CommandQueue::updateGlobalUBO: uboManager 为空"); return; } // 填充全局 UBO 数据 - std::memcpy(globalUBOData_.viewProjection, glm::value_ptr(viewProjection), sizeof(float) * 16); + std::memcpy(globalUBOData_.viewProjection, glm::value_ptr(viewProjection), + sizeof(float) * 16); globalUBOData_.cameraPosition[0] = 0.0f; globalUBOData_.cameraPosition[1] = 0.0f; globalUBOData_.cameraPosition[2] = 0.0f; globalUBOData_.cameraPosition[3] = 1.0f; - globalUBOData_.time = 0.0f; // TODO: 传递实际时间 + globalUBOData_.time = 0.0f; // TODO: 传递实际时间 globalUBOData_.deltaTime = deltaTime; globalUBOData_.screenSize[0] = static_cast(screenWidth); globalUBOData_.screenSize[1] = static_cast(screenHeight); // 使用双缓冲更新 UBO - uboManager_->updateGlobalUBO(&globalUBOData_, sizeof(globalUBOData_), frameIndex); + uboManager_->updateGlobalUBO(&globalUBOData_, sizeof(globalUBOData_), + frameIndex); } void CommandQueue::execute(uint32_t frameIndex) { if (!commandList_) { - E2D_LOG_ERROR("CommandQueue::execute: commandList 为空"); + E2D_ERROR("CommandQueue::execute: commandList 为空"); return; } @@ -477,7 +486,8 @@ void CommandQueue::execute(uint32_t frameIndex) { commandList_->submit(); } -void CommandQueue::executeBatch(uint32_t batchIndex, const CommandBatch &batch, uint32_t frameIndex) { +void CommandQueue::executeBatch(uint32_t batchIndex, const CommandBatch &batch, + uint32_t frameIndex) { if (!commandList_) { return; } @@ -487,12 +497,12 @@ void CommandQueue::executeBatch(uint32_t batchIndex, const CommandBatch &batch, commandList_->setPipeline(batch.pipeline.get()); stats_.pipelineBinds++; } else { - E2D_LOG_WARN("批次没有有效的管线!"); + E2D_WARN("批次没有有效的管线!"); } // 绑定全局 UBO (binding = 0) - 使用双缓冲 if (uboManager_) { - UniformBuffer* globalUBO = uboManager_->getGlobalUBO(frameIndex); + UniformBuffer *globalUBO = uboManager_->getGlobalUBO(frameIndex); if (globalUBO) { commandList_->setUniformBuffer(0, globalUBO->getRHIBuffer()); stats_.bufferBinds++; @@ -518,7 +528,7 @@ void CommandQueue::executeBatch(uint32_t batchIndex, const CommandBatch &batch, commandList_->setVertexBuffer(0, cmd.vertexBuffer.get(), 0); stats_.bufferBinds++; } else { - E2D_LOG_WARN("绘制命令没有有效的顶点缓冲区!"); + E2D_WARN("绘制命令没有有效的顶点缓冲区!"); } // 绑定索引缓冲区(如果有) @@ -529,7 +539,9 @@ void CommandQueue::executeBatch(uint32_t batchIndex, const CommandBatch &batch, // 绑定材质 UBO (binding = 1) if (cmd.materialUBOSize > 0 && currentMaterialUBO_) { - commandList_->setUniformBuffer(1, currentMaterialUBO_->getRHIBuffer(), cmd.materialUBOOffset, cmd.materialUBOSize); + commandList_->setUniformBuffer(1, currentMaterialUBO_->getRHIBuffer(), + cmd.materialUBOOffset, + cmd.materialUBOSize); stats_.bufferBinds++; } diff --git a/src/renderer/material.cpp b/src/renderer/material.cpp index 041c918..16b9a4a 100644 --- a/src/renderer/material.cpp +++ b/src/renderer/material.cpp @@ -1,6 +1,6 @@ +#include #include #include -#include namespace extra2d { @@ -15,31 +15,31 @@ MaterialLayout::MaterialLayout() = default; * @param name 参数名称 * @param type 参数类型 */ -void MaterialLayout::addParam(const std::string& name, MaterialParamType type) { - if (finalized_) { - E2D_LOG_WARN("无法向已完成的材质布局添加参数"); - return; - } +void MaterialLayout::addParam(const std::string &name, MaterialParamType type) { + if (finalized_) { + E2D_WARN("无法向已完成的材质布局添加参数"); + return; + } - // 检查是否已存在 - if (paramIndexMap_.find(name) != paramIndexMap_.end()) { - E2D_LOG_WARN("参数 '{}' 已存在于材质布局中", name); - return; - } - - MaterialParamInfo info; - info.type = type; - info.size = getMaterialParamSize(type); - info.offset = 0; // 将在 finalize 时计算 - - size_t index = params_.size(); - params_.emplace_back(name, info); - paramIndexMap_[name] = index; + // 检查是否已存在 + if (paramIndexMap_.find(name) != paramIndexMap_.end()) { + E2D_WARN("参数 '{}' 已存在于材质布局中", name); + return; + } + + MaterialParamInfo info; + info.type = type; + info.size = getMaterialParamSize(type); + info.offset = 0; // 将在 finalize 时计算 + + size_t index = params_.size(); + params_.emplace_back(name, info); + paramIndexMap_[name] = index; } /** * @brief 完成布局定义,计算 std140 布局偏移 - * + * * std140 布局规则: * - 标量和向量:偏移必须是其大小的倍数 * - 数组和结构体:偏移必须是 16 的倍数 @@ -47,45 +47,46 @@ void MaterialLayout::addParam(const std::string& name, MaterialParamType type) { * - 整个结构体大小必须是16的倍数 */ void MaterialLayout::finalize() { - if (finalized_) return; - - uint32_t offset = 0; - for (auto& pair : params_) { - auto& info = pair.second; - - // 计算对齐要求 - std140规则 - uint32_t alignment = 4; // 默认 4 字节对齐 - - switch (info.type) { - case MaterialParamType::Float: - alignment = 4; // float: 4 字节对齐 - break; - case MaterialParamType::Vec2: - alignment = 8; // vec2: 8 字节对齐 - break; - case MaterialParamType::Vec3: - case MaterialParamType::Vec4: - case MaterialParamType::Color: - alignment = 16; // vec3/vec4/color: 16 字节对齐(std140 规则) - break; - case MaterialParamType::Mat4: - alignment = 16; // mat4: 16 字节对齐,每列vec4对齐到16字节 - break; - default: - alignment = 4; - break; - } - - // 对齐偏移到alignment的倍数 - offset = (offset + alignment - 1) & ~(alignment - 1); - - info.offset = offset; - offset += info.size; + if (finalized_) + return; + + uint32_t offset = 0; + for (auto &pair : params_) { + auto &info = pair.second; + + // 计算对齐要求 - std140规则 + uint32_t alignment = 4; // 默认 4 字节对齐 + + switch (info.type) { + case MaterialParamType::Float: + alignment = 4; // float: 4 字节对齐 + break; + case MaterialParamType::Vec2: + alignment = 8; // vec2: 8 字节对齐 + break; + case MaterialParamType::Vec3: + case MaterialParamType::Vec4: + case MaterialParamType::Color: + alignment = 16; // vec3/vec4/color: 16 字节对齐(std140 规则) + break; + case MaterialParamType::Mat4: + alignment = 16; // mat4: 16 字节对齐,每列vec4对齐到16字节 + break; + default: + alignment = 4; + break; } - - // 最终大小对齐到 16 字节(std140要求结构体总大小是16的倍数) - bufferSize_ = (offset + 15) & ~15; - finalized_ = true; + + // 对齐偏移到alignment的倍数 + offset = (offset + alignment - 1) & ~(alignment - 1); + + info.offset = offset; + offset += info.size; + } + + // 最终大小对齐到 16 字节(std140要求结构体总大小是16的倍数) + bufferSize_ = (offset + 15) & ~15; + finalized_ = true; } /** @@ -93,12 +94,13 @@ void MaterialLayout::finalize() { * @param name 参数名称 * @return 参数信息指针,不存在返回 nullptr */ -const MaterialParamInfo* MaterialLayout::getParam(const std::string& name) const { - auto mapIt = paramIndexMap_.find(name); - if (mapIt != paramIndexMap_.end()) { - return ¶ms_[mapIt->second].second; - } - return nullptr; +const MaterialParamInfo * +MaterialLayout::getParam(const std::string &name) const { + auto mapIt = paramIndexMap_.find(name); + if (mapIt != paramIndexMap_.end()) { + return ¶ms_[mapIt->second].second; + } + return nullptr; } // ======================================== @@ -112,29 +114,27 @@ Material::Material() = default; * @param layout 材质布局 */ void Material::setLayout(Ptr layout) { - layout_ = layout; - if (layout_ && layout_->isFinalized()) { - data_.resize(layout_->getBufferSize(), 0); - } + layout_ = layout; + if (layout_ && layout_->isFinalized()) { + data_.resize(layout_->getBufferSize(), 0); + } } /** * @brief 设置着色器 * @param shader 着色器 */ -void Material::setShader(Ptr shader) { - shader_ = shader; -} +void Material::setShader(Ptr shader) { shader_ = shader; } /** * @brief 获取 RHI 管线句柄 * @return RHI 管线句柄 */ PipelineHandle Material::getPipeline() const { - if (shader_) { - return shader_->getPipeline(); - } - return PipelineHandle{}; + if (shader_) { + return shader_->getPipeline(); + } + return PipelineHandle{}; } /** @@ -142,13 +142,14 @@ PipelineHandle Material::getPipeline() const { * @param name 参数名称 * @param value 值 */ -void Material::setFloat(const std::string& name, float value) { - if (!layout_) return; - - const auto* param = layout_->getParam(name); - if (param && param->type == MaterialParamType::Float) { - std::memcpy(data_.data() + param->offset, &value, sizeof(float)); - } +void Material::setFloat(const std::string &name, float value) { + if (!layout_) + return; + + const auto *param = layout_->getParam(name); + if (param && param->type == MaterialParamType::Float) { + std::memcpy(data_.data() + param->offset, &value, sizeof(float)); + } } /** @@ -156,13 +157,14 @@ void Material::setFloat(const std::string& name, float value) { * @param name 参数名称 * @param value 值 */ -void Material::setVec2(const std::string& name, const Vec2& value) { - if (!layout_) return; - - const auto* param = layout_->getParam(name); - if (param && param->type == MaterialParamType::Vec2) { - std::memcpy(data_.data() + param->offset, &value.x, sizeof(float) * 2); - } +void Material::setVec2(const std::string &name, const Vec2 &value) { + if (!layout_) + return; + + const auto *param = layout_->getParam(name); + if (param && param->type == MaterialParamType::Vec2) { + std::memcpy(data_.data() + param->offset, &value.x, sizeof(float) * 2); + } } /** @@ -173,14 +175,16 @@ void Material::setVec2(const std::string& name, const Vec2& value) { * @param z Z 分量 * @param w W 分量 */ -void Material::setVec4(const std::string& name, float x, float y, float z, float w) { - if (!layout_) return; - - const auto* param = layout_->getParam(name); - if (param && param->type == MaterialParamType::Vec4) { - float values[4] = {x, y, z, w}; - std::memcpy(data_.data() + param->offset, values, sizeof(float) * 4); - } +void Material::setVec4(const std::string &name, float x, float y, float z, + float w) { + if (!layout_) + return; + + const auto *param = layout_->getParam(name); + if (param && param->type == MaterialParamType::Vec4) { + float values[4] = {x, y, z, w}; + std::memcpy(data_.data() + param->offset, values, sizeof(float) * 4); + } } /** @@ -188,13 +192,14 @@ void Material::setVec4(const std::string& name, float x, float y, float z, float * @param name 参数名称 * @param value 颜色值 */ -void Material::setColor(const std::string& name, const Color& value) { - if (!layout_) return; - - const auto* param = layout_->getParam(name); - if (param && param->type == MaterialParamType::Color) { - std::memcpy(data_.data() + param->offset, &value.r, sizeof(float) * 4); - } +void Material::setColor(const std::string &name, const Color &value) { + if (!layout_) + return; + + const auto *param = layout_->getParam(name); + if (param && param->type == MaterialParamType::Color) { + std::memcpy(data_.data() + param->offset, &value.r, sizeof(float) * 4); + } } /** @@ -202,13 +207,14 @@ void Material::setColor(const std::string& name, const Color& value) { * @param name 参数名称 * @param value 矩阵数据指针 */ -void Material::setMat4(const std::string& name, const float* value) { - if (!layout_) return; - - const auto* param = layout_->getParam(name); - if (param && param->type == MaterialParamType::Mat4) { - std::memcpy(data_.data() + param->offset, value, sizeof(float) * 16); - } +void Material::setMat4(const std::string &name, const float *value) { + if (!layout_) + return; + + const auto *param = layout_->getParam(name); + if (param && param->type == MaterialParamType::Mat4) { + std::memcpy(data_.data() + param->offset, value, sizeof(float) * 16); + } } /** @@ -217,25 +223,24 @@ void Material::setMat4(const std::string& name, const float* value) { * @param texture 纹理 * @param slot 纹理槽位(0-15) */ -void Material::setTexture(const std::string& uniformName, Ptr texture, uint32_t slot) { - // 查找是否已存在相同名称的纹理 - for (auto& texSlot : textures_) { - if (texSlot.uniformName == uniformName) { - texSlot.texture = texture; - texSlot.slot = slot; - return; - } +void Material::setTexture(const std::string &uniformName, Ptr texture, + uint32_t slot) { + // 查找是否已存在相同名称的纹理 + for (auto &texSlot : textures_) { + if (texSlot.uniformName == uniformName) { + texSlot.texture = texture; + texSlot.slot = slot; + return; } - - // 添加新的纹理槽位 - textures_.push_back({texture, slot, uniformName}); + } + + // 添加新的纹理槽位 + textures_.push_back({texture, slot, uniformName}); } /** * @brief 清除所有纹理 */ -void Material::clearTextures() { - textures_.clear(); -} +void Material::clearTextures() { textures_.clear(); } } // namespace extra2d diff --git a/src/renderer/mesh.cpp b/src/renderer/mesh.cpp index bb7fe2c..0533d52 100644 --- a/src/renderer/mesh.cpp +++ b/src/renderer/mesh.cpp @@ -20,13 +20,13 @@ void Mesh::setVertices(const Vertex *vertices, uint32_t count) { // 获取 RHI 模块 auto *rhiModule = RHIModule::get(); if (!rhiModule) { - E2D_LOG_ERROR("RHI 模块不可用"); + E2D_ERROR("RHI 模块不可用"); return; } auto *device = rhiModule->getDevice(); if (!device) { - E2D_LOG_ERROR("RHI 设备不可用"); + E2D_ERROR("RHI 设备不可用"); return; } @@ -37,7 +37,7 @@ void Mesh::setVertices(const Vertex *vertices, uint32_t count) { // 通过句柄获取缓冲区指针并更新数据 // 注意:这里假设可以通过某种方式获取缓冲区指针 // 实际实现可能需要通过 RHI 命令列表来更新 - E2D_LOG_WARN("顶点缓冲区更新尚未实现"); + E2D_WARN("顶点缓冲区更新尚未实现"); } else { // 需要创建新缓冲区 vertexBuffer_ = BufferHandle(); @@ -49,7 +49,7 @@ void Mesh::setVertices(const Vertex *vertices, uint32_t count) { // 创建缓冲区 auto buffer = device->createBuffer(desc); if (!buffer) { - E2D_LOG_ERROR("创建顶点缓冲区失败"); + E2D_ERROR("创建顶点缓冲区失败"); return; } @@ -62,7 +62,7 @@ void Mesh::setVertices(const Vertex *vertices, uint32_t count) { } vertexCount_ = count; - E2D_LOG_INFO("设置了 {} 个顶点", count); + E2D_INFO("设置了 {} 个顶点", count); } void Mesh::setIndices(const uint16_t *indices, uint32_t count) { @@ -72,13 +72,13 @@ void Mesh::setIndices(const uint16_t *indices, uint32_t count) { // 获取 RHI 模块 auto *rhiModule = RHIModule::get(); if (!rhiModule) { - E2D_LOG_ERROR("RHI 模块不可用"); + E2D_ERROR("RHI 模块不可用"); return; } auto *device = rhiModule->getDevice(); if (!device) { - E2D_LOG_ERROR("RHI 设备不可用"); + E2D_ERROR("RHI 设备不可用"); return; } @@ -86,7 +86,7 @@ void Mesh::setIndices(const uint16_t *indices, uint32_t count) { // 如果缓冲区已存在且容量足够,更新数据 if (indexBuffer_.isValid() && indexCapacity_ >= count) { - E2D_LOG_WARN("索引缓冲区更新尚未实现"); + E2D_WARN("索引缓冲区更新尚未实现"); } else { // 需要创建新缓冲区 indexBuffer_ = BufferHandle(); @@ -98,7 +98,7 @@ void Mesh::setIndices(const uint16_t *indices, uint32_t count) { // 创建缓冲区 auto buffer = device->createBuffer(desc); if (!buffer) { - E2D_LOG_ERROR("创建索引缓冲区失败"); + E2D_ERROR("创建索引缓冲区失败"); return; } @@ -109,7 +109,7 @@ void Mesh::setIndices(const uint16_t *indices, uint32_t count) { } indexCount_ = count; - E2D_LOG_INFO("设置了 {} 个索引", count); + E2D_INFO("设置了 {} 个索引", count); } void Mesh::updateVertices(const Vertex *vertices, uint32_t count, @@ -118,7 +118,7 @@ void Mesh::updateVertices(const Vertex *vertices, uint32_t count, return; if (offset + count > vertexCount_) { - E2D_LOG_WARN("顶点更新超出边界"); + E2D_WARN("顶点更新超出边界"); return; } @@ -134,7 +134,7 @@ void Mesh::updateVertices(const Vertex *vertices, uint32_t count, // 通过句柄获取缓冲区并更新数据 // 注意:这里需要 RHI 提供更新缓冲区的方法 // 暂时记录为未实现 - E2D_LOG_WARN("updateVertices 尚未完全实现"); + E2D_WARN("updateVertices 尚未完全实现"); } Ptr Mesh::createQuad(const Vec2 &size, const Rect &uv) { diff --git a/src/renderer/render_graph.cpp b/src/renderer/render_graph.cpp index 7ecc96f..c1cf21d 100644 --- a/src/renderer/render_graph.cpp +++ b/src/renderer/render_graph.cpp @@ -95,11 +95,11 @@ RenderGraph &RenderGraph::operator=(RenderGraph &&other) noexcept { bool RenderGraph::initialize() { if (!commandQueue_.initialize()) { - E2D_LOG_ERROR("初始化命令队列失败"); + E2D_ERROR("初始化命令队列失败"); return false; } - E2D_LOG_INFO("渲染图已初始化"); + E2D_INFO("渲染图已初始化"); return true; } @@ -110,7 +110,7 @@ void RenderGraph::shutdown() { commandQueue_.shutdown(); compiled_ = false; - E2D_LOG_INFO("渲染图已关闭"); + E2D_INFO("渲染图已关闭"); } RenderPass *RenderGraph::addPass(std::unique_ptr pass) { @@ -174,15 +174,15 @@ bool RenderGraph::compile() { createResources(); compiled_ = true; - E2D_LOG_INFO("渲染图编译完成,共 {} 个通道", executionOrder_.size()); + E2D_INFO("渲染图编译完成,共 {} 个通道", executionOrder_.size()); return true; } -void RenderGraph::execute(float deltaTime, const Mat4& viewProjection) { +void RenderGraph::execute(float deltaTime, const Mat4 &viewProjection) { if (!compiled_) { if (!compile()) { - E2D_LOG_ERROR("编译渲染图失败"); + E2D_ERROR("编译渲染图失败"); return; } } diff --git a/src/renderer/renderer_module.cpp b/src/renderer/renderer_module.cpp index 7e82d71..7e0dee8 100644 --- a/src/renderer/renderer_module.cpp +++ b/src/renderer/renderer_module.cpp @@ -12,7 +12,7 @@ RendererModule::RendererModule() = default; RendererModule::~RendererModule() = default; bool RendererModule::init() { - E2D_LOG_INFO("正在初始化渲染模块..."); + E2D_INFO("正在初始化渲染模块..."); // 绑定事件监听器 onRenderBeginListener_.bind([this]() { onRenderBegin(); }); @@ -24,7 +24,7 @@ bool RendererModule::init() { onResizeListener_.bind([this](int32 w, int32 h) { onResize(w, h); }); onShowListener_.bind([this]() { onWindowShow(); }); - E2D_LOG_INFO("渲染模块已初始化 (等待窗口显示)"); + E2D_INFO("渲染模块已初始化 (等待窗口显示)"); return true; } @@ -33,25 +33,25 @@ void RendererModule::onWindowShow() { return; } - E2D_LOG_INFO("正在初始化渲染模块上下文..."); + E2D_INFO("正在初始化渲染模块上下文..."); // 初始化 RHI 模块 auto *rhiModule = RHIModule::get(); if (!rhiModule) { - E2D_LOG_ERROR("RHI 模块不可用"); + E2D_ERROR("RHI 模块不可用"); return; } if (!rhiModule->getDevice()) { // RHI 设备尚未初始化,这是正常的时序问题 // RHIModule 会在窗口显示后初始化设备,然后再次触发此函数 - E2D_LOG_INFO("RHI 设备尚未就绪,等待 RHI 初始化..."); + E2D_INFO("RHI 设备尚未就绪,等待 RHI 初始化..."); return; } // 初始化渲染图 if (!renderGraph_.initialize()) { - E2D_LOG_ERROR("初始化渲染图失败"); + E2D_ERROR("初始化渲染图失败"); return; } @@ -61,22 +61,22 @@ void RendererModule::onWindowShow() { auto geometryPass = std::make_unique("Geometry"); renderGraph_.addPass(std::move(geometryPass)); - E2D_LOG_INFO("已添加默认几何渲染通道"); + E2D_INFO("已添加默认几何渲染通道"); auto windowModule = getModule(); if (!windowModule) { - E2D_LOG_ERROR("窗口模块不可用"); + E2D_ERROR("窗口模块不可用"); return; } setViewport(0, 0, static_cast(windowModule->getSize().w), static_cast(windowModule->getSize().h)); initialized_ = true; - E2D_LOG_INFO("渲染模块上下文初始化成功"); + E2D_INFO("渲染模块上下文初始化成功"); } void RendererModule::shutdown() { - E2D_LOG_INFO("正在关闭渲染模块..."); + E2D_INFO("正在关闭渲染模块..."); renderGraph_.shutdown(); commandQueue_ = nullptr; @@ -84,7 +84,7 @@ void RendererModule::shutdown() { // 注意:事件监听器是值类型,会在析构时自动清理 - E2D_LOG_INFO("渲染模块关闭完成"); + E2D_INFO("渲染模块关闭完成"); } RHIContext *RendererModule::getRHIContext() const { @@ -162,7 +162,7 @@ void RendererModule::onRenderBegin() { void RendererModule::onRenderSubmit(const RenderCommand &cmd) { if (!initialized_ || !commandQueue_) { - E2D_LOG_WARN("onRenderSubmit: 渲染模块未初始化或没有命令队列"); + E2D_WARN("onRenderSubmit: 渲染模块未初始化或没有命令队列"); return; } @@ -194,8 +194,8 @@ void RendererModule::onRenderSubmit(const RenderCommand &cmd) { transform, cmd.drawMesh.color); stats_.commandsSubmitted++; } else { - E2D_LOG_WARN("提交绘制命令失败: 材质={}, 网格={}", - material ? "有效" : "空", mesh ? "有效" : "空"); + E2D_WARN("提交绘制命令失败: 材质={}, 网格={}", material ? "有效" : "空", + mesh ? "有效" : "空"); } break; } @@ -226,7 +226,7 @@ void RendererModule::onRenderSetCamera(const Mat4 &viewProj) { void RendererModule::onRenderEnd() { if (!initialized_) { - E2D_LOG_WARN("onRenderEnd: 渲染模块未初始化"); + E2D_WARN("onRenderEnd: 渲染模块未初始化"); return; } @@ -241,10 +241,10 @@ void RendererModule::onRenderEnd() { // 每60帧输出一次统计信息 static uint32_t frameCount = 0; if (++frameCount % 60 == 0) { - E2D_LOG_INFO("渲染统计: 绘制调用={}, 三角形数={}, 顶点数={}, " - "管线绑定={}, 纹理绑定={}, 缓冲区绑定={}", - stats.drawCalls, stats.triangles, stats.vertices, - stats.pipelineBinds, stats.textureBinds, stats.bufferBinds); + E2D_INFO("渲染统计: 绘制调用={}, 三角形数={}, 顶点数={}, " + "管线绑定={}, 纹理绑定={}, 缓冲区绑定={}", + stats.drawCalls, stats.triangles, stats.vertices, + stats.pipelineBinds, stats.textureBinds, stats.bufferBinds); } } diff --git a/src/renderer/rhi/opengl/gl_context.cpp b/src/renderer/rhi/opengl/gl_context.cpp index 175909c..98ab53a 100644 --- a/src/renderer/rhi/opengl/gl_context.cpp +++ b/src/renderer/rhi/opengl/gl_context.cpp @@ -12,22 +12,22 @@ GLContext::GLContext(GLDevice *device) GLContext::~GLContext() = default; bool GLContext::initialize() { - E2D_LOG_INFO("正在初始化 OpenGL 上下文..."); + E2D_INFO("正在初始化 OpenGL 上下文..."); // 创建默认帧缓冲(窗口帧缓冲) defaultFramebuffer_ = std::make_unique(); defaultFramebuffer_->setSize(800, 600); // 默认大小,会被更新 - E2D_LOG_INFO("OpenGL 上下文初始化完成"); + E2D_INFO("OpenGL 上下文初始化完成"); return true; } void GLContext::shutdown() { - E2D_LOG_INFO("正在关闭 OpenGL 上下文..."); + E2D_INFO("正在关闭 OpenGL 上下文..."); defaultFramebuffer_.reset(); - E2D_LOG_INFO("OpenGL 上下文关闭完成"); + E2D_INFO("OpenGL 上下文关闭完成"); } void GLContext::beginFrame() { diff --git a/src/renderer/rhi/opengl/gl_device.cpp b/src/renderer/rhi/opengl/gl_device.cpp index 20919b6..5ccbca5 100644 --- a/src/renderer/rhi/opengl/gl_device.cpp +++ b/src/renderer/rhi/opengl/gl_device.cpp @@ -7,8 +7,8 @@ #include #include -#include #include +#include #include namespace extra2d { @@ -21,19 +21,20 @@ class GLDevice; */ class GLDevice : public RHIDevice { public: - GLDevice() : window_(nullptr), glContext_(nullptr), context_(nullptr), stats_() {} + GLDevice() + : window_(nullptr), glContext_(nullptr), context_(nullptr), stats_() {} ~GLDevice() override { shutdown(); } - bool initialize(void* nativeWindow) override { - E2D_LOG_INFO("正在初始化 OpenGL 设备..."); + bool initialize(void *nativeWindow) override { + E2D_INFO("正在初始化 OpenGL 设备..."); if (!nativeWindow) { - E2D_LOG_ERROR("原生窗口句柄为空"); + E2D_ERROR("原生窗口句柄为空"); return false; } - window_ = static_cast(nativeWindow); + window_ = static_cast(nativeWindow); // 创建 OpenGL ES 3.2 上下文 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); @@ -45,38 +46,39 @@ public: glContext_ = SDL_GL_CreateContext(window_); if (!glContext_) { - E2D_LOG_ERROR("创建 OpenGL ES 上下文失败: {}", SDL_GetError()); + E2D_ERROR("创建 OpenGL ES 上下文失败: {}", SDL_GetError()); return false; } // 初始化 GLAD if (!gladLoadGLES2Loader((GLADloadproc)SDL_GL_GetProcAddress)) { - E2D_LOG_ERROR("初始化 GLAD 失败"); + E2D_ERROR("初始化 GLAD 失败"); SDL_GL_DeleteContext(glContext_); glContext_ = nullptr; return false; } - E2D_LOG_INFO("OpenGL ES 上下文已创建: {}.{}", GLVersion.major, GLVersion.minor); + E2D_INFO("OpenGL ES 上下文已创建: {}.{}", GLVersion.major, GLVersion.minor); - const char* version = reinterpret_cast(glGetString(GL_VERSION)); + const char *version = + reinterpret_cast(glGetString(GL_VERSION)); if (!version) { - E2D_LOG_ERROR("获取 OpenGL 版本失败"); + E2D_ERROR("获取 OpenGL 版本失败"); SDL_GL_DeleteContext(glContext_); glContext_ = nullptr; return false; } - E2D_LOG_INFO("OpenGL 版本: {}", version); - E2D_LOG_INFO("OpenGL 供应商: {}", - reinterpret_cast(glGetString(GL_VENDOR))); - E2D_LOG_INFO("OpenGL 渲染器: {}", - reinterpret_cast(glGetString(GL_RENDERER))); + E2D_INFO("OpenGL 版本: {}", version); + E2D_INFO("OpenGL 供应商: {}", + reinterpret_cast(glGetString(GL_VENDOR))); + E2D_INFO("OpenGL 渲染器: {}", + reinterpret_cast(glGetString(GL_RENDERER))); // 创建上下文管理器 context_ = std::make_unique(this); if (!context_->initialize()) { - E2D_LOG_ERROR("初始化 GL 上下文失败"); + E2D_ERROR("初始化 GL 上下文失败"); SDL_GL_DeleteContext(glContext_); glContext_ = nullptr; return false; @@ -86,12 +88,12 @@ public: glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - E2D_LOG_INFO("OpenGL 设备初始化成功"); + E2D_INFO("OpenGL 设备初始化成功"); return true; } void shutdown() override { - E2D_LOG_INFO("正在关闭 OpenGL 设备..."); + E2D_INFO("正在关闭 OpenGL 设备..."); if (context_) { context_->shutdown(); @@ -105,7 +107,7 @@ public: window_ = nullptr; - E2D_LOG_INFO("OpenGL 设备关闭完成"); + E2D_INFO("OpenGL 设备关闭完成"); } std::unique_ptr createBuffer(const BufferDesc &desc) override { @@ -127,7 +129,7 @@ public: std::unique_ptr createShader(const ShaderDesc &desc) override { auto shader = std::make_unique(desc); if (!shader->compile()) { - E2D_LOG_ERROR("着色器编译失败: {}", shader->getCompileLog()); + E2D_ERROR("着色器编译失败: {}", shader->getCompileLog()); return nullptr; } return shader; @@ -139,16 +141,16 @@ public: if (!pipeline->create()) { return nullptr; } - + // 获取 vertex shader 的 program ID if (desc.vertexShader.isValid()) { - RHIShader* shader = desc.vertexShader.get(); + RHIShader *shader = desc.vertexShader.get(); if (shader) { - auto* glShader = static_cast(shader); + auto *glShader = static_cast(shader); pipeline->setGLProgram(glShader->getGLProgram()); } } - + return pipeline; } @@ -186,7 +188,7 @@ public: void incrementRenderPassSwitches() { stats_.renderPassSwitches++; } private: - SDL_Window* window_; + SDL_Window *window_; SDL_GLContext glContext_; std::unique_ptr context_; RenderStats stats_; diff --git a/src/renderer/rhi_module.cpp b/src/renderer/rhi_module.cpp index f82d617..73609f8 100644 --- a/src/renderer/rhi_module.cpp +++ b/src/renderer/rhi_module.cpp @@ -26,13 +26,13 @@ RHIModule::~RHIModule() { } bool RHIModule::init() { - E2D_LOG_INFO("正在初始化 RHI 模块..."); + E2D_INFO("正在初始化 RHI 模块..."); // 注册窗口显示事件监听,在窗口显示时创建 OpenGL 上下文 onShowListener_ = std::make_unique(); onShowListener_->bind([this]() { this->onWindowShow(); }); - E2D_LOG_INFO("RHI 模块已初始化 (等待窗口显示)"); + E2D_INFO("RHI 模块已初始化 (等待窗口显示)"); return true; } @@ -41,54 +41,45 @@ void RHIModule::onWindowShow() { return; } - E2D_LOG_INFO("RHI 模块: 正在创建 OpenGL 设备..."); + E2D_INFO("RHI 模块: 正在创建 OpenGL 设备..."); // 获取窗口模块 auto *windowModule = getModule(); if (!windowModule) { - E2D_LOG_ERROR("窗口模块不可用"); + E2D_ERROR("窗口模块不可用"); return; } // 等待窗口创建完成 if (!windowModule->handle()) { - E2D_LOG_ERROR("窗口尚未创建"); + E2D_ERROR("窗口尚未创建"); return; } // 创建 OpenGL 设备并传入窗口句柄 device_ = CreateGLDevice(); if (!device_) { - E2D_LOG_ERROR("创建 RHI 设备失败"); + E2D_ERROR("创建 RHI 设备失败"); return; } if (!device_->initialize(windowModule->handle())) { - E2D_LOG_ERROR("初始化 RHI 设备失败"); + E2D_ERROR("初始化 RHI 设备失败"); device_.reset(); return; } context_ = device_->getContext(); if (!context_) { - E2D_LOG_ERROR("获取 RHI 上下文失败"); + E2D_ERROR("获取 RHI 上下文失败"); device_->shutdown(); device_.reset(); return; } - - // 初始化上下文 - if (!context_->initialize()) { - E2D_LOG_ERROR("初始化 RHI 上下文失败"); - device_->shutdown(); - device_.reset(); - context_ = nullptr; - return; - } + // 注意:context 已在 GLDevice::initialize() 中初始化,这里不需要再次初始化 initialized_ = true; - E2D_LOG_INFO("RHIModule initialized successfully (backend: {})", - device_->getBackendName()); + E2D_INFO("RHI模块 初始化成功 (后端:{})", device_->getBackendName()); // RHI 初始化完成,再次触发 OnShow 事件通知其他模块 // 这样 RendererModule 等依赖 RHI 的模块可以完成初始化 @@ -96,7 +87,7 @@ void RHIModule::onWindowShow() { } void RHIModule::shutdown() { - E2D_LOG_INFO("Shutting down RHIModule..."); + E2D_INFO("正在关闭 RHI模块..."); // 清理事件监听器 onShowListener_.reset(); @@ -113,14 +104,14 @@ void RHIModule::shutdown() { initialized_ = false; - E2D_LOG_INFO("RHIModule shutdown complete"); + E2D_INFO("RHI模块 关闭完成"); } RHIModule *RHIModule::get() { return g_rhiModule; } std::unique_ptr RHIModule::createBuffer(const BufferDesc &desc) { if (!device_) { - E2D_LOG_ERROR("Cannot create buffer: RHI device not initialized"); + E2D_ERROR("无法创建缓冲区:RHI 设备未初始化"); return nullptr; } return device_->createBuffer(desc); @@ -128,7 +119,7 @@ std::unique_ptr RHIModule::createBuffer(const BufferDesc &desc) { std::unique_ptr RHIModule::createTexture(const TextureDesc &desc) { if (!device_) { - E2D_LOG_ERROR("无法创建纹理: RHI 设备未初始化"); + E2D_ERROR("无法创建纹理: RHI 设备未初始化"); return nullptr; } return device_->createTexture(desc); @@ -136,7 +127,7 @@ std::unique_ptr RHIModule::createTexture(const TextureDesc &desc) { std::unique_ptr RHIModule::createShader(const ShaderDesc &desc) { if (!device_) { - E2D_LOG_ERROR("无法创建着色器: RHI 设备未初始化"); + E2D_ERROR("无法创建着色器: RHI 设备未初始化"); return nullptr; } return device_->createShader(desc); @@ -145,7 +136,7 @@ std::unique_ptr RHIModule::createShader(const ShaderDesc &desc) { std::unique_ptr RHIModule::createPipeline(const PipelineDesc &desc) { if (!device_) { - E2D_LOG_ERROR("无法创建管线: RHI 设备未初始化"); + E2D_ERROR("无法创建管线: RHI 设备未初始化"); return nullptr; } return device_->createPipeline(desc); @@ -154,7 +145,7 @@ RHIModule::createPipeline(const PipelineDesc &desc) { std::unique_ptr RHIModule::createFramebuffer(const RenderPassDesc &desc) { if (!device_) { - E2D_LOG_ERROR("无法创建帧缓冲区: RHI 设备未初始化"); + E2D_ERROR("无法创建帧缓冲区: RHI 设备未初始化"); return nullptr; } return device_->createFramebuffer(desc); @@ -162,7 +153,7 @@ RHIModule::createFramebuffer(const RenderPassDesc &desc) { std::unique_ptr RHIModule::createCommandList() { if (!device_) { - E2D_LOG_ERROR("无法创建命令列表: RHI 设备未初始化"); + E2D_ERROR("无法创建命令列表: RHI 设备未初始化"); return nullptr; } return device_->createCommandList(); diff --git a/src/renderer/shader.cpp b/src/renderer/shader.cpp index c42465a..2e28ff4 100644 --- a/src/renderer/shader.cpp +++ b/src/renderer/shader.cpp @@ -35,13 +35,13 @@ bool Shader::loadFromSourceWithLayout(const std::string &vsSource, // 获取 RHI 设备 auto *rhiModule = RHIModule::get(); if (!rhiModule) { - E2D_LOG_ERROR("RHI 模块不可用"); + E2D_ERROR("RHI 模块不可用"); return false; } auto *device = rhiModule->getDevice(); if (!device) { - E2D_LOG_ERROR("RHI 设备不可用"); + E2D_ERROR("RHI 设备不可用"); return false; } @@ -57,7 +57,7 @@ bool Shader::loadFromSourceWithLayout(const std::string &vsSource, // 创建着色器 auto shader = device->createShader(shaderDesc); if (!shader) { - E2D_LOG_ERROR("创建着色器失败"); + E2D_ERROR("创建着色器失败"); return false; } @@ -76,7 +76,7 @@ bool Shader::loadFromSourceWithLayout(const std::string &vsSource, // 创建管线 auto pipeline = device->createPipeline(pipelineDesc); if (!pipeline) { - E2D_LOG_ERROR("创建管线失败"); + E2D_ERROR("创建管线失败"); handle_ = ShaderHandle(); return false; } @@ -84,7 +84,7 @@ bool Shader::loadFromSourceWithLayout(const std::string &vsSource, // 获取管线句柄 pipeline_ = PipelineHandle(pipeline.release()); - E2D_LOG_INFO("着色器创建成功"); + E2D_INFO("着色器创建成功"); return true; } @@ -127,13 +127,13 @@ bool Shader::reloadFromSourceWithLayout(const std::string &vsSource, // 获取 RHI 设备 auto *rhiModule = RHIModule::get(); if (!rhiModule) { - E2D_LOG_ERROR("RHI 模块不可用"); + E2D_ERROR("RHI 模块不可用"); return false; } auto *device = rhiModule->getDevice(); if (!device) { - E2D_LOG_ERROR("RHI 设备不可用"); + E2D_ERROR("RHI 设备不可用"); return false; } @@ -149,7 +149,7 @@ bool Shader::reloadFromSourceWithLayout(const std::string &vsSource, // 创建着色器 auto shader = device->createShader(shaderDesc); if (!shader) { - E2D_LOG_ERROR("重载时创建着色器失败"); + E2D_ERROR("重载时创建着色器失败"); return false; } @@ -168,7 +168,7 @@ bool Shader::reloadFromSourceWithLayout(const std::string &vsSource, // 创建管线 auto pipeline = device->createPipeline(pipelineDesc); if (!pipeline) { - E2D_LOG_ERROR("重载时创建管线失败"); + E2D_ERROR("重载时创建管线失败"); handle_ = ShaderHandle(); return false; } @@ -176,7 +176,7 @@ bool Shader::reloadFromSourceWithLayout(const std::string &vsSource, // 获取管线句柄 pipeline_ = PipelineHandle(pipeline.release()); - E2D_LOG_INFO("着色器重载成功"); + E2D_INFO("着色器重载成功"); return true; } diff --git a/src/renderer/texture.cpp b/src/renderer/texture.cpp index 181e3a6..241abb4 100644 --- a/src/renderer/texture.cpp +++ b/src/renderer/texture.cpp @@ -1,5 +1,5 @@ -#include #include +#include #include #define STB_IMAGE_IMPLEMENTATION #include @@ -9,223 +9,259 @@ namespace extra2d { Texture::Texture() = default; Texture::~Texture() { - // RHI 纹理句柄是轻量级句柄,不需要显式释放 - // 实际的纹理资源由 RHI 设备管理 - handle_ = TextureHandle(); + // RHI 纹理句柄是轻量级句柄,不需要显式释放 + // 实际的纹理资源由 RHI 设备管理 + handle_ = TextureHandle(); } -bool Texture::loadFromFile(const std::string& path) { - // 加载图片 - int channels; - stbi_set_flip_vertically_on_load(true); - unsigned char* data = stbi_load(path.c_str(), &width_, &height_, &channels, 0); - - if (!data) { - E2D_LOG_ERROR("加载纹理失败: {}", path); - return false; - } - - // 根据通道数确定格式 - TextureFormat format; - switch (channels) { - case 1: format = TextureFormat::R8; break; - case 2: format = TextureFormat::RG8; break; - case 3: format = TextureFormat::RGB8; break; - case 4: format = TextureFormat::RGBA8; break; - default: format = TextureFormat::RGBA8; break; - } - - bool result = loadFromMemory(data, width_, height_, format); - stbi_image_free(data); - - if (result) { - E2D_LOG_DEBUG("纹理已加载: {} ({}x{})", path, width_, height_); - } - - return result; +bool Texture::loadFromFile(const std::string &path) { + // 加载图片 + int channels; + stbi_set_flip_vertically_on_load(true); + unsigned char *data = + stbi_load(path.c_str(), &width_, &height_, &channels, 0); + + if (!data) { + E2D_ERROR("加载纹理失败: {}", path); + return false; + } + + // 根据通道数确定格式 + TextureFormat format; + switch (channels) { + case 1: + format = TextureFormat::R8; + break; + case 2: + format = TextureFormat::RG8; + break; + case 3: + format = TextureFormat::RGB8; + break; + case 4: + format = TextureFormat::RGBA8; + break; + default: + format = TextureFormat::RGBA8; + break; + } + + bool result = loadFromMemory(data, width_, height_, format); + stbi_image_free(data); + + if (result) { + E2D_DEBUG("纹理已加载: {} ({}x{})", path, width_, height_); + } + + return result; } -bool Texture::loadFromMemory(const uint8_t* data, int width, int height, TextureFormat format) { - // 释放旧纹理 - handle_ = TextureHandle(); - - width_ = width; - height_ = height; - format_ = format; - - // 获取 RHI 设备 - auto* rhiModule = RHIModule::get(); - if (!rhiModule) { - E2D_LOG_ERROR("RHI 模块不可用"); - return false; - } +bool Texture::loadFromMemory(const uint8_t *data, int width, int height, + TextureFormat format) { + // 释放旧纹理 + handle_ = TextureHandle(); - auto* device = rhiModule->getDevice(); - if (!device) { - E2D_LOG_ERROR("RHI 设备不可用"); - return false; - } - - // 创建纹理描述 - TextureDesc desc; - desc.width = static_cast(width); - desc.height = static_cast(height); - desc.format = format; - desc.mipLevels = 1; // 初始创建 1 层,后续生成 mipmap - - // 创建 RHI 纹理 - auto texture = device->createTexture(desc); - if (!texture) { - E2D_LOG_ERROR("创建 RHI 纹理失败"); - return false; - } - - // 上传纹理数据 - if (data) { - // 注意:update 方法的参数需要根据实际 RHI 接口调整 - // 这里假设 update 接受数据指针 - texture->update(data, static_cast(width * height * getBytesPerPixel(format))); - // 生成 mipmap - // 注意:generateMipmap 方法需要在 RHI 接口中实现 - } - - // 获取纹理句柄 - handle_ = TextureHandle(texture.release()); - - return true; + width_ = width; + height_ = height; + format_ = format; + + // 获取 RHI 设备 + auto *rhiModule = RHIModule::get(); + if (!rhiModule) { + E2D_ERROR("RHI 模块不可用"); + return false; + } + + auto *device = rhiModule->getDevice(); + if (!device) { + E2D_ERROR("RHI 设备不可用"); + return false; + } + + // 创建纹理描述 + TextureDesc desc; + desc.width = static_cast(width); + desc.height = static_cast(height); + desc.format = format; + desc.mipLevels = 1; // 初始创建 1 层,后续生成 mipmap + + // 创建 RHI 纹理 + auto texture = device->createTexture(desc); + if (!texture) { + E2D_ERROR("创建 RHI 纹理失败"); + return false; + } + + // 上传纹理数据 + if (data) { + // 注意:update 方法的参数需要根据实际 RHI 接口调整 + // 这里假设 update 接受数据指针 + texture->update( + data, static_cast(width * height * getBytesPerPixel(format))); + // 生成 mipmap + // 注意:generateMipmap 方法需要在 RHI 接口中实现 + } + + // 获取纹理句柄 + handle_ = TextureHandle(texture.release()); + + return true; } bool Texture::create(int width, int height, TextureFormat format) { - // 释放旧纹理 - handle_ = TextureHandle(); - - width_ = width; - height_ = height; - format_ = format; - - // 获取 RHI 设备 - auto* rhiModule = RHIModule::get(); - if (!rhiModule) { - E2D_LOG_ERROR("RHI 模块不可用"); - return false; - } + // 释放旧纹理 + handle_ = TextureHandle(); - auto* device = rhiModule->getDevice(); - if (!device) { - E2D_LOG_ERROR("RHI 设备不可用"); - return false; - } - - // 创建纹理描述 - TextureDesc desc; - desc.width = static_cast(width); - desc.height = static_cast(height); - desc.format = format; - desc.mipLevels = 1; // 不生成 mipmap - - // 创建 RHI 纹理 - auto texture = device->createTexture(desc); - if (!texture) { - E2D_LOG_ERROR("创建 RHI 纹理失败"); - return false; - } - - // 获取纹理句柄 - handle_ = TextureHandle(texture.release()); - - return true; + width_ = width; + height_ = height; + format_ = format; + + // 获取 RHI 设备 + auto *rhiModule = RHIModule::get(); + if (!rhiModule) { + E2D_ERROR("RHI 模块不可用"); + return false; + } + + auto *device = rhiModule->getDevice(); + if (!device) { + E2D_ERROR("RHI 设备不可用"); + return false; + } + + // 创建纹理描述 + TextureDesc desc; + desc.width = static_cast(width); + desc.height = static_cast(height); + desc.format = format; + desc.mipLevels = 1; // 不生成 mipmap + + // 创建 RHI 纹理 + auto texture = device->createTexture(desc); + if (!texture) { + E2D_ERROR("创建 RHI 纹理失败"); + return false; + } + + // 获取纹理句柄 + handle_ = TextureHandle(texture.release()); + + return true; } -bool Texture::reloadFromFile(const std::string& path) { - // 加载图片 - int channels; - stbi_set_flip_vertically_on_load(true); - unsigned char* data = stbi_load(path.c_str(), &width_, &height_, &channels, 0); - - if (!data) { - E2D_LOG_ERROR("重载纹理失败: {}", path); - return false; - } - - // 根据通道数确定格式 - TextureFormat format; - switch (channels) { - case 1: format = TextureFormat::R8; break; - case 2: format = TextureFormat::RG8; break; - case 3: format = TextureFormat::RGB8; break; - case 4: format = TextureFormat::RGBA8; break; - default: format = TextureFormat::RGBA8; break; - } - - bool result = reloadFromMemory(data, width_, height_, format); - stbi_image_free(data); - - if (result) { - E2D_LOG_INFO("纹理已重载: {} ({}x{})", path, width_, height_); - } - - return result; +bool Texture::reloadFromFile(const std::string &path) { + // 加载图片 + int channels; + stbi_set_flip_vertically_on_load(true); + unsigned char *data = + stbi_load(path.c_str(), &width_, &height_, &channels, 0); + + if (!data) { + E2D_ERROR("重载纹理失败: {}", path); + return false; + } + + // 根据通道数确定格式 + TextureFormat format; + switch (channels) { + case 1: + format = TextureFormat::R8; + break; + case 2: + format = TextureFormat::RG8; + break; + case 3: + format = TextureFormat::RGB8; + break; + case 4: + format = TextureFormat::RGBA8; + break; + default: + format = TextureFormat::RGBA8; + break; + } + + bool result = reloadFromMemory(data, width_, height_, format); + stbi_image_free(data); + + if (result) { + E2D_INFO("纹理已重载: {} ({}x{})", path, width_, height_); + } + + return result; } -bool Texture::reloadFromMemory(const uint8_t* data, int width, int height, TextureFormat format) { - // 更新尺寸和格式 - width_ = width; - height_ = height; - format_ = format; - - // 获取 RHI 设备 - auto* rhiModule = RHIModule::get(); - if (!rhiModule) { - E2D_LOG_ERROR("RHI 模块不可用"); - return false; - } +bool Texture::reloadFromMemory(const uint8_t *data, int width, int height, + TextureFormat format) { + // 更新尺寸和格式 + width_ = width; + height_ = height; + format_ = format; - auto* device = rhiModule->getDevice(); - if (!device) { - E2D_LOG_ERROR("RHI 设备不可用"); - return false; - } - - // 创建新的纹理描述 - TextureDesc desc; - desc.width = static_cast(width); - desc.height = static_cast(height); - desc.format = format; - desc.mipLevels = 1; - - // 创建新的 RHI 纹理 - auto texture = device->createTexture(desc); - if (!texture) { - E2D_LOG_ERROR("重载时创建 RHI 纹理失败"); - return false; - } - - // 上传纹理数据 - if (data) { - texture->update(data, static_cast(width * height * getBytesPerPixel(format))); - } - - // 替换旧的纹理句柄 - handle_ = TextureHandle(texture.release()); - - return true; + // 获取 RHI 设备 + auto *rhiModule = RHIModule::get(); + if (!rhiModule) { + E2D_ERROR("RHI 模块不可用"); + return false; + } + + auto *device = rhiModule->getDevice(); + if (!device) { + E2D_ERROR("RHI 设备不可用"); + return false; + } + + // 创建新的纹理描述 + TextureDesc desc; + desc.width = static_cast(width); + desc.height = static_cast(height); + desc.format = format; + desc.mipLevels = 1; + + // 创建新的 RHI 纹理 + auto texture = device->createTexture(desc); + if (!texture) { + E2D_ERROR("重载时创建 RHI 纹理失败"); + return false; + } + + // 上传纹理数据 + if (data) { + texture->update( + data, static_cast(width * height * getBytesPerPixel(format))); + } + + // 替换旧的纹理句柄 + handle_ = TextureHandle(texture.release()); + + return true; } // 辅助函数:获取每个像素的字节数 uint32_t Texture::getBytesPerPixel(TextureFormat format) { - switch (format) { - case TextureFormat::R8: return 1; - case TextureFormat::RG8: return 2; - case TextureFormat::RGB8: return 3; - case TextureFormat::RGBA8: - case TextureFormat::RGBA8_SRGB: return 4; - case TextureFormat::Depth16: return 2; - case TextureFormat::Depth24: return 3; - case TextureFormat::Depth32F: return 4; - case TextureFormat::Depth24Stencil8: return 4; - case TextureFormat::Depth32FStencil8: return 5; - default: return 4; - } + switch (format) { + case TextureFormat::R8: + return 1; + case TextureFormat::RG8: + return 2; + case TextureFormat::RGB8: + return 3; + case TextureFormat::RGBA8: + case TextureFormat::RGBA8_SRGB: + return 4; + case TextureFormat::Depth16: + return 2; + case TextureFormat::Depth24: + return 3; + case TextureFormat::Depth32F: + return 4; + case TextureFormat::Depth24Stencil8: + return 4; + case TextureFormat::Depth32FStencil8: + return 5; + default: + return 4; + } } } // namespace extra2d diff --git a/src/renderer/texture_atlas.cpp b/src/renderer/texture_atlas.cpp index a4ed105..9d3fe37 100644 --- a/src/renderer/texture_atlas.cpp +++ b/src/renderer/texture_atlas.cpp @@ -1,7 +1,7 @@ -#include -#include #include #include +#include +#include namespace extra2d { @@ -11,294 +11,295 @@ namespace extra2d { TextureAtlas::TextureAtlas() = default; -TextureAtlas::~TextureAtlas() { - shutdown(); +TextureAtlas::~TextureAtlas() { shutdown(); } + +TextureAtlas::TextureAtlas(TextureAtlas &&other) noexcept + : width_(other.width_), height_(other.height_), + atlasTexture_(std::move(other.atlasTexture_)), + regions_(std::move(other.regions_)), + pendingTextures_(std::move(other.pendingTextures_)), + packContext_(std::move(other.packContext_)), + packNodes_(std::move(other.packNodes_)), finalized_(other.finalized_) { + other.width_ = 0; + other.height_ = 0; + other.finalized_ = false; } -TextureAtlas::TextureAtlas(TextureAtlas&& other) noexcept - : width_(other.width_) - , height_(other.height_) - , atlasTexture_(std::move(other.atlasTexture_)) - , regions_(std::move(other.regions_)) - , pendingTextures_(std::move(other.pendingTextures_)) - , packContext_(std::move(other.packContext_)) - , packNodes_(std::move(other.packNodes_)) - , finalized_(other.finalized_) { +TextureAtlas &TextureAtlas::operator=(TextureAtlas &&other) noexcept { + if (this != &other) { + shutdown(); + + width_ = other.width_; + height_ = other.height_; + atlasTexture_ = std::move(other.atlasTexture_); + regions_ = std::move(other.regions_); + pendingTextures_ = std::move(other.pendingTextures_); + packContext_ = std::move(other.packContext_); + packNodes_ = std::move(other.packNodes_); + finalized_ = other.finalized_; + other.width_ = 0; other.height_ = 0; other.finalized_ = false; -} - -TextureAtlas& TextureAtlas::operator=(TextureAtlas&& other) noexcept { - if (this != &other) { - shutdown(); - - width_ = other.width_; - height_ = other.height_; - atlasTexture_ = std::move(other.atlasTexture_); - regions_ = std::move(other.regions_); - pendingTextures_ = std::move(other.pendingTextures_); - packContext_ = std::move(other.packContext_); - packNodes_ = std::move(other.packNodes_); - finalized_ = other.finalized_; - - other.width_ = 0; - other.height_ = 0; - other.finalized_ = false; - } - return *this; + } + return *this; } bool TextureAtlas::initialize(int width, int height) { - shutdown(); - - if (width <= 0 || height <= 0) { - E2D_LOG_ERROR("TextureAtlas::initialize: 无效的尺寸 {}x{}", width, height); - return false; - } - - width_ = width; - height_ = height; - - // 初始化 stb_rect_pack - packContext_ = std::make_unique(); - packNodes_.resize(width); - stbrp_init_target(packContext_.get(), width, height, packNodes_.data(), width); - - E2D_LOG_DEBUG("纹理图集已初始化: {}x{}", width, height); - return true; + shutdown(); + + if (width <= 0 || height <= 0) { + E2D_ERROR("TextureAtlas::initialize: 无效的尺寸 {}x{}", width, height); + return false; + } + + width_ = width; + height_ = height; + + // 初始化 stb_rect_pack + packContext_ = std::make_unique(); + packNodes_.resize(width); + stbrp_init_target(packContext_.get(), width, height, packNodes_.data(), + width); + + E2D_DEBUG("纹理图集已初始化: {}x{}", width, height); + return true; } void TextureAtlas::shutdown() { - atlasTexture_.reset(); - regions_.clear(); - pendingTextures_.clear(); - packContext_.reset(); - packNodes_.clear(); - width_ = 0; - height_ = 0; - finalized_ = false; + atlasTexture_.reset(); + regions_.clear(); + pendingTextures_.clear(); + packContext_.reset(); + packNodes_.clear(); + width_ = 0; + height_ = 0; + finalized_ = false; } -bool TextureAtlas::addTexture(const std::string& name, Ptr texture) { - if (finalized_) { - E2D_LOG_WARN("TextureAtlas::addTexture: 无法向已完成的图集添加纹理"); - return false; - } +bool TextureAtlas::addTexture(const std::string &name, Ptr texture) { + if (finalized_) { + E2D_WARN("TextureAtlas::addTexture: 无法向已完成的图集添加纹理"); + return false; + } - if (!texture) { - E2D_LOG_WARN("TextureAtlas::addTexture: 纹理为空"); - return false; - } + if (!texture) { + E2D_WARN("TextureAtlas::addTexture: 纹理为空"); + return false; + } - if (regions_.find(name) != regions_.end()) { - E2D_LOG_WARN("TextureAtlas::addTexture: 纹理 '{}' 已存在", name); - return false; - } + if (regions_.find(name) != regions_.end()) { + E2D_WARN("TextureAtlas::addTexture: 纹理 '{}' 已存在", name); + return false; + } - // 获取纹理尺寸 - int texWidth = static_cast(texture->getWidth()); - int texHeight = static_cast(texture->getHeight()); + // 获取纹理尺寸 + int texWidth = static_cast(texture->getWidth()); + int texHeight = static_cast(texture->getHeight()); - if (texWidth <= 0 || texHeight <= 0) { - E2D_LOG_WARN("TextureAtlas::addTexture: 无效的纹理尺寸 {}x{}", texWidth, texHeight); - return false; - } + if (texWidth <= 0 || texHeight <= 0) { + E2D_WARN("TextureAtlas::addTexture: 无效的纹理尺寸 {}x{}", texWidth, + texHeight); + return false; + } - // 检查纹理是否适合图集 - if (texWidth > width_ || texHeight > height_) { - E2D_LOG_WARN("TextureAtlas::addTexture: 纹理 {}x{} 太大,无法放入图集 {}x{}", - texWidth, texHeight, width_, height_); - return false; - } - - // 创建待处理纹理信息 - PendingTexture pending; - pending.name = name; - pending.width = texWidth; - pending.height = texHeight; - pending.format = texture->getFormat(); - - // 获取纹理数据 - size_t dataSize = texWidth * texHeight * 4; // 假设 RGBA - pending.data.resize(dataSize); - - // TODO: 实现 Texture::getData() 方法来读取像素数据 - // 暂时使用占位数据 - std::fill(pending.data.begin(), pending.data.end(), 255); - - pendingTextures_.push_back(std::move(pending)); - - E2D_LOG_DEBUG("纹理图集: 已添加纹理 '{}' ({}x{})", name, texWidth, texHeight); - return true; + // 检查纹理是否适合图集 + if (texWidth > width_ || texHeight > height_) { + E2D_WARN("TextureAtlas::addTexture: 纹理 {}x{} 太大,无法放入图集 {}x{}", + texWidth, texHeight, width_, height_); + return false; + } + + // 创建待处理纹理信息 + PendingTexture pending; + pending.name = name; + pending.width = texWidth; + pending.height = texHeight; + pending.format = texture->getFormat(); + + // 获取纹理数据 + size_t dataSize = texWidth * texHeight * 4; // 假设 RGBA + pending.data.resize(dataSize); + + // TODO: 实现 Texture::getData() 方法来读取像素数据 + // 暂时使用占位数据 + std::fill(pending.data.begin(), pending.data.end(), 255); + + pendingTextures_.push_back(std::move(pending)); + + E2D_DEBUG("纹理图集: 已添加纹理 '{}' ({}x{})", name, texWidth, texHeight); + return true; } -bool TextureAtlas::addTextureData(const std::string& name, const uint8_t* data, +bool TextureAtlas::addTextureData(const std::string &name, const uint8_t *data, int width, int height, TextureFormat format) { - if (finalized_) { - E2D_LOG_WARN("TextureAtlas::addTextureData: 无法向已完成的图集添加纹理"); - return false; - } + if (finalized_) { + E2D_WARN("TextureAtlas::addTextureData: 无法向已完成的图集添加纹理"); + return false; + } - if (!data || width <= 0 || height <= 0) { - E2D_LOG_WARN("TextureAtlas::addTextureData: 无效参数"); - return false; - } + if (!data || width <= 0 || height <= 0) { + E2D_WARN("TextureAtlas::addTextureData: 无效参数"); + return false; + } - if (regions_.find(name) != regions_.end()) { - E2D_LOG_WARN("TextureAtlas::addTextureData: 纹理 '{}' 已存在", name); - return false; - } + if (regions_.find(name) != regions_.end()) { + E2D_WARN("TextureAtlas::addTextureData: 纹理 '{}' 已存在", name); + return false; + } - if (width > width_ || height > height_) { - E2D_LOG_WARN("TextureAtlas::addTextureData: 纹理 {}x{} 太大,无法放入图集 {}x{}", - width, height, width_, height_); - return false; - } - - PendingTexture pending; - pending.name = name; - pending.width = width; - pending.height = height; - pending.format = format; - - // 复制像素数据 - int channels = (format == TextureFormat::RGBA8) ? 4 : 3; - size_t dataSize = width * height * channels; - pending.data.resize(dataSize); - std::memcpy(pending.data.data(), data, dataSize); - - pendingTextures_.push_back(std::move(pending)); - - E2D_LOG_DEBUG("纹理图集: 已添加纹理数据 '{}' ({}x{})", name, width, height); - return true; + if (width > width_ || height > height_) { + E2D_WARN( + "TextureAtlas::addTextureData: 纹理 {}x{} 太大,无法放入图集 {}x{}", + width, height, width_, height_); + return false; + } + + PendingTexture pending; + pending.name = name; + pending.width = width; + pending.height = height; + pending.format = format; + + // 复制像素数据 + int channels = (format == TextureFormat::RGBA8) ? 4 : 3; + size_t dataSize = width * height * channels; + pending.data.resize(dataSize); + std::memcpy(pending.data.data(), data, dataSize); + + pendingTextures_.push_back(std::move(pending)); + + E2D_DEBUG("纹理图集: 已添加纹理数据 '{}' ({}x{})", name, width, height); + return true; } bool TextureAtlas::finalize() { - if (finalized_) { - return true; - } - - if (pendingTextures_.empty()) { - E2D_LOG_WARN("TextureAtlas::finalize: 没有要打包的纹理"); - return false; - } - - // 准备矩形数组 - std::vector rects; - rects.reserve(pendingTextures_.size()); - - for (size_t i = 0; i < pendingTextures_.size(); ++i) { - stbrp_rect rect; - rect.id = static_cast(i); - rect.w = pendingTextures_[i].width; - rect.h = pendingTextures_[i].height; - rect.x = 0; - rect.y = 0; - rect.was_packed = 0; - rects.push_back(rect); - } - - // 执行打包 - int result = stbrp_pack_rects(packContext_.get(), rects.data(), static_cast(rects.size())); - - if (!result) { - E2D_LOG_ERROR("TextureAtlas::finalize: 打包所有纹理失败"); - return false; - } - - // 创建图集纹理数据 - std::vector atlasData(width_ * height_ * 4, 0); // RGBA 黑色背景 - - // 处理打包结果 - for (const auto& rect : rects) { - if (!rect.was_packed) { - E2D_LOG_WARN("TextureAtlas::finalize: 纹理 {} 未被打包", rect.id); - continue; - } - - const auto& pending = pendingTextures_[rect.id]; - - // 创建区域信息 - AtlasRegion region; - region.x = rect.x; - region.y = rect.y; - region.width = rect.w; - region.height = rect.h; - - regions_[pending.name] = region; - - // 复制像素数据到图集 - // TODO: 实现正确的像素格式转换 - // 目前假设所有纹理都是 RGBA8 - for (int y = 0; y < pending.height; ++y) { - for (int x = 0; x < pending.width; ++x) { - int srcIdx = (y * pending.width + x) * 4; - int dstIdx = ((rect.y + y) * width_ + (rect.x + x)) * 4; - - if (srcIdx + 3 < static_cast(pending.data.size()) && - dstIdx + 3 < static_cast(atlasData.size())) { - atlasData[dstIdx + 0] = pending.data[srcIdx + 0]; - atlasData[dstIdx + 1] = pending.data[srcIdx + 1]; - atlasData[dstIdx + 2] = pending.data[srcIdx + 2]; - atlasData[dstIdx + 3] = pending.data[srcIdx + 3]; - } - } - } - - E2D_LOG_DEBUG("纹理图集: 已打包 '{}' 在 ({}, {}) 尺寸 {}x{}", - pending.name, rect.x, rect.y, rect.w, rect.h); - } - - // 创建图集纹理 - atlasTexture_ = makePtr(); - if (!atlasTexture_->loadFromMemory(atlasData.data(), width_, height_, TextureFormat::RGBA8)) { - E2D_LOG_ERROR("TextureAtlas::finalize: 创建图集纹理失败"); - return false; - } - - // 清理待处理列表 - pendingTextures_.clear(); - finalized_ = true; - - E2D_LOG_INFO("纹理图集完成: {} 个纹理打包到 {}x{} 图集 (使用率 {}%)", - regions_.size(), width_, height_, - static_cast(getUsageRatio() * 100)); - + if (finalized_) { return true; -} + } -const AtlasRegion* TextureAtlas::getRegion(const std::string& name) const { - auto it = regions_.find(name); - if (it != regions_.end()) { - return &it->second; + if (pendingTextures_.empty()) { + E2D_WARN("TextureAtlas::finalize: 没有要打包的纹理"); + return false; + } + + // 准备矩形数组 + std::vector rects; + rects.reserve(pendingTextures_.size()); + + for (size_t i = 0; i < pendingTextures_.size(); ++i) { + stbrp_rect rect; + rect.id = static_cast(i); + rect.w = pendingTextures_[i].width; + rect.h = pendingTextures_[i].height; + rect.x = 0; + rect.y = 0; + rect.was_packed = 0; + rects.push_back(rect); + } + + // 执行打包 + int result = stbrp_pack_rects(packContext_.get(), rects.data(), + static_cast(rects.size())); + + if (!result) { + E2D_ERROR("TextureAtlas::finalize: 打包所有纹理失败"); + return false; + } + + // 创建图集纹理数据 + std::vector atlasData(width_ * height_ * 4, 0); // RGBA 黑色背景 + + // 处理打包结果 + for (const auto &rect : rects) { + if (!rect.was_packed) { + E2D_WARN("TextureAtlas::finalize: 纹理 {} 未被打包", rect.id); + continue; } - return nullptr; -} -Rect TextureAtlas::getUVRect(const std::string& name) const { - const AtlasRegion* region = getRegion(name); - if (region) { - return region->getUVRect(width_, height_); + const auto &pending = pendingTextures_[rect.id]; + + // 创建区域信息 + AtlasRegion region; + region.x = rect.x; + region.y = rect.y; + region.width = rect.w; + region.height = rect.h; + + regions_[pending.name] = region; + + // 复制像素数据到图集 + // TODO: 实现正确的像素格式转换 + // 目前假设所有纹理都是 RGBA8 + for (int y = 0; y < pending.height; ++y) { + for (int x = 0; x < pending.width; ++x) { + int srcIdx = (y * pending.width + x) * 4; + int dstIdx = ((rect.y + y) * width_ + (rect.x + x)) * 4; + + if (srcIdx + 3 < static_cast(pending.data.size()) && + dstIdx + 3 < static_cast(atlasData.size())) { + atlasData[dstIdx + 0] = pending.data[srcIdx + 0]; + atlasData[dstIdx + 1] = pending.data[srcIdx + 1]; + atlasData[dstIdx + 2] = pending.data[srcIdx + 2]; + atlasData[dstIdx + 3] = pending.data[srcIdx + 3]; + } + } } - return Rect(0.0f, 0.0f, 1.0f, 1.0f); + + E2D_DEBUG("纹理图集: 已打包 '{}' 在 ({}, {}) 尺寸 {}x{}", pending.name, + rect.x, rect.y, rect.w, rect.h); + } + + // 创建图集纹理 + atlasTexture_ = makePtr(); + if (!atlasTexture_->loadFromMemory(atlasData.data(), width_, height_, + TextureFormat::RGBA8)) { + E2D_ERROR("TextureAtlas::finalize: 创建图集纹理失败"); + return false; + } + + // 清理待处理列表 + pendingTextures_.clear(); + finalized_ = true; + + E2D_INFO("纹理图集完成: {} 个纹理打包到 {}x{} 图集 (使用率 {}%)", + regions_.size(), width_, height_, + static_cast(getUsageRatio() * 100)); + + return true; } -bool TextureAtlas::hasTexture(const std::string& name) const { - return regions_.find(name) != regions_.end(); +const AtlasRegion *TextureAtlas::getRegion(const std::string &name) const { + auto it = regions_.find(name); + if (it != regions_.end()) { + return &it->second; + } + return nullptr; +} + +Rect TextureAtlas::getUVRect(const std::string &name) const { + const AtlasRegion *region = getRegion(name); + if (region) { + return region->getUVRect(width_, height_); + } + return Rect(0.0f, 0.0f, 1.0f, 1.0f); +} + +bool TextureAtlas::hasTexture(const std::string &name) const { + return regions_.find(name) != regions_.end(); } float TextureAtlas::getUsageRatio() const { - if (!finalized_ || regions_.empty()) { - return 0.0f; - } - - int totalArea = 0; - for (const auto& pair : regions_) { - totalArea += pair.second.width * pair.second.height; - } - - return static_cast(totalArea) / (width_ * height_); + if (!finalized_ || regions_.empty()) { + return 0.0f; + } + + int totalArea = 0; + for (const auto &pair : regions_) { + totalArea += pair.second.width * pair.second.height; + } + + return static_cast(totalArea) / (width_ * height_); } // ======================================== @@ -306,62 +307,63 @@ float TextureAtlas::getUsageRatio() const { // ======================================== Ptr AtlasBuilder::build() { - if (textures_.empty()) { - E2D_LOG_WARN("AtlasBuilder::build: No textures to build"); - return nullptr; - } - - auto atlas = makePtr(); - if (!atlas->initialize(width_, height_)) { - return nullptr; - } - - for (const auto& pair : textures_) { - atlas->addTexture(pair.first, pair.second); - } - - if (!atlas->finalize()) { - return nullptr; - } - - return atlas; + if (textures_.empty()) { + E2D_WARN("AtlasBuilder::build: No textures to build"); + return nullptr; + } + + auto atlas = makePtr(); + if (!atlas->initialize(width_, height_)) { + return nullptr; + } + + for (const auto &pair : textures_) { + atlas->addTexture(pair.first, pair.second); + } + + if (!atlas->finalize()) { + return nullptr; + } + + return atlas; } Ptr AtlasBuilder::buildAuto() { - if (textures_.empty()) { - E2D_LOG_WARN("AtlasBuilder::buildAuto: No textures to build"); - return nullptr; + if (textures_.empty()) { + E2D_WARN("AtlasBuilder::buildAuto: No textures to build"); + return nullptr; + } + + // 计算总面积 + int totalArea = 0; + int maxWidth = 0; + int maxHeight = 0; + + for (const auto &pair : textures_) { + if (pair.second) { + int w = static_cast(pair.second->getWidth()); + int h = static_cast(pair.second->getHeight()); + totalArea += w * h; + maxWidth = std::max(maxWidth, w); + maxHeight = std::max(maxHeight, h); } - - // 计算总面积 - int totalArea = 0; - int maxWidth = 0; - int maxHeight = 0; - - for (const auto& pair : textures_) { - if (pair.second) { - int w = static_cast(pair.second->getWidth()); - int h = static_cast(pair.second->getHeight()); - totalArea += w * h; - maxWidth = std::max(maxWidth, w); - maxHeight = std::max(maxHeight, h); - } + } + + // 选择合适的大小(2 的幂) + int atlasSize = 64; + while (atlasSize < maxWidth || atlasSize < maxHeight || + atlasSize * atlasSize < totalArea * 1.5f) { + atlasSize *= 2; + if (atlasSize > 8192) { + E2D_ERROR("AtlasBuilder::buildAuto: Textures too large for atlas"); + return nullptr; } - - // 选择合适的大小(2 的幂) - int atlasSize = 64; - while (atlasSize < maxWidth || atlasSize < maxHeight || atlasSize * atlasSize < totalArea * 1.5f) { - atlasSize *= 2; - if (atlasSize > 8192) { - E2D_LOG_ERROR("AtlasBuilder::buildAuto: Textures too large for atlas"); - return nullptr; - } - } - - width_ = atlasSize; - height_ = atlasSize; - - return build(); + } + + width_ = atlasSize; + height_ = atlasSize; + + return build(); } } // namespace extra2d diff --git a/src/renderer/uniform_buffer.cpp b/src/renderer/uniform_buffer.cpp index 65ef9aa..17eaa70 100644 --- a/src/renderer/uniform_buffer.cpp +++ b/src/renderer/uniform_buffer.cpp @@ -15,13 +15,13 @@ bool UniformBuffer::create(uint32_t size, uint32_t binding) { // 获取 RHI 设备 auto *rhiModule = RHIModule::get(); if (!rhiModule) { - E2D_LOG_ERROR("RHI 模块不可用"); + E2D_ERROR("RHI 模块不可用"); return false; } auto *device = rhiModule->getDevice(); if (!device) { - E2D_LOG_ERROR("RHI 设备不可用"); + E2D_ERROR("RHI 设备不可用"); return false; } @@ -34,14 +34,14 @@ bool UniformBuffer::create(uint32_t size, uint32_t binding) { // 创建缓冲区 auto buffer = device->createBuffer(desc); if (!buffer) { - E2D_LOG_ERROR("创建 uniform 缓冲区失败"); + E2D_ERROR("创建 uniform 缓冲区失败"); return false; } // 获取缓冲区句柄 handle_ = BufferHandle(buffer.release()); - E2D_LOG_DEBUG("UBO 已创建: 大小={}, 绑定槽={}", size, binding); + E2D_DEBUG("UBO 已创建: 大小={}, 绑定槽={}", size, binding); return true; } @@ -57,8 +57,8 @@ void UniformBuffer::update(const void *data, uint32_t size, uint32_t offset) { return; if (offset + size > size_) { - E2D_LOG_WARN("UBO 更新超出边界: 偏移={}, 大小={}, 缓冲区大小={}", - offset, size, size_); + E2D_WARN("UBO 更新超出边界: 偏移={}, 大小={}, 缓冲区大小={}", offset, size, + size_); return; } @@ -123,7 +123,7 @@ bool UniformBufferManager::initialize() { globalUBOs_[i] = std::make_unique(); if (!globalUBOs_[i]->create(UniformBufferManager::GLOBAL_UBO_SIZE, UniformBufferManager::GLOBAL_UBO_BINDING)) { - E2D_LOG_ERROR("创建全局 UBO {} 失败", i); + E2D_ERROR("创建全局 UBO {} 失败", i); return false; } } @@ -134,13 +134,13 @@ bool UniformBufferManager::initialize() { // 预分配材质 UBO CPU 缓冲区 materialUBOBuffer_.resize(MATERIAL_UBO_BUFFER_SIZE); - E2D_LOG_INFO("UniformBufferManager 已初始化,使用双缓冲"); + E2D_INFO("UniformBufferManager 已初始化,使用双缓冲"); return true; } void UniformBufferManager::shutdown() { materialUBOPool_.clear(); - for (auto& ubo : globalUBOs_) { + for (auto &ubo : globalUBOs_) { ubo.reset(); } currentUBOIndex_ = 0; @@ -148,7 +148,7 @@ void UniformBufferManager::shutdown() { materialUBOBufferOffset_ = 0; currentMaterialUBO_ = nullptr; - E2D_LOG_INFO("UniformBufferManager 已关闭"); + E2D_INFO("UniformBufferManager 已关闭"); } UniformBuffer *UniformBufferManager::getGlobalUBO(uint32_t frameIndex) { @@ -169,7 +169,7 @@ UniformBuffer *UniformBufferManager::acquireMaterialUBO(uint32_t size) { // 需要创建新的 UBO auto ubo = std::make_unique(); if (!ubo->create(size, UniformBufferManager::MATERIAL_UBO_BINDING)) { - E2D_LOG_ERROR("创建材质 UBO 失败"); + E2D_ERROR("创建材质 UBO 失败"); return nullptr; } @@ -186,7 +186,8 @@ void UniformBufferManager::resetMaterialUBOs() { currentMaterialUBO_ = nullptr; } -void UniformBufferManager::updateGlobalUBO(const void *data, uint32_t size, uint32_t frameIndex) { +void UniformBufferManager::updateGlobalUBO(const void *data, uint32_t size, + uint32_t frameIndex) { // 使用双缓冲更新全局 UBO size_t index = frameIndex % 2; if (globalUBOs_[index]) { @@ -195,9 +196,11 @@ void UniformBufferManager::updateGlobalUBO(const void *data, uint32_t size, uint } } -void UniformBufferManager::batchUpdateMaterialUBO(const void *data, uint32_t size, uint32_t offset) { +void UniformBufferManager::batchUpdateMaterialUBO(const void *data, + uint32_t size, + uint32_t offset) { if (!data || size == 0 || offset + size > materialUBOBuffer_.size()) { - E2D_LOG_WARN("无效的批量更新参数"); + E2D_WARN("无效的批量更新参数"); return; } @@ -211,7 +214,8 @@ void UniformBufferManager::flushMaterialUBO() { } // 一次性将 CPU 缓冲区数据更新到 GPU - currentMaterialUBO_->update(materialUBOBuffer_.data(), materialUBOBufferOffset_, 0); + currentMaterialUBO_->update(materialUBOBuffer_.data(), + materialUBOBufferOffset_, 0); materialUBOBufferOffset_ = 0; } diff --git a/src/scene/components/camera_component.cpp b/src/scene/components/camera_component.cpp index c3dd59e..65c4db5 100644 --- a/src/scene/components/camera_component.cpp +++ b/src/scene/components/camera_component.cpp @@ -47,8 +47,8 @@ void CameraComponent::setOrtho(float left, float right, float bottom, float top, far_ = far; markProjDirty(); - E2D_LOG_DEBUG("正交投影已设置: 左={}, 右={}, 下={}, 上={}, 近={}, 远={}", - left, right, bottom, top, near, far); + E2D_DEBUG("正交投影已设置: 左={}, 右={}, 下={}, 上={}, 近={}, 远={}", left, + right, bottom, top, near, far); } /** diff --git a/src/scene/director.cpp b/src/scene/director.cpp index ff03665..4895a02 100644 --- a/src/scene/director.cpp +++ b/src/scene/director.cpp @@ -132,7 +132,7 @@ void Director::render() { Mat4 viewProj = camera->getViewProjectionMatrix(); events::OnRenderSetCamera::emit(viewProj); } else { - E2D_LOG_WARN("Director::render: 未设置主相机!"); + E2D_WARN("Director::render: 未设置主相机!"); } runningScene_->render(); diff --git a/src/utils/logger.cpp b/src/utils/logger.cpp index 864ad8e..d1690f1 100644 --- a/src/utils/logger.cpp +++ b/src/utils/logger.cpp @@ -1,65 +1,25 @@ #include +#include +#include + #ifdef _WIN32 -#include -#include #include #endif namespace extra2d { -// 静态成员定义 -LogLevel Logger::level_ = LogLevel::Info; +std::shared_ptr Logger::logger_ = nullptr; bool Logger::initialized_ = false; bool Logger::consoleOutput_ = true; bool Logger::fileOutput_ = false; std::string Logger::logFile_; -// Switch 平台:自定义 SDL 日志输出函数 -#ifdef __SWITCH__ -/** - * @brief Switch 平台日志输出回调函数 - * @param userdata 用户数据 - * @param category 日志类别 - * @param priority 日志优先级 - * @param message 日志消息 - */ -static void SwitchLogOutput(void *userdata, int category, - SDL_LogPriority priority, const char *message) { - (void)userdata; - (void)category; - (void)priority; - // 输出到 Switch 控制台 - printf("%s\n", message); -} -#endif - -/** - * @brief 获取日志级别字符串 - * @param level 日志级别 - * @return 级别字符串 - */ -const char *Logger::getLevelString(LogLevel level) { - switch (level) { - case LogLevel::Trace: - return "跟踪"; - case LogLevel::Debug: - return "调试"; - case LogLevel::Info: - return "信息"; - case LogLevel::Warn: - return "警告"; - case LogLevel::Error: - return "错误"; - case LogLevel::Fatal: - return "致命"; - default: - return "未知"; - } -} - /** * @brief 初始化日志系统 + * + * 设置控制台输出编码(Windows),初始化 Nintendo Switch 控制台(Switch 平台) + * 创建日志输出目标(控制台和/或文件),注册日志器到 spdlog */ void Logger::init() { if (initialized_) { @@ -67,41 +27,59 @@ void Logger::init() { } #ifdef _WIN32 - // 获取标准输出句柄 - HANDLE hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE); - if (hConsoleOut == INVALID_HANDLE_VALUE) { - return; - } - - // 设置控制台输出代码页为UTF-8 (65001是UTF-8的代码页编号) SetConsoleOutputCP(CP_UTF8); - - // 设置控制台模式,确保支持UTF-8输出(可选,但能提升兼容性) - DWORD consoleMode; - GetConsoleMode(hConsoleOut, &consoleMode); - consoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; // 启用ANSI转义序列(可选) - SetConsoleMode(hConsoleOut, consoleMode); #endif #ifdef __SWITCH__ - // Switch 平台:初始化控制台并设置 SDL 日志重定向 consoleInit(NULL); - SDL_LogSetOutputFunction(SwitchLogOutput, nullptr); -#else - // 其他平台:设置 SDL 日志级别为详细模式 - SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_VERBOSE); #endif + std::vector sinks; + + if (consoleOutput_) { + auto consoleSink = std::make_shared(); + consoleSink->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] %v"); + sinks.push_back(consoleSink); + } + + if (fileOutput_ && !logFile_.empty()) { + auto fileSink = + std::make_shared(logFile_, true); + fileSink->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v"); + sinks.push_back(fileSink); + } + + if (sinks.empty()) { + auto consoleSink = std::make_shared(); + consoleSink->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] %v"); + sinks.push_back(consoleSink); + } + + logger_ = + std::make_shared("extra2d", sinks.begin(), sinks.end()); + logger_->set_level(spdlog::level::trace); + logger_->flush_on(spdlog::level::warn); + + spdlog::register_logger(logger_); + spdlog::set_default_logger(logger_); + + // 注册后重新设置日志级别,防止被 registry 的全局级别覆盖 + logger_->set_level(spdlog::level::trace); + initialized_ = true; log(LogLevel::Info, "日志系统已初始化"); } /** * @brief 关闭日志系统 + * + * 记录关闭日志,释放 spdlog 资源,清理 Nintendo Switch 控制台 */ void Logger::shutdown() { if (initialized_) { log(LogLevel::Info, "日志系统正在关闭"); + spdlog::shutdown(); + logger_.reset(); #ifdef __SWITCH__ consoleExit(NULL); #endif @@ -111,45 +89,53 @@ void Logger::shutdown() { /** * @brief 设置日志级别 - * @param level 日志级别 + * @param level 要设置的日志级别 + * + * 低于此级别的日志将不会被输出 */ void Logger::setLevel(LogLevel level) { - level_ = level; - // 同时设置 SDL 的日志级别 - if (level != LogLevel::Off) { - SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, - static_cast(level)); + if (logger_) { + logger_->set_level(static_cast(level)); } } /** - * @brief 设置是否输出到控制台 - * @param enable 是否启用 + * @brief 启用或禁用控制台输出 + * @param enable true 启用控制台输出,false 禁用 */ -void Logger::setConsoleOutput(bool enable) { - consoleOutput_ = enable; - // SDL2 日志默认输出到控制台,通过设置日志优先级控制 - if (!enable) { - SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_CRITICAL); - } else { - SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, - static_cast(level_)); - } -} +void Logger::setConsoleOutput(bool enable) { consoleOutput_ = enable; } /** - * @brief 设置日志输出到文件 - * @param filename 日志文件名 + * @brief 设置文件输出路径 + * @param filename 日志文件路径,为空字符串则禁用文件输出 */ void Logger::setFileOutput(const std::string &filename) { logFile_ = filename; fileOutput_ = !filename.empty(); +} - if (fileOutput_) { - // SDL2 使用 SDL_LogSetOutputFunction 可以重定向日志输出 - // 这里我们记录文件路径,实际文件输出可以通过自定义回调实现 - log(LogLevel::Info, "文件输出已配置: {}", filename); +/** + * @brief 获取当前日志级别 + * @return 当前设置的日志级别,如果日志器未初始化则返回 Info + */ +LogLevel Logger::getLevel() { + if (logger_) { + return static_cast(logger_->level()); } + return LogLevel::Info; +} + +/** + * @brief 记录日志(字符串版本) + * @param level 日志级别 + * @param msg 日志消息 + */ +void Logger::log(LogLevel level, const char *msg) { + if (!logger_) { + return; + } + auto spdLevel = static_cast(level); + logger_->log(spdLevel, msg); } } // namespace extra2d diff --git a/xmake/engine.lua b/xmake/engine.lua index ef0e962..c2e953d 100644 --- a/xmake/engine.lua +++ b/xmake/engine.lua @@ -15,10 +15,14 @@ function define_extra2d_engine() add_files("src/**.cpp") add_files("third_party/glad/src/glad.c") + add_files("third_party/spdlog/src/*.cpp") add_includedirs("include", {public = true}) add_includedirs("third_party", {public = true}) add_includedirs("third_party/glad/include", {public = true}) + add_includedirs("third_party/spdlog/include", {public = true}) + + add_defines("SPDLOG_COMPILED_LIB", {public = true}) local plat = get_current_plat() if plat == "mingw" then @@ -47,7 +51,7 @@ function define_extra2d_engine() add_cxxflags("-Wno-deprecated-copy", "-Wno-class-memaccess", {force = true}) if is_mode("debug") then - add_defines("E2D_DEBUG", "_DEBUG", {public = true}) + add_defines("_DEBUG", {public = true}) add_cxxflags("-O0", "-g", {force = true}) else add_defines("NDEBUG", {public = true})