refactor(logger): 替换日志系统为spdlog实现

重构日志系统,使用spdlog替代原有实现,提供更强大的格式化功能和性能优化
移除自定义日志格式化和级别处理代码,统一使用spdlog接口
更新所有日志调用点,移除E2D_LOG_前缀宏,简化为E2D_前缀
添加spdlog为第三方依赖,更新构建配置
This commit is contained in:
ChestnutYueyue 2026-03-03 21:23:54 +08:00
parent 8864637459
commit 579aa2dd0d
25 changed files with 1500 additions and 1433 deletions

View File

@ -1,7 +0,0 @@
{
"permissions": {
"allow": [
"Bash(git diff:*)"
]
}
}

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <renderer/rhi/rhi.h>
#include <glad/glad.h> #include <glad/glad.h>
#include <renderer/rhi/rhi.h>
#include <utils/logger.h> #include <utils/logger.h>
namespace extra2d { namespace extra2d {
@ -9,30 +9,41 @@ namespace extra2d {
/** /**
* @brief OpenGL * @brief OpenGL
*/ */
#define GL_CHECK(call) do { \ #define GL_CHECK(call) \
do { \
call; \ call; \
GLenum err = glGetError(); \ GLenum err = glGetError(); \
if (err != GL_NO_ERROR) { \ if (err != GL_NO_ERROR) { \
E2D_LOG_ERROR("OpenGL 错误在 {}: {} ({})", #call, getGLErrorString(err), err); \ E2D_ERROR("OpenGL 错误在 {}: {} ({})", #call, getGLErrorString(err), \
err); \
} \ } \
} while(0) } while (0)
/** /**
* @brief OpenGL * @brief OpenGL
* @param error OpenGL * @param error OpenGL
* @return * @return
*/ */
inline const char* getGLErrorString(GLenum error) { inline const char *getGLErrorString(GLenum error) {
switch (error) { switch (error) {
case GL_NO_ERROR: return "GL_NO_ERROR"; case GL_NO_ERROR:
case GL_INVALID_ENUM: return "GL_INVALID_ENUM"; return "GL_NO_ERROR";
case GL_INVALID_VALUE: return "GL_INVALID_VALUE"; case GL_INVALID_ENUM:
case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION"; return "GL_INVALID_ENUM";
case GL_STACK_OVERFLOW: return "GL_STACK_OVERFLOW"; case GL_INVALID_VALUE:
case GL_STACK_UNDERFLOW: return "GL_STACK_UNDERFLOW"; return "GL_INVALID_VALUE";
case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY"; case GL_INVALID_OPERATION:
case GL_INVALID_FRAMEBUFFER_OPERATION: return "GL_INVALID_FRAMEBUFFER_OPERATION"; return "GL_INVALID_OPERATION";
default: return "Unknown Error"; 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";
} }
} }
@ -41,12 +52,18 @@ inline const char* getGLErrorString(GLenum error) {
*/ */
inline GLenum bufferTypeToGL(BufferType type) { inline GLenum bufferTypeToGL(BufferType type) {
switch (type) { switch (type) {
case BufferType::Vertex: return GL_ARRAY_BUFFER; case BufferType::Vertex:
case BufferType::Index: return GL_ELEMENT_ARRAY_BUFFER; return GL_ARRAY_BUFFER;
case BufferType::Uniform: return GL_UNIFORM_BUFFER; case BufferType::Index:
case BufferType::Storage: return GL_SHADER_STORAGE_BUFFER; return GL_ELEMENT_ARRAY_BUFFER;
case BufferType::Staging: return GL_ARRAY_BUFFER; case BufferType::Uniform:
default: return GL_ARRAY_BUFFER; return GL_UNIFORM_BUFFER;
case BufferType::Storage:
return GL_SHADER_STORAGE_BUFFER;
case BufferType::Staging:
return GL_ARRAY_BUFFER;
default:
return GL_ARRAY_BUFFER;
} }
} }
@ -55,10 +72,14 @@ inline GLenum bufferTypeToGL(BufferType type) {
*/ */
inline GLenum bufferUsageToGL(BufferUsage usage) { inline GLenum bufferUsageToGL(BufferUsage usage) {
switch (usage) { switch (usage) {
case BufferUsage::Static: return GL_STATIC_DRAW; case BufferUsage::Static:
case BufferUsage::Dynamic: return GL_DYNAMIC_DRAW; return GL_STATIC_DRAW;
case BufferUsage::Stream: return GL_STREAM_DRAW; case BufferUsage::Dynamic:
default: return GL_STATIC_DRAW; return GL_DYNAMIC_DRAW;
case BufferUsage::Stream:
return GL_STREAM_DRAW;
default:
return GL_STATIC_DRAW;
} }
} }
@ -67,20 +88,34 @@ inline GLenum bufferUsageToGL(BufferUsage usage) {
*/ */
inline GLenum textureFormatToGLInternal(TextureFormat format) { inline GLenum textureFormatToGLInternal(TextureFormat format) {
switch (format) { switch (format) {
case TextureFormat::R8: return GL_R8; case TextureFormat::R8:
case TextureFormat::RG8: return GL_RG8; return GL_R8;
case TextureFormat::RGB8: return GL_RGB8; case TextureFormat::RG8:
case TextureFormat::RGBA8: return GL_RGBA8; return GL_RG8;
case TextureFormat::RGBA8_SRGB: return GL_SRGB8_ALPHA8; case TextureFormat::RGB8:
case TextureFormat::Depth16: return GL_DEPTH_COMPONENT16; return GL_RGB8;
case TextureFormat::Depth24: return GL_DEPTH_COMPONENT24; case TextureFormat::RGBA8:
case TextureFormat::Depth32F: return GL_DEPTH_COMPONENT32F; return GL_RGBA8;
case TextureFormat::Depth24Stencil8: return GL_DEPTH24_STENCIL8; case TextureFormat::RGBA8_SRGB:
case TextureFormat::Depth32FStencil8:return GL_DEPTH32F_STENCIL8; return GL_SRGB8_ALPHA8;
case TextureFormat::BC1: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; case TextureFormat::Depth16:
case TextureFormat::BC3: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; return GL_DEPTH_COMPONENT16;
case TextureFormat::BC5: return 0x8DBD; // GL_COMPRESSED_RG_RGTC2 case TextureFormat::Depth24:
default: return GL_RGBA8; 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;
} }
} }
@ -89,17 +124,24 @@ inline GLenum textureFormatToGLInternal(TextureFormat format) {
*/ */
inline GLenum textureFormatToGLFormat(TextureFormat format) { inline GLenum textureFormatToGLFormat(TextureFormat format) {
switch (format) { switch (format) {
case TextureFormat::R8: return GL_RED; case TextureFormat::R8:
case TextureFormat::RG8: return GL_RG; return GL_RED;
case TextureFormat::RGB8: return GL_RGB; case TextureFormat::RG8:
return GL_RG;
case TextureFormat::RGB8:
return GL_RGB;
case TextureFormat::RGBA8: case TextureFormat::RGBA8:
case TextureFormat::RGBA8_SRGB: return GL_RGBA; case TextureFormat::RGBA8_SRGB:
return GL_RGBA;
case TextureFormat::Depth16: case TextureFormat::Depth16:
case TextureFormat::Depth24: case TextureFormat::Depth24:
case TextureFormat::Depth32F: return GL_DEPTH_COMPONENT; case TextureFormat::Depth32F:
return GL_DEPTH_COMPONENT;
case TextureFormat::Depth24Stencil8: case TextureFormat::Depth24Stencil8:
case TextureFormat::Depth32FStencil8:return GL_DEPTH_STENCIL; case TextureFormat::Depth32FStencil8:
default: return GL_RGBA; return GL_DEPTH_STENCIL;
default:
return GL_RGBA;
} }
} }
@ -112,13 +154,20 @@ inline GLenum textureFormatToGLType(TextureFormat format) {
case TextureFormat::RG8: case TextureFormat::RG8:
case TextureFormat::RGB8: case TextureFormat::RGB8:
case TextureFormat::RGBA8: case TextureFormat::RGBA8:
case TextureFormat::RGBA8_SRGB: return GL_UNSIGNED_BYTE; case TextureFormat::RGBA8_SRGB:
case TextureFormat::Depth16: return GL_UNSIGNED_SHORT; return GL_UNSIGNED_BYTE;
case TextureFormat::Depth24: return GL_UNSIGNED_INT; case TextureFormat::Depth16:
case TextureFormat::Depth32F: return GL_FLOAT; return GL_UNSIGNED_SHORT;
case TextureFormat::Depth24Stencil8: return GL_UNSIGNED_INT_24_8; case TextureFormat::Depth24:
case TextureFormat::Depth32FStencil8:return GL_FLOAT_32_UNSIGNED_INT_24_8_REV; return GL_UNSIGNED_INT;
default: return GL_UNSIGNED_BYTE; 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;
} }
} }
@ -127,13 +176,20 @@ inline GLenum textureFormatToGLType(TextureFormat format) {
*/ */
inline GLenum textureFilterToGLMin(TextureFilter filter) { inline GLenum textureFilterToGLMin(TextureFilter filter) {
switch (filter) { switch (filter) {
case TextureFilter::Nearest: return GL_NEAREST; case TextureFilter::Nearest:
case TextureFilter::Linear: return GL_LINEAR; return GL_NEAREST;
case TextureFilter::NearestMipmapNearest: return GL_NEAREST_MIPMAP_NEAREST; case TextureFilter::Linear:
case TextureFilter::LinearMipmapNearest: return GL_LINEAR_MIPMAP_NEAREST; return GL_LINEAR;
case TextureFilter::NearestMipmapLinear: return GL_NEAREST_MIPMAP_LINEAR; case TextureFilter::NearestMipmapNearest:
case TextureFilter::LinearMipmapLinear: return GL_LINEAR_MIPMAP_LINEAR; return GL_NEAREST_MIPMAP_NEAREST;
default: return GL_LINEAR; 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;
} }
} }
@ -157,36 +213,110 @@ inline GLenum textureFilterToGLMag(TextureFilter filter) {
*/ */
inline GLenum textureWrapToGL(TextureWrap wrap) { inline GLenum textureWrapToGL(TextureWrap wrap) {
switch (wrap) { switch (wrap) {
case TextureWrap::Repeat: return GL_REPEAT; case TextureWrap::Repeat:
case TextureWrap::ClampToEdge: return GL_CLAMP_TO_EDGE; return GL_REPEAT;
case TextureWrap::ClampToBorder: return GL_CLAMP_TO_BORDER; case TextureWrap::ClampToEdge:
case TextureWrap::MirroredRepeat: return GL_MIRRORED_REPEAT; return GL_CLAMP_TO_EDGE;
default: return GL_REPEAT; case TextureWrap::ClampToBorder:
return GL_CLAMP_TO_BORDER;
case TextureWrap::MirroredRepeat:
return GL_MIRRORED_REPEAT;
default:
return GL_REPEAT;
} }
} }
/** /**
* @brief VertexFormat OpenGL * @brief VertexFormat OpenGL
*/ */
inline void vertexFormatToGL(VertexFormat format, GLint& components, GLenum& type, GLboolean& normalized) { inline void vertexFormatToGL(VertexFormat format, GLint &components,
GLenum &type, GLboolean &normalized) {
switch (format) { switch (format) {
case VertexFormat::Float1: components = 1; type = GL_FLOAT; normalized = GL_FALSE; break; case VertexFormat::Float1:
case VertexFormat::Float2: components = 2; type = GL_FLOAT; normalized = GL_FALSE; break; components = 1;
case VertexFormat::Float3: components = 3; type = GL_FLOAT; normalized = GL_FALSE; break; type = GL_FLOAT;
case VertexFormat::Float4: components = 4; type = GL_FLOAT; normalized = GL_FALSE; break; normalized = GL_FALSE;
case VertexFormat::Int1: components = 1; type = GL_INT; normalized = GL_FALSE; break; break;
case VertexFormat::Int2: components = 2; type = GL_INT; normalized = GL_FALSE; break; case VertexFormat::Float2:
case VertexFormat::Int3: components = 3; type = GL_INT; normalized = GL_FALSE; break; components = 2;
case VertexFormat::Int4: components = 4; type = GL_INT; normalized = GL_FALSE; break; type = GL_FLOAT;
case VertexFormat::UInt1: components = 1; type = GL_UNSIGNED_INT; normalized = GL_FALSE; break; normalized = GL_FALSE;
case VertexFormat::UInt2: components = 2; type = GL_UNSIGNED_INT; normalized = GL_FALSE; break; break;
case VertexFormat::UInt3: components = 3; type = GL_UNSIGNED_INT; normalized = GL_FALSE; break; case VertexFormat::Float3:
case VertexFormat::UInt4: components = 4; type = GL_UNSIGNED_INT; normalized = GL_FALSE; break; components = 3;
case VertexFormat::Byte4: components = 4; type = GL_BYTE; normalized = GL_FALSE; break; type = GL_FLOAT;
case VertexFormat::Byte4Normalized: components = 4; type = GL_BYTE; normalized = GL_TRUE; break; normalized = GL_FALSE;
case VertexFormat::UByte4: components = 4; type = GL_UNSIGNED_BYTE; normalized = GL_FALSE; break; break;
case VertexFormat::UByte4Normalized:components = 4; type = GL_UNSIGNED_BYTE; normalized = GL_TRUE; break; case VertexFormat::Float4:
default: components = 4; type = GL_FLOAT; normalized = GL_FALSE; break; 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;
} }
} }
@ -195,9 +325,12 @@ inline void vertexFormatToGL(VertexFormat format, GLint& components, GLenum& typ
*/ */
inline GLenum indexTypeToGL(IndexType type) { inline GLenum indexTypeToGL(IndexType type) {
switch (type) { switch (type) {
case IndexType::UInt16: return GL_UNSIGNED_SHORT; case IndexType::UInt16:
case IndexType::UInt32: return GL_UNSIGNED_INT; return GL_UNSIGNED_SHORT;
default: return GL_UNSIGNED_SHORT; case IndexType::UInt32:
return GL_UNSIGNED_INT;
default:
return GL_UNSIGNED_SHORT;
} }
} }
@ -206,13 +339,20 @@ inline GLenum indexTypeToGL(IndexType type) {
*/ */
inline GLenum primitiveTypeToGL(PrimitiveType type) { inline GLenum primitiveTypeToGL(PrimitiveType type) {
switch (type) { switch (type) {
case PrimitiveType::Points: return GL_POINTS; case PrimitiveType::Points:
case PrimitiveType::Lines: return GL_LINES; return GL_POINTS;
case PrimitiveType::LineStrip: return GL_LINE_STRIP; case PrimitiveType::Lines:
case PrimitiveType::Triangles: return GL_TRIANGLES; return GL_LINES;
case PrimitiveType::TriangleStrip: return GL_TRIANGLE_STRIP; case PrimitiveType::LineStrip:
case PrimitiveType::TriangleFan: return GL_TRIANGLE_FAN; return GL_LINE_STRIP;
default: return GL_TRIANGLES; case PrimitiveType::Triangles:
return GL_TRIANGLES;
case PrimitiveType::TriangleStrip:
return GL_TRIANGLE_STRIP;
case PrimitiveType::TriangleFan:
return GL_TRIANGLE_FAN;
default:
return GL_TRIANGLES;
} }
} }
@ -221,17 +361,28 @@ inline GLenum primitiveTypeToGL(PrimitiveType type) {
*/ */
inline GLenum blendFactorToGL(BlendFactor factor) { inline GLenum blendFactorToGL(BlendFactor factor) {
switch (factor) { switch (factor) {
case BlendFactor::Zero: return GL_ZERO; case BlendFactor::Zero:
case BlendFactor::One: return GL_ONE; return GL_ZERO;
case BlendFactor::SrcColor: return GL_SRC_COLOR; case BlendFactor::One:
case BlendFactor::OneMinusSrcColor: return GL_ONE_MINUS_SRC_COLOR; return GL_ONE;
case BlendFactor::DstColor: return GL_DST_COLOR; case BlendFactor::SrcColor:
case BlendFactor::OneMinusDstColor: return GL_ONE_MINUS_DST_COLOR; return GL_SRC_COLOR;
case BlendFactor::SrcAlpha: return GL_SRC_ALPHA; case BlendFactor::OneMinusSrcColor:
case BlendFactor::OneMinusSrcAlpha: return GL_ONE_MINUS_SRC_ALPHA; return GL_ONE_MINUS_SRC_COLOR;
case BlendFactor::DstAlpha: return GL_DST_ALPHA; case BlendFactor::DstColor:
case BlendFactor::OneMinusDstAlpha: return GL_ONE_MINUS_DST_ALPHA; return GL_DST_COLOR;
default: return GL_ONE; 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;
} }
} }
@ -240,12 +391,18 @@ inline GLenum blendFactorToGL(BlendFactor factor) {
*/ */
inline GLenum blendOpToGL(BlendOp op) { inline GLenum blendOpToGL(BlendOp op) {
switch (op) { switch (op) {
case BlendOp::Add: return GL_FUNC_ADD; case BlendOp::Add:
case BlendOp::Subtract: return GL_FUNC_SUBTRACT; return GL_FUNC_ADD;
case BlendOp::ReverseSubtract: return GL_FUNC_REVERSE_SUBTRACT; case BlendOp::Subtract:
case BlendOp::Min: return GL_MIN; return GL_FUNC_SUBTRACT;
case BlendOp::Max: return GL_MAX; case BlendOp::ReverseSubtract:
default: return GL_FUNC_ADD; return GL_FUNC_REVERSE_SUBTRACT;
case BlendOp::Min:
return GL_MIN;
case BlendOp::Max:
return GL_MAX;
default:
return GL_FUNC_ADD;
} }
} }
@ -254,15 +411,24 @@ inline GLenum blendOpToGL(BlendOp op) {
*/ */
inline GLenum compareFuncToGL(CompareFunc func) { inline GLenum compareFuncToGL(CompareFunc func) {
switch (func) { switch (func) {
case CompareFunc::Never: return GL_NEVER; case CompareFunc::Never:
case CompareFunc::Less: return GL_LESS; return GL_NEVER;
case CompareFunc::Equal: return GL_EQUAL; case CompareFunc::Less:
case CompareFunc::LessEqual: return GL_LEQUAL; return GL_LESS;
case CompareFunc::Greater: return GL_GREATER; case CompareFunc::Equal:
case CompareFunc::NotEqual: return GL_NOTEQUAL; return GL_EQUAL;
case CompareFunc::GreaterEqual: return GL_GEQUAL; case CompareFunc::LessEqual:
case CompareFunc::Always: return GL_ALWAYS; return GL_LEQUAL;
default: return GL_LESS; 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;
} }
} }
@ -271,11 +437,16 @@ inline GLenum compareFuncToGL(CompareFunc func) {
*/ */
inline GLenum shaderTypeToGL(ShaderType type) { inline GLenum shaderTypeToGL(ShaderType type) {
switch (type) { switch (type) {
case ShaderType::Vertex: return GL_VERTEX_SHADER; case ShaderType::Vertex:
case ShaderType::Fragment: return GL_FRAGMENT_SHADER; return GL_VERTEX_SHADER;
case ShaderType::Geometry: return GL_GEOMETRY_SHADER; case ShaderType::Fragment:
case ShaderType::Compute: return GL_COMPUTE_SHADER; return GL_FRAGMENT_SHADER;
default: return GL_VERTEX_SHADER; case ShaderType::Geometry:
return GL_GEOMETRY_SHADER;
case ShaderType::Compute:
return GL_COMPUTE_SHADER;
default:
return GL_VERTEX_SHADER;
} }
} }
@ -284,23 +455,38 @@ inline GLenum shaderTypeToGL(ShaderType type) {
*/ */
inline uint32_t getVertexFormatSize(VertexFormat format) { inline uint32_t getVertexFormatSize(VertexFormat format) {
switch (format) { switch (format) {
case VertexFormat::Float1: return sizeof(float) * 1; case VertexFormat::Float1:
case VertexFormat::Float2: return sizeof(float) * 2; return sizeof(float) * 1;
case VertexFormat::Float3: return sizeof(float) * 3; case VertexFormat::Float2:
case VertexFormat::Float4: return sizeof(float) * 4; return sizeof(float) * 2;
case VertexFormat::Int1: return sizeof(int32_t) * 1; case VertexFormat::Float3:
case VertexFormat::Int2: return sizeof(int32_t) * 2; return sizeof(float) * 3;
case VertexFormat::Int3: return sizeof(int32_t) * 3; case VertexFormat::Float4:
case VertexFormat::Int4: return sizeof(int32_t) * 4; return sizeof(float) * 4;
case VertexFormat::UInt1: return sizeof(uint32_t) * 1; case VertexFormat::Int1:
case VertexFormat::UInt2: return sizeof(uint32_t) * 2; return sizeof(int32_t) * 1;
case VertexFormat::UInt3: return sizeof(uint32_t) * 3; case VertexFormat::Int2:
case VertexFormat::UInt4: return sizeof(uint32_t) * 4; 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::Byte4:
case VertexFormat::Byte4Normalized: return sizeof(int8_t) * 4; case VertexFormat::Byte4Normalized:
return sizeof(int8_t) * 4;
case VertexFormat::UByte4: case VertexFormat::UByte4:
case VertexFormat::UByte4Normalized: return sizeof(uint8_t) * 4; case VertexFormat::UByte4Normalized:
default: return sizeof(float) * 4; return sizeof(uint8_t) * 4;
default:
return sizeof(float) * 4;
} }
} }

View File

@ -1,172 +1,37 @@
#pragma once #pragma once
#include <cstdio> #include <memory>
#include <sstream>
#include <string> #include <string>
#include <type_traits> #include <utility>
#include <types/base/types.h>
#include <spdlog/fmt/fmt.h>
#include <spdlog/spdlog.h>
// Switch 平台支持
#ifdef __SWITCH__ #ifdef __SWITCH__
#include <switch.h> #include <switch.h>
#endif
#ifndef TEST_BUILD
// SDL2 日志头文件(测试构建时不使用)
#include <SDL.h>
#endif #endif
namespace extra2d { namespace extra2d {
// ============================================================================ /**
// 日志级别枚举 * @brief
// ============================================================================ */
enum class LogLevel { enum class LogLevel {
#ifdef TEST_BUILD Trace = spdlog::level::trace,
Trace = 0, Debug = spdlog::level::debug,
Debug = 1, Info = spdlog::level::info,
Info = 2, Warn = spdlog::level::warn,
Warn = 3, Error = spdlog::level::err,
Error = 4, Fatal = spdlog::level::critical,
Fatal = 5, Off = spdlog::level::off
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
}; };
// ============================================================================ /**
// 简单的 fmt-style {} 格式化器 * @brief
// ============================================================================ *
namespace detail { *
* setLevel()
// 将单个参数转为字符串 */
template <typename T> inline std::string to_string_arg(const T &value) {
if constexpr (std::is_same_v<T, std::string>) {
return value;
} else if constexpr (std::is_same_v<T, const char *> ||
std::is_same_v<T, char *>) {
return value ? std::string(value) : std::string("(null)");
} else if constexpr (std::is_same_v<T, bool>) {
return value ? "true" : "false";
} else if constexpr (std::is_arithmetic_v<T>) {
// 对浮点数使用特殊格式
if constexpr (std::is_floating_point_v<T>) {
char buf[64];
snprintf(buf, sizeof(buf), "%.2f", static_cast<double>(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 <typename T, typename... Args>
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<T>) {
char buf[32];
snprintf(buf, sizeof(buf), "0x%x",
static_cast<unsigned int>(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<T>) {
// 解析精度
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<double>(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 <typename... Args>
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 日志系统
// ============================================================================
class Logger { class Logger {
public: public:
/** /**
@ -186,14 +51,14 @@ public:
static void setLevel(LogLevel level); static void setLevel(LogLevel level);
/** /**
* @brief * @brief /
* @param enable * @param enable
*/ */
static void setConsoleOutput(bool enable); static void setConsoleOutput(bool enable);
/** /**
* @brief * @brief
* @param filename * @param filename
*/ */
static void setFileOutput(const std::string &filename); static void setFileOutput(const std::string &filename);
@ -201,94 +66,84 @@ public:
* @brief * @brief
* @return * @return
*/ */
static LogLevel getLevel() { return level_; } static LogLevel getLevel();
/** /**
* @brief * @brief
* @tparam Args
* @param level * @param level
* @param fmt * @param fmt
* @param args * @param args
*/ */
template <typename... Args> template <typename... Args>
static void log(LogLevel level, const char *fmt, const Args &...args) { static void log(LogLevel level, fmt::format_string<Args...> fmt,
if (static_cast<int>(level) < static_cast<int>(level_)) Args &&...args) {
if (!logger_) {
return; return;
std::string msg = e2d_format(fmt, args...); }
#ifdef TEST_BUILD auto spdLevel = static_cast<spdlog::level::level_enum>(level);
printf("[%s] %s\n", getLevelString(level), msg.c_str()); logger_->log(spdLevel, fmt, std::forward<Args>(args)...);
#else
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION,
static_cast<SDL_LogPriority>(level), "[%s] %s",
getLevelString(level), msg.c_str());
#endif
} }
/** /**
* @brief * @brief
* @param level * @param level
* @param msg * @param msg
*/ */
static void log(LogLevel level, const char *msg) { static void log(LogLevel level, const char *msg);
if (static_cast<int>(level) < static_cast<int>(level_))
return;
#ifdef TEST_BUILD
printf("[%s] %s\n", getLevelString(level), msg);
#else
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION,
static_cast<SDL_LogPriority>(level), "[%s] %s",
getLevelString(level), msg);
#endif
}
private:
static LogLevel level_; // 当前日志级别
static bool initialized_; // 是否已初始化
static bool consoleOutput_; // 是否输出到控制台
static bool fileOutput_; // 是否输出到文件
static std::string logFile_; // 日志文件路径
/** /**
* @brief * @brief spdlog
* @param level * @return spdlog
* @return
*/ */
static const char *getLevelString(LogLevel level); static std::shared_ptr<spdlog::logger> getLogger() { return logger_; }
private:
static std::shared_ptr<spdlog::logger> 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 } // 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__)

View File

@ -23,22 +23,24 @@ Application &Application::operator=(Application &&) noexcept = default;
bool Application::init(const AppConfig &config) { bool Application::init(const AppConfig &config) {
if (initialized_) { if (initialized_) {
E2D_LOG_WARN("应用程序已经初始化");
return true; return true;
} }
config_ = config; config_ = config;
// 初始化日志系统(必须在所有日志调用之前)
Logger::init();
// 创建引擎上下文 // 创建引擎上下文
context_ = Context::create(); context_ = Context::create();
if (!context_) { if (!context_) {
E2D_LOG_ERROR("创建上下文失败"); E2D_ERROR("创建上下文失败");
return false; return false;
} }
// 初始化引擎 // 初始化引擎
if (!context_->init()) { if (!context_->init()) {
E2D_LOG_ERROR("初始化上下文失败"); E2D_ERROR("初始化上下文失败");
return false; return false;
} }
@ -53,9 +55,9 @@ bool Application::init(const AppConfig &config) {
events::OnInit::emit(); events::OnInit::emit();
E2D_LOG_INFO("应用程序初始化成功"); E2D_INFO("应用程序初始化成功");
E2D_LOG_INFO("窗口: {}x{}, 全屏: {}", config.width, E2D_INFO("窗口: {}x{}, 全屏: {}", config.width, config.height,
config.height, config.fullscreen); config.fullscreen);
return true; return true;
} }
@ -71,9 +73,9 @@ void Application::initModules() {
// 初始化所有模块 // 初始化所有模块
for (auto &module : modules_) { for (auto &module : modules_) {
if (!module->init()) { if (!module->init()) {
E2D_LOG_ERROR("初始化模块失败: {}", module->getName()); E2D_ERROR("初始化模块失败: {}", module->getName());
} else { } else {
E2D_LOG_INFO("模块已初始化: {} (优先级: {})", module->getName(), E2D_INFO("模块已初始化: {} (优先级: {})", module->getName(),
module->getPriority()); module->getPriority());
} }
} }
@ -85,7 +87,7 @@ void Application::shutdown() {
events::OnShutdown::emit(); events::OnShutdown::emit();
E2D_LOG_INFO("正在关闭应用程序..."); E2D_INFO("正在关闭应用程序...");
// 按相反顺序销毁模块 // 按相反顺序销毁模块
for (auto it = modules_.rbegin(); it != modules_.rend(); ++it) { for (auto it = modules_.rbegin(); it != modules_.rend(); ++it) {
@ -99,12 +101,15 @@ void Application::shutdown() {
initialized_ = false; initialized_ = false;
running_ = false; running_ = false;
E2D_LOG_INFO("应用程序关闭完成"); E2D_INFO("应用程序关闭完成");
// 关闭日志系统(在所有日志调用之后)
Logger::shutdown();
} }
void Application::run() { void Application::run() {
if (!initialized_) { if (!initialized_) {
E2D_LOG_ERROR("应用程序未初始化"); E2D_ERROR("应用程序未初始化");
return; return;
} }
@ -159,7 +164,7 @@ void Application::pause() {
if (!paused_) { if (!paused_) {
paused_ = true; paused_ = true;
events::OnPause::emit(); events::OnPause::emit();
E2D_LOG_INFO("应用程序已暂停"); E2D_INFO("应用程序已暂停");
} }
} }
@ -167,7 +172,7 @@ void Application::resume() {
if (paused_) { if (paused_) {
paused_ = false; paused_ = false;
events::OnResume::emit(); events::OnResume::emit();
E2D_LOG_INFO("应用程序已恢复"); E2D_INFO("应用程序已恢复");
} }
} }

View File

@ -75,7 +75,7 @@ AssetsModule::~AssetsModule() {
} }
bool AssetsModule::init() { bool AssetsModule::init() {
E2D_LOG_INFO("资源模块正在初始化..."); E2D_INFO("资源模块正在初始化...");
textureLoader_ = std::make_unique<TextureLoader>(); textureLoader_ = std::make_unique<TextureLoader>();
shaderLoader_ = std::make_unique<ShaderLoader>(); shaderLoader_ = std::make_unique<ShaderLoader>();
@ -84,8 +84,7 @@ bool AssetsModule::init() {
onShowListener_ = std::make_unique<events::OnShow::Listener>(); onShowListener_ = std::make_unique<events::OnShow::Listener>();
onShowListener_->bind([this]() { this->onGLContextReady(); }); onShowListener_->bind([this]() { this->onGLContextReady(); });
E2D_LOG_INFO( E2D_INFO("资源模块初始化成功 (等待 GL 上下文)");
"资源模块初始化成功 (等待 GL 上下文)");
return true; return true;
} }
@ -94,19 +93,19 @@ void AssetsModule::onGLContextReady() {
return; return;
} }
E2D_LOG_INFO("OpenGL 上下文就绪,正在创建默认资源..."); E2D_INFO("OpenGL 上下文就绪,正在创建默认资源...");
if (!createDefaultResources()) { if (!createDefaultResources()) {
E2D_LOG_ERROR("创建默认资源失败"); E2D_ERROR("创建默认资源失败");
return; return;
} }
defaultResourcesCreated_ = true; defaultResourcesCreated_ = true;
E2D_LOG_INFO("默认资源创建成功"); E2D_INFO("默认资源创建成功");
} }
void AssetsModule::shutdown() { void AssetsModule::shutdown() {
E2D_LOG_INFO("资源模块正在关闭..."); E2D_INFO("资源模块正在关闭...");
// 关闭异步加载系统 // 关闭异步加载系统
shutdownAsyncLoader(); shutdownAsyncLoader();
@ -141,7 +140,7 @@ void AssetsModule::shutdown() {
defaultResourcesCreated_ = false; defaultResourcesCreated_ = false;
E2D_LOG_INFO("资源模块关闭完成"); E2D_INFO("资源模块关闭完成");
} }
AssetsModule *getAssets() { return g_assetsModule; } AssetsModule *getAssets() { return g_assetsModule; }
@ -164,13 +163,13 @@ Handle<Texture> AssetsModule::load<Texture>(const std::string &path) {
} }
if (!textureLoader_) { if (!textureLoader_) {
E2D_LOG_ERROR("纹理加载器未注册"); E2D_ERROR("纹理加载器未注册");
return Handle<Texture>::invalid(); return Handle<Texture>::invalid();
} }
Ptr<Texture> texture = textureLoader_->load(path); Ptr<Texture> texture = textureLoader_->load(path);
if (!texture) { if (!texture) {
E2D_LOG_ERROR("加载纹理失败: {}", path); E2D_ERROR("加载纹理失败: {}", path);
return Handle<Texture>::invalid(); return Handle<Texture>::invalid();
} }
@ -189,7 +188,7 @@ Handle<Texture> AssetsModule::load<Texture>(const std::string &path) {
texturePathCache_[path] = handle; texturePathCache_[path] = handle;
} }
E2D_LOG_DEBUG("已加载纹理: {} -> 句柄索引 {}", path, handle.index()); E2D_DEBUG("已加载纹理: {} -> 句柄索引 {}", path, handle.index());
// 如果启用了热重载,添加文件监控 // 如果启用了热重载,添加文件监控
if (hotReloadEnabled_) { if (hotReloadEnabled_) {
@ -212,13 +211,13 @@ Handle<Texture> AssetsModule::loadFromMemory<Texture>(const std::string &key,
} }
if (!textureLoader_) { if (!textureLoader_) {
E2D_LOG_ERROR("纹理加载器未注册"); E2D_ERROR("纹理加载器未注册");
return Handle<Texture>::invalid(); return Handle<Texture>::invalid();
} }
Ptr<Texture> texture = textureLoader_->loadFromMemory(data, size); Ptr<Texture> texture = textureLoader_->loadFromMemory(data, size);
if (!texture) { if (!texture) {
E2D_LOG_ERROR("从内存加载纹理失败: {}", key); E2D_ERROR("从内存加载纹理失败: {}", key);
return Handle<Texture>::invalid(); return Handle<Texture>::invalid();
} }
@ -245,13 +244,13 @@ template <> Handle<Shader> AssetsModule::load<Shader>(const std::string &path) {
} }
if (!shaderLoader_) { if (!shaderLoader_) {
E2D_LOG_ERROR("着色器加载器未注册"); E2D_ERROR("着色器加载器未注册");
return Handle<Shader>::invalid(); return Handle<Shader>::invalid();
} }
Ptr<Shader> shader = shaderLoader_->load(path); Ptr<Shader> shader = shaderLoader_->load(path);
if (!shader) { if (!shader) {
E2D_LOG_ERROR("加载着色器失败: {}", path); E2D_ERROR("加载着色器失败: {}", path);
return Handle<Shader>::invalid(); return Handle<Shader>::invalid();
} }
@ -270,7 +269,7 @@ template <> Handle<Shader> AssetsModule::load<Shader>(const std::string &path) {
shaderPathCache_[path] = handle; shaderPathCache_[path] = handle;
} }
E2D_LOG_DEBUG("已加载着色器: {} -> 句柄索引 {}", path, handle.index()); E2D_DEBUG("已加载着色器: {} -> 句柄索引 {}", path, handle.index());
// 如果启用了热重载,添加文件监控 // 如果启用了热重载,添加文件监控
if (hotReloadEnabled_) { if (hotReloadEnabled_) {
@ -297,14 +296,14 @@ Handle<Shader> AssetsModule::load<Shader>(const std::string &vertPath,
} }
if (!shaderLoader_) { if (!shaderLoader_) {
E2D_LOG_ERROR("着色器加载器未注册"); E2D_ERROR("着色器加载器未注册");
return Handle<Shader>::invalid(); return Handle<Shader>::invalid();
} }
ShaderLoader *shaderLoader = static_cast<ShaderLoader *>(shaderLoader_.get()); ShaderLoader *shaderLoader = static_cast<ShaderLoader *>(shaderLoader_.get());
Ptr<Shader> shader = shaderLoader->load(vertPath, fragPath); Ptr<Shader> shader = shaderLoader->load(vertPath, fragPath);
if (!shader) { if (!shader) {
E2D_LOG_ERROR("加载着色器失败: {} + {}", vertPath, fragPath); E2D_ERROR("加载着色器失败: {} + {}", vertPath, fragPath);
return Handle<Shader>::invalid(); return Handle<Shader>::invalid();
} }
@ -323,7 +322,7 @@ Handle<Shader> AssetsModule::load<Shader>(const std::string &vertPath,
shaderPathCache_[cacheKey] = handle; shaderPathCache_[cacheKey] = handle;
} }
E2D_LOG_DEBUG("已加载着色器: {} + {} -> 句柄索引 {}", vertPath, fragPath, E2D_DEBUG("已加载着色器: {} + {} -> 句柄索引 {}", vertPath, fragPath,
handle.index()); handle.index());
// 如果启用了热重载,添加文件监控 // 如果启用了热重载,添加文件监控
@ -348,7 +347,7 @@ AssetsModule::loadDir<Texture>(const std::string &directory,
try { try {
std::filesystem::path dirPath(directory); std::filesystem::path dirPath(directory);
if (!fileExists(directory)) { if (!fileExists(directory)) {
E2D_LOG_WARN("目录未找到: {}", directory); E2D_WARN("目录未找到: {}", directory);
return handles; return handles;
} }
@ -382,10 +381,10 @@ AssetsModule::loadDir<Texture>(const std::string &directory,
} }
} }
} catch (const std::exception &e) { } 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; return handles;
} }
@ -455,11 +454,11 @@ bool AssetsModule::createDefaultResources() {
Ptr<Texture> texture = makePtr<Texture>(); Ptr<Texture> texture = makePtr<Texture>();
uint8_t whitePixel[] = {255, 255, 255, 255}; uint8_t whitePixel[] = {255, 255, 255, 255};
if (!texture->loadFromMemory(whitePixel, 1, 1, TextureFormat::RGBA8)) { if (!texture->loadFromMemory(whitePixel, 1, 1, TextureFormat::RGBA8)) {
E2D_LOG_ERROR("创建默认纹理失败"); E2D_ERROR("创建默认纹理失败");
return false; return false;
} }
defaultTexture_ = textures_.insert(texture); defaultTexture_ = textures_.insert(texture);
E2D_LOG_DEBUG("已创建默认纹理"); E2D_DEBUG("已创建默认纹理");
} }
{ {
@ -474,8 +473,7 @@ bool AssetsModule::createDefaultResources() {
: "shader/default.frag"; : "shader/default.frag";
if (!fileExists(vertPath) || !fileExists(fragPath)) { if (!fileExists(vertPath) || !fileExists(fragPath)) {
E2D_LOG_ERROR("默认着色器文件未找到: {}, {}", vertPath, E2D_ERROR("默认着色器文件未找到: {}, {}", vertPath, fragPath);
fragPath);
return false; return false;
} }
@ -483,22 +481,19 @@ bool AssetsModule::createDefaultResources() {
std::string vsSource = readFileToString(vertPath); std::string vsSource = readFileToString(vertPath);
std::string fsSource = readFileToString(fragPath); std::string fsSource = readFileToString(fragPath);
if (vsSource.empty() || fsSource.empty()) { if (vsSource.empty() || fsSource.empty()) {
E2D_LOG_ERROR("读取默认着色器文件失败: {}, {}", vertPath, E2D_ERROR("读取默认着色器文件失败: {}, {}", vertPath, fragPath);
fragPath);
return false; return false;
} }
// 从源码加载着色器 // 从源码加载着色器
Ptr<Shader> shader = makePtr<Shader>(); Ptr<Shader> shader = makePtr<Shader>();
if (!shader->loadFromSource(vsSource, fsSource)) { if (!shader->loadFromSource(vsSource, fsSource)) {
E2D_LOG_ERROR("编译默认着色器失败: {}, {}", vertPath, E2D_ERROR("编译默认着色器失败: {}, {}", vertPath, fragPath);
fragPath);
return false; return false;
} }
defaultShader_ = shaders_.insert(shader); defaultShader_ = shaders_.insert(shader);
E2D_LOG_DEBUG("已从文件加载默认着色器: {}, {}", vertPath, E2D_DEBUG("已从文件加载默认着色器: {}, {}", vertPath, fragPath);
fragPath);
} }
{ {
@ -527,17 +522,17 @@ bool AssetsModule::createDefaultResources() {
// 添加默认纹理到材质 // 添加默认纹理到材质
material->setTexture("uTexture", getPtr(defaultTexture_), 0); material->setTexture("uTexture", getPtr(defaultTexture_), 0);
defaultMaterial_ = materials_.insert(material); defaultMaterial_ = materials_.insert(material);
E2D_LOG_DEBUG("已创建默认材质,使用默认纹理和布局"); E2D_DEBUG("已创建默认材质,使用默认纹理和布局");
} }
{ {
Ptr<Mesh> mesh = Mesh::createQuad(Vec2(1.0f, 1.0f)); Ptr<Mesh> mesh = Mesh::createQuad(Vec2(1.0f, 1.0f));
if (!mesh) { if (!mesh) {
E2D_LOG_ERROR("创建默认四边形网格失败"); E2D_ERROR("创建默认四边形网格失败");
return false; return false;
} }
defaultQuad_ = meshes_.insert(mesh); defaultQuad_ = meshes_.insert(mesh);
E2D_LOG_DEBUG("已创建默认四边形网格"); E2D_DEBUG("已创建默认四边形网格");
} }
return true; return true;
@ -584,9 +579,9 @@ Mesh *AssetsModule::getDefaultQuadPtr() { return meshes_.get(defaultQuad_); }
void AssetsModule::enableHotReload(bool enable) { void AssetsModule::enableHotReload(bool enable) {
hotReloadEnabled_ = enable; hotReloadEnabled_ = enable;
if (enable) { if (enable) {
E2D_LOG_INFO("热重载已启用"); E2D_INFO("热重载已启用");
} else { } else {
E2D_LOG_INFO("热重载已禁用"); E2D_INFO("热重载已禁用");
} }
} }
@ -594,7 +589,8 @@ void AssetsModule::setHotReloadInterval(float interval) {
hotReloadInterval_ = interval; hotReloadInterval_ = interval;
} }
void AssetsModule::addFileWatchInternal(const std::string &path, FileWatchInfo &&info) { void AssetsModule::addFileWatchInternal(const std::string &path,
FileWatchInfo &&info) {
try { try {
if (!fileExists(path)) { if (!fileExists(path)) {
return; return;
@ -606,20 +602,22 @@ void AssetsModule::addFileWatchInternal(const std::string &path, FileWatchInfo &
std::unique_lock<std::shared_mutex> lock(mutex_); std::unique_lock<std::shared_mutex> lock(mutex_);
fileWatchList_.push_back(std::move(info)); fileWatchList_.push_back(std::move(info));
const char *type = fileWatchList_.back().isTexture ? "纹理" : "着色器"; const char *type = fileWatchList_.back().isTexture ? "纹理" : "着色器";
E2D_LOG_DEBUG("正在监控 {} 文件: {}", type, path); E2D_DEBUG("正在监控 {} 文件: {}", type, path);
} catch (const std::exception &e) { } catch (const std::exception &e) {
E2D_LOG_ERROR("添加文件监控失败 {}: {}", path, e.what()); E2D_ERROR("添加文件监控失败 {}: {}", path, e.what());
} }
} }
void AssetsModule::addFileWatch(const std::string &path, Handle<Texture> handle) { void AssetsModule::addFileWatch(const std::string &path,
Handle<Texture> handle) {
FileWatchInfo info; FileWatchInfo info;
info.textureHandle = handle; info.textureHandle = handle;
info.isTexture = true; info.isTexture = true;
addFileWatchInternal(path, std::move(info)); addFileWatchInternal(path, std::move(info));
} }
void AssetsModule::addFileWatch(const std::string &path, Handle<Shader> handle) { void AssetsModule::addFileWatch(const std::string &path,
Handle<Shader> handle) {
FileWatchInfo info; FileWatchInfo info;
info.shaderHandle = handle; info.shaderHandle = handle;
info.isTexture = false; info.isTexture = false;
@ -631,22 +629,22 @@ void AssetsModule::reloadTexture(const FileWatchInfo &info) {
return; return;
} }
E2D_LOG_INFO("正在重载纹理: {}", info.path); E2D_INFO("正在重载纹理: {}", info.path);
// 获取旧纹理指针 // 获取旧纹理指针
Texture *oldTexture = textures_.get(info.textureHandle); Texture *oldTexture = textures_.get(info.textureHandle);
if (!oldTexture) { if (!oldTexture) {
E2D_LOG_ERROR("未找到要重载的旧纹理: {}", info.path); E2D_ERROR("未找到要重载的旧纹理: {}", info.path);
return; return;
} }
// 直接在原有纹理对象上重新加载 // 直接在原有纹理对象上重新加载
if (!oldTexture->reloadFromFile(info.path)) { if (!oldTexture->reloadFromFile(info.path)) {
E2D_LOG_ERROR("重载纹理失败: {}", info.path); E2D_ERROR("重载纹理失败: {}", info.path);
return; return;
} }
E2D_LOG_INFO("纹理重载成功: {}", info.path); E2D_INFO("纹理重载成功: {}", info.path);
notifyTextureReloaded(info.textureHandle); notifyTextureReloaded(info.textureHandle);
} }
@ -655,12 +653,12 @@ void AssetsModule::reloadShader(const FileWatchInfo &info) {
return; return;
} }
E2D_LOG_INFO("正在重载着色器: {}", info.path); E2D_INFO("正在重载着色器: {}", info.path);
// 获取旧着色器指针 // 获取旧着色器指针
Shader *oldShader = shaders_.get(info.shaderHandle); Shader *oldShader = shaders_.get(info.shaderHandle);
if (!oldShader) { if (!oldShader) {
E2D_LOG_ERROR("未找到要重载的旧着色器: {}", info.path); E2D_ERROR("未找到要重载的旧着色器: {}", info.path);
return; return;
} }
@ -677,7 +675,7 @@ void AssetsModule::reloadShader(const FileWatchInfo &info) {
} }
if (cacheKey.empty()) { if (cacheKey.empty()) {
E2D_LOG_WARN("未找到着色器缓存键: {}", info.path); E2D_WARN("未找到着色器缓存键: {}", info.path);
return; return;
} }
@ -685,7 +683,7 @@ void AssetsModule::reloadShader(const FileWatchInfo &info) {
size_t sepPos = cacheKey.find('|'); size_t sepPos = cacheKey.find('|');
if (sepPos == std::string::npos) { if (sepPos == std::string::npos) {
// 单文件模式 - 这里暂不支持,因为 ShaderLoader 目前只支持双文件 // 单文件模式 - 这里暂不支持,因为 ShaderLoader 目前只支持双文件
E2D_LOG_WARN("不支持单文件着色器重载: {}", info.path); E2D_WARN("不支持单文件着色器重载: {}", info.path);
} else { } else {
// 双文件模式 // 双文件模式
std::string vertPath = cacheKey.substr(0, sepPos); std::string vertPath = cacheKey.substr(0, sepPos);
@ -695,18 +693,18 @@ void AssetsModule::reloadShader(const FileWatchInfo &info) {
std::string vsSource = readFileToString(vertPath); std::string vsSource = readFileToString(vertPath);
std::string fsSource = readFileToString(fragPath); std::string fsSource = readFileToString(fragPath);
if (vsSource.empty() || fsSource.empty()) { if (vsSource.empty() || fsSource.empty()) {
E2D_LOG_ERROR("读取着色器文件失败: {}, {}", vertPath, fragPath); E2D_ERROR("读取着色器文件失败: {}, {}", vertPath, fragPath);
return; return;
} }
// 直接在原有着色器对象上重新加载 // 直接在原有着色器对象上重新加载
if (!oldShader->reloadFromSource(vsSource, fsSource)) { if (!oldShader->reloadFromSource(vsSource, fsSource)) {
E2D_LOG_ERROR("重载着色器失败: {} + {}", vertPath, fragPath); E2D_ERROR("重载着色器失败: {} + {}", vertPath, fragPath);
return; return;
} }
} }
E2D_LOG_INFO("着色器重载成功: {}", info.path); E2D_INFO("着色器重载成功: {}", info.path);
notifyShaderReloaded(info.shaderHandle); notifyShaderReloaded(info.shaderHandle);
} }
@ -744,7 +742,7 @@ void AssetsModule::checkForChanges() {
lock.lock(); lock.lock();
} }
} catch (const std::exception &e) { } 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); workerThreads_.emplace_back(&AssetsModule::workerThreadLoop, this);
} }
E2D_LOG_INFO("异步加载器已初始化,使用 {} 个线程", threadCount); E2D_INFO("异步加载器已初始化,使用 {} 个线程", threadCount);
} }
void AssetsModule::shutdownAsyncLoader() { void AssetsModule::shutdownAsyncLoader() {
@ -790,7 +788,7 @@ void AssetsModule::shutdownAsyncLoader() {
std::lock_guard<std::mutex> lock(queueMutex_); std::lock_guard<std::mutex> lock(queueMutex_);
loadQueue_.clear(); loadQueue_.clear();
E2D_LOG_INFO("异步加载器已关闭"); E2D_INFO("异步加载器已关闭");
} }
void AssetsModule::submitLoadTask(const LoadTask &task) { void AssetsModule::submitLoadTask(const LoadTask &task) {
@ -890,8 +888,7 @@ void AssetsModule::registerMaterialDependency(Handle<Material> material,
info.dependentMaterials.end(), material); info.dependentMaterials.end(), material);
if (it == info.dependentMaterials.end()) { if (it == info.dependentMaterials.end()) {
info.dependentMaterials.push_back(material); info.dependentMaterials.push_back(material);
E2D_LOG_DEBUG("已注册材质 {} 对纹理 {} 的依赖", E2D_DEBUG("已注册材质 {} 对纹理 {} 的依赖", material.index(), textureIndex);
material.index(), textureIndex);
} }
} }
@ -912,8 +909,8 @@ void AssetsModule::registerMaterialDependency(Handle<Material> material,
info.dependentMaterials.end(), material); info.dependentMaterials.end(), material);
if (it == info.dependentMaterials.end()) { if (it == info.dependentMaterials.end()) {
info.dependentMaterials.push_back(material); info.dependentMaterials.push_back(material);
E2D_LOG_DEBUG("已注册材质 {} 对着色器 {} 的依赖", E2D_DEBUG("已注册材质 {} 对着色器 {} 的依赖", material.index(),
material.index(), shaderIndex); shaderIndex);
} }
} }
@ -927,8 +924,7 @@ void AssetsModule::notifyTextureReloaded(Handle<Texture> texture) {
uint32_t textureIndex = texture.index(); uint32_t textureIndex = texture.index();
auto it = textureDependencies_.find(textureIndex); auto it = textureDependencies_.find(textureIndex);
if (it != textureDependencies_.end()) { if (it != textureDependencies_.end()) {
E2D_LOG_INFO("通知 {} 个材质纹理已重载", E2D_INFO("通知 {} 个材质纹理已重载", it->second.dependentMaterials.size());
it->second.dependentMaterials.size());
// 材质需要更新纹理引用 // 材质需要更新纹理引用
// 这里可以触发材质更新事件 // 这里可以触发材质更新事件
@ -936,8 +932,7 @@ void AssetsModule::notifyTextureReloaded(Handle<Texture> texture) {
Material *material = materials_.get(materialHandle); Material *material = materials_.get(materialHandle);
if (material) { if (material) {
// 材质自动使用新的纹理数据 // 材质自动使用新的纹理数据
E2D_LOG_DEBUG("材质 {} 已更新为重载后的纹理", E2D_DEBUG("材质 {} 已更新为重载后的纹理", materialHandle.index());
materialHandle.index());
} }
} }
} }
@ -953,7 +948,7 @@ void AssetsModule::notifyShaderReloaded(Handle<Shader> shader) {
uint32_t shaderIndex = shader.index(); uint32_t shaderIndex = shader.index();
auto it = shaderDependencies_.find(shaderIndex); auto it = shaderDependencies_.find(shaderIndex);
if (it != shaderDependencies_.end()) { if (it != shaderDependencies_.end()) {
E2D_LOG_INFO("通知 {} 个材质着色器已重载", E2D_INFO("通知 {} 个材质着色器已重载",
it->second.dependentMaterials.size()); it->second.dependentMaterials.size());
for (const auto &materialHandle : it->second.dependentMaterials) { for (const auto &materialHandle : it->second.dependentMaterials) {
@ -961,8 +956,7 @@ void AssetsModule::notifyShaderReloaded(Handle<Shader> shader) {
if (material) { if (material) {
// 更新材质的着色器引用 // 更新材质的着色器引用
material->setShader(getPtr(shader)); material->setShader(getPtr(shader));
E2D_LOG_DEBUG("材质 {} 已更新为重载后的着色器", E2D_DEBUG("材质 {} 已更新为重载后的着色器", materialHandle.index());
materialHandle.index());
} }
} }
} }

View File

@ -11,9 +11,7 @@ namespace {
/** /**
* @brief FileModule * @brief FileModule
*/ */
FileModule *getFileModule() { FileModule *getFileModule() { return getModule<FileModule>(); }
return getModule<FileModule>();
}
/** /**
* @brief 使 FileModule * @brief 使 FileModule
@ -65,31 +63,30 @@ Ptr<Shader> ShaderLoader::load(const std::string &vertPath,
// 读取顶点着色器文件 // 读取顶点着色器文件
std::string vsSource = readFileToString(vertPath); std::string vsSource = readFileToString(vertPath);
if (vsSource.empty()) { if (vsSource.empty()) {
E2D_LOG_ERROR("ShaderLoader: 读取顶点着色器失败: {}", vertPath); E2D_ERROR("ShaderLoader: 读取顶点着色器失败: {}", vertPath);
return Ptr<Shader>(); return Ptr<Shader>();
} }
// 读取片段着色器文件 // 读取片段着色器文件
std::string fsSource = readFileToString(fragPath); std::string fsSource = readFileToString(fragPath);
if (fsSource.empty()) { if (fsSource.empty()) {
E2D_LOG_ERROR("ShaderLoader: 读取片段着色器失败: {}", fragPath); E2D_ERROR("ShaderLoader: 读取片段着色器失败: {}", fragPath);
return Ptr<Shader>(); return Ptr<Shader>();
} }
// 从源码加载着色器 // 从源码加载着色器
Ptr<Shader> shader = makePtr<Shader>(); Ptr<Shader> shader = makePtr<Shader>();
if (!shader->loadFromSource(vsSource, fsSource)) { if (!shader->loadFromSource(vsSource, fsSource)) {
E2D_LOG_ERROR("ShaderLoader: 编译着色器失败 {} + {}", vertPath, E2D_ERROR("ShaderLoader: 编译着色器失败 {} + {}", vertPath, fragPath);
fragPath);
return Ptr<Shader>(); return Ptr<Shader>();
} }
E2D_LOG_DEBUG("ShaderLoader: 已加载着色器 {} + {}", vertPath, fragPath); E2D_DEBUG("ShaderLoader: 已加载着色器 {} + {}", vertPath, fragPath);
return shader; return shader;
} }
Ptr<Shader> ShaderLoader::loadFromMemory(const uint8_t *data, size_t size) { Ptr<Shader> ShaderLoader::loadFromMemory(const uint8_t *data, size_t size) {
E2D_LOG_ERROR("ShaderLoader: loadFromMemory 不支持着色器"); E2D_ERROR("ShaderLoader: loadFromMemory 不支持着色器");
return Ptr<Shader>(); return Ptr<Shader>();
} }
@ -98,11 +95,11 @@ Ptr<Shader> ShaderLoader::loadFromSource(const std::string &vsSource,
Ptr<Shader> shader = makePtr<Shader>(); Ptr<Shader> shader = makePtr<Shader>();
if (!shader->loadFromSource(vsSource, fsSource)) { if (!shader->loadFromSource(vsSource, fsSource)) {
E2D_LOG_ERROR("ShaderLoader: 从源码编译着色器失败"); E2D_ERROR("ShaderLoader: 从源码编译着色器失败");
return Ptr<Shader>(); return Ptr<Shader>();
} }
E2D_LOG_DEBUG("ShaderLoader: 已从源码编译着色器"); E2D_DEBUG("ShaderLoader: 已从源码编译着色器");
return shader; return shader;
} }

View File

@ -10,11 +10,11 @@ Ptr<Texture> TextureLoader::load(const std::string &path) {
Ptr<Texture> texture = makePtr<Texture>(); Ptr<Texture> texture = makePtr<Texture>();
if (!texture->loadFromFile(path)) { if (!texture->loadFromFile(path)) {
E2D_LOG_ERROR("TextureLoader: 从 {} 加载纹理失败", path); E2D_ERROR("TextureLoader: 从 {} 加载纹理失败", path);
return Ptr<Texture>(); return Ptr<Texture>();
} }
E2D_LOG_DEBUG("TextureLoader: 已加载纹理 {}", path); E2D_DEBUG("TextureLoader: 已加载纹理 {}", path);
return texture; return texture;
} }
@ -26,7 +26,7 @@ Ptr<Texture> TextureLoader::loadFromMemory(const uint8_t *data, size_t size) {
&width, &height, &channels, 0); &width, &height, &channels, 0);
if (!imageData) { if (!imageData) {
E2D_LOG_ERROR("TextureLoader: 从内存解码图像失败"); E2D_ERROR("TextureLoader: 从内存解码图像失败");
return Ptr<Texture>(); return Ptr<Texture>();
} }
@ -54,12 +54,11 @@ Ptr<Texture> TextureLoader::loadFromMemory(const uint8_t *data, size_t size) {
stbi_image_free(imageData); stbi_image_free(imageData);
if (!success) { if (!success) {
E2D_LOG_ERROR("TextureLoader: 从内存创建纹理失败"); E2D_ERROR("TextureLoader: 从内存创建纹理失败");
return Ptr<Texture>(); return Ptr<Texture>();
} }
E2D_LOG_DEBUG("TextureLoader: 已从内存创建纹理 ({}x{})", width, E2D_DEBUG("TextureLoader: 已从内存创建纹理 ({}x{})", width, height);
height);
return texture; return texture;
} }

View File

@ -30,11 +30,11 @@ bool FileModule::init() {
// 初始化 Switch 的 RomFS // 初始化 Switch 的 RomFS
Result rc = romfsInit(); Result rc = romfsInit();
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
E2D_LOG_INFO("RomFS 初始化成功"); E2D_INFO("RomFS 初始化成功");
// 在 Switch 上设置资源根目录为 RomFS // 在 Switch 上设置资源根目录为 RomFS
assetRoot_ = "romfs:/"; assetRoot_ = "romfs:/";
} else { } else {
E2D_LOG_WARN("RomFS 初始化失败: {:#08X}", rc); E2D_WARN("RomFS 初始化失败: {:#08X}", rc);
// RomFS 初始化失败,使用当前目录 // RomFS 初始化失败,使用当前目录
assetRoot_ = "./"; assetRoot_ = "./";
} }
@ -43,7 +43,7 @@ bool FileModule::init() {
assetRoot_ = "./"; assetRoot_ = "./";
#endif #endif
E2D_LOG_INFO("资源根目录设置为: {}", assetRoot_); E2D_INFO("资源根目录设置为: {}", assetRoot_);
return true; return true;
} }
@ -102,7 +102,7 @@ bool FileModule::write(const std::string &path, const void *data,
size_t size) const { size_t size) const {
// RomFS 是只读的,不允许写入 // RomFS 是只读的,不允许写入
if (isRomfsPath(path)) { if (isRomfsPath(path)) {
E2D_LOG_WARN("无法写入 RomFS 路径: {}", path); E2D_WARN("无法写入 RomFS 路径: {}", path);
return false; return false;
} }
@ -124,7 +124,7 @@ bool FileModule::append(const std::string &path, const void *data,
size_t size) const { size_t size) const {
// RomFS 是只读的,不允许写入 // RomFS 是只读的,不允许写入
if (isRomfsPath(path)) { if (isRomfsPath(path)) {
E2D_LOG_WARN("无法追加到 RomFS 路径: {}", path); E2D_WARN("无法追加到 RomFS 路径: {}", path);
return false; return false;
} }
@ -140,7 +140,7 @@ bool FileModule::append(const std::string &path, const void *data,
bool FileModule::remove(const std::string &path) const { bool FileModule::remove(const std::string &path) const {
// RomFS 是只读的,不允许删除 // RomFS 是只读的,不允许删除
if (isRomfsPath(path)) { if (isRomfsPath(path)) {
E2D_LOG_WARN("无法删除 RomFS 路径: {}", path); E2D_WARN("无法删除 RomFS 路径: {}", path);
return false; return false;
} }
return fs::remove(path); return fs::remove(path);
@ -149,7 +149,7 @@ bool FileModule::remove(const std::string &path) const {
bool FileModule::mkdir(const std::string &path) const { bool FileModule::mkdir(const std::string &path) const {
// RomFS 是只读的,不允许创建目录 // RomFS 是只读的,不允许创建目录
if (isRomfsPath(path)) { if (isRomfsPath(path)) {
E2D_LOG_WARN("无法在 RomFS 中创建目录: {}", path); E2D_WARN("无法在 RomFS 中创建目录: {}", path);
return false; return false;
} }

View File

@ -12,7 +12,7 @@ WindowModule::~WindowModule() { shutdown(); }
bool WindowModule::init() { bool WindowModule::init() {
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) { if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
E2D_LOG_ERROR("初始化 SDL 视频子系统失败: {}", SDL_GetError()); E2D_ERROR("初始化 SDL 视频子系统失败: {}", SDL_GetError());
return false; return false;
} }
@ -58,11 +58,11 @@ bool WindowModule::create(const WindowCfg &cfg) {
SDL_WINDOWPOS_CENTERED, cfg.width, cfg.height, flags); SDL_WINDOWPOS_CENTERED, cfg.width, cfg.height, flags);
if (!window_) { if (!window_) {
E2D_LOG_ERROR("创建窗口失败: {}", SDL_GetError()); E2D_ERROR("创建窗口失败: {}", SDL_GetError());
return false; return false;
} }
E2D_LOG_INFO("窗口已创建: {}x{}", cfg.width, cfg.height); E2D_INFO("窗口已创建: {}x{}", cfg.width, cfg.height);
return true; return true;
} }
@ -71,7 +71,7 @@ bool WindowModule::pollEvents() {
while (SDL_PollEvent(&evt)) { while (SDL_PollEvent(&evt)) {
switch (evt.type) { switch (evt.type) {
case SDL_QUIT: case SDL_QUIT:
E2D_LOG_INFO("收到 SDL_QUIT 事件"); E2D_INFO("收到 SDL_QUIT 事件");
shouldClose_ = true; shouldClose_ = true;
// 发送窗口关闭事件 // 发送窗口关闭事件
events::OnClose::emit(); events::OnClose::emit();
@ -139,10 +139,8 @@ void WindowModule::onModuleConfig(const AppConfig &config) {
cfg.resizable = config.resizable; cfg.resizable = config.resizable;
if (create(cfg)) { if (create(cfg)) {
// 发送窗口显示事件 // 先显示窗口setVisible 会触发 OnShow 事件
// RHI 模块会监听此事件并创建 OpenGL 上下文 // RHI 模块会监听此事件并创建 OpenGL 上下文
events::OnShow::emit();
setVisible(true); setVisible(true);
} }
} }
@ -193,12 +191,10 @@ void WindowModule::setVisible(bool visible) {
if (window_) { if (window_) {
if (visible) { if (visible) {
SDL_ShowWindow(window_); SDL_ShowWindow(window_);
// 发送窗口显示事件 // SDL_WINDOWEVENT_SHOWN 事件会触发 OnShow这里不需要手动触发
events::OnShow::emit();
} else { } else {
SDL_HideWindow(window_); SDL_HideWindow(window_);
// 发送窗口隐藏事件 // SDL_WINDOWEVENT_HIDDEN 事件会触发 OnHide这里不需要手动触发
events::OnHide::emit();
} }
} }
} }

View File

@ -1,15 +1,15 @@
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <vector>
#include <renderer/command_queue.h> #include <renderer/command_queue.h>
#include <renderer/material.h> #include <renderer/material.h>
#include <renderer/mesh.h> #include <renderer/mesh.h>
#include <renderer/rhi_module.h>
#include <renderer/rhi/opengl/gl_command_list.h> #include <renderer/rhi/opengl/gl_command_list.h>
#include <renderer/rhi/opengl/gl_texture.h> #include <renderer/rhi/opengl/gl_texture.h>
#include <renderer/rhi_module.h>
#include <types/math/transform.h> #include <types/math/transform.h>
#include <types/ptr/intrusive_ptr.h> #include <types/ptr/intrusive_ptr.h>
#include <utils/logger.h> #include <utils/logger.h>
#include <vector>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
@ -28,14 +28,14 @@ CommandSorter::CommandSorter() {
CommandSorter::~CommandSorter() = default; CommandSorter::~CommandSorter() = default;
CommandSorter::CommandSorter(CommandSorter&& other) noexcept CommandSorter::CommandSorter(CommandSorter &&other) noexcept
: commands_(std::move(other.commands_)), : commands_(std::move(other.commands_)),
sortedIndices_(std::move(other.sortedIndices_)), sortedIndices_(std::move(other.sortedIndices_)),
commandCount_(other.commandCount_) { commandCount_(other.commandCount_) {
other.commandCount_ = 0; other.commandCount_ = 0;
} }
CommandSorter& CommandSorter::operator=(CommandSorter&& other) noexcept { CommandSorter &CommandSorter::operator=(CommandSorter &&other) noexcept {
if (this != &other) { if (this != &other) {
commands_ = std::move(other.commands_); commands_ = std::move(other.commands_);
sortedIndices_ = std::move(other.sortedIndices_); sortedIndices_ = std::move(other.sortedIndices_);
@ -62,15 +62,15 @@ uint32_t CommandSorter::addCommand(const DrawCommand &cmd) {
} }
void CommandSorter::sort() { void CommandSorter::sort() {
if (commandCount_ == 0) return; if (commandCount_ == 0)
return;
// 只排序有效范围的索引 // 只排序有效范围的索引
auto indicesBegin = sortedIndices_.begin(); auto indicesBegin = sortedIndices_.begin();
auto indicesEnd = sortedIndices_.begin() + commandCount_; auto indicesEnd = sortedIndices_.begin() + commandCount_;
// 使用稳定排序保持相同键的命令顺序 // 使用稳定排序保持相同键的命令顺序
std::stable_sort(indicesBegin, indicesEnd, std::stable_sort(indicesBegin, indicesEnd, [this](uint32_t a, uint32_t b) {
[this](uint32_t a, uint32_t b) {
return commands_[a].key < commands_[b].key; return commands_[a].key < commands_[b].key;
}); });
} }
@ -198,40 +198,40 @@ bool CommandQueue::initialize() {
// 获取 RHI 模块 // 获取 RHI 模块
auto *rhiModule = RHIModule::get(); auto *rhiModule = RHIModule::get();
if (!rhiModule) { if (!rhiModule) {
E2D_LOG_ERROR("RHIModule not available"); E2D_ERROR("RHIModule not available");
return false; return false;
} }
auto *device = rhiModule->getDevice(); auto *device = rhiModule->getDevice();
if (!device) { if (!device) {
E2D_LOG_ERROR("RHIDevice not available"); E2D_ERROR("RHIDevice not available");
return false; return false;
} }
context_ = rhiModule->getContext(); context_ = rhiModule->getContext();
if (!context_) { if (!context_) {
E2D_LOG_ERROR("RHIContext not available"); E2D_ERROR("RHIContext not available");
return false; return false;
} }
// 创建命令列表 // 创建命令列表
commandList_ = device->createCommandList(); commandList_ = device->createCommandList();
if (!commandList_) { if (!commandList_) {
E2D_LOG_ERROR("Failed to create command list"); E2D_ERROR("Failed to create command list");
return false; return false;
} }
// 初始化 UBO 管理器 // 初始化 UBO 管理器
uboManager_ = std::make_unique<UniformBufferManager>(); uboManager_ = std::make_unique<UniformBufferManager>();
if (!uboManager_->initialize()) { if (!uboManager_->initialize()) {
E2D_LOG_ERROR("Failed to initialize UniformBufferManager"); E2D_ERROR("Failed to initialize UniformBufferManager");
return false; return false;
} }
// 预分配材质 UBO 数据缓冲区 // 预分配材质 UBO 数据缓冲区
materialUBOData_.reserve(1024 * 1024); // 1MB materialUBOData_.reserve(1024 * 1024); // 1MB
E2D_LOG_INFO("命令队列已初始化"); E2D_INFO("命令队列已初始化");
return true; return true;
} }
@ -240,7 +240,7 @@ void CommandQueue::shutdown() {
commandList_.reset(); commandList_.reset();
context_ = nullptr; context_ = nullptr;
materialUBOData_.clear(); materialUBOData_.clear();
E2D_LOG_INFO("命令队列已关闭"); E2D_INFO("命令队列已关闭");
} }
void CommandQueue::beginFrame() { void CommandQueue::beginFrame() {
@ -285,7 +285,8 @@ uint32_t CommandQueue::getMaterialId(Material *material) {
return id; return id;
} }
std::pair<UniformBuffer*, uint32_t> CommandQueue::allocateMaterialUBO(uint32_t size) { std::pair<UniformBuffer *, uint32_t>
CommandQueue::allocateMaterialUBO(uint32_t size) {
if (!uboManager_ || size == 0) { if (!uboManager_ || size == 0) {
return {nullptr, 0}; return {nullptr, 0};
} }
@ -314,7 +315,8 @@ std::pair<UniformBuffer*, uint32_t> CommandQueue::allocateMaterialUBO(uint32_t s
materialUBOBufferOffset_ = offset + alignedSize; materialUBOBufferOffset_ = offset + alignedSize;
return {nullptr, offset}; // 返回 nullptr 表示使用 CPU 缓冲区offset 是 CPU 缓冲区偏移 return {nullptr,
offset}; // 返回 nullptr 表示使用 CPU 缓冲区offset 是 CPU 缓冲区偏移
} }
void CommandQueue::flushMaterialUBOToGPU() { void CommandQueue::flushMaterialUBOToGPU() {
@ -323,20 +325,22 @@ void CommandQueue::flushMaterialUBOToGPU() {
} }
// 获取一个足够大的 UBO // 获取一个足够大的 UBO
currentMaterialUBO_ = uboManager_->acquireMaterialUBO(materialUBOBufferOffset_); currentMaterialUBO_ =
uboManager_->acquireMaterialUBO(materialUBOBufferOffset_);
if (!currentMaterialUBO_) { if (!currentMaterialUBO_) {
E2D_LOG_ERROR("获取材质 UBO 失败"); E2D_ERROR("获取材质 UBO 失败");
return; return;
} }
// 批量更新到 GPU // 批量更新到 GPU
currentMaterialUBO_->update(materialUBOData_.data(), materialUBOBufferOffset_, 0); currentMaterialUBO_->update(materialUBOData_.data(), materialUBOBufferOffset_,
0);
// 重置 CPU 缓冲区偏移 // 重置 CPU 缓冲区偏移
materialUBOBufferOffset_ = 0; materialUBOBufferOffset_ = 0;
} }
UniformBuffer* CommandQueue::getCurrentMaterialUBO() const { UniformBuffer *CommandQueue::getCurrentMaterialUBO() const {
return currentMaterialUBO_; return currentMaterialUBO_;
} }
@ -386,14 +390,16 @@ void CommandQueue::submitDraw(Ptr<Material> material, Ptr<Mesh> mesh,
// 复制材质数据到 CPU 缓冲区,并修改颜色 // 复制材质数据到 CPU 缓冲区,并修改颜色
if (offset + materialDataSize <= materialUBOData_.size()) { if (offset + materialDataSize <= materialUBOData_.size()) {
std::memcpy(materialUBOData_.data() + offset, material->getData(), materialDataSize); std::memcpy(materialUBOData_.data() + offset, material->getData(),
materialDataSize);
// 将实例颜色应用到 UBO 数据中的 uColor 参数 // 将实例颜色应用到 UBO 数据中的 uColor 参数
auto layout = material->getLayout(); auto layout = material->getLayout();
if (layout) { if (layout) {
const auto* param = layout->getParam("uColor"); const auto *param = layout->getParam("uColor");
if (param && param->type == MaterialParamType::Color) { 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,15 +437,17 @@ void CommandQueue::setViewport(int32_t x, int32_t y, int32_t width,
commandList_->setViewport(viewport); commandList_->setViewport(viewport);
} }
void CommandQueue::updateGlobalUBO(const Mat4& viewProjection, float deltaTime, void CommandQueue::updateGlobalUBO(const Mat4 &viewProjection, float deltaTime,
uint32_t screenWidth, uint32_t screenHeight, uint32_t frameIndex) { uint32_t screenWidth, uint32_t screenHeight,
uint32_t frameIndex) {
if (!uboManager_) { if (!uboManager_) {
E2D_LOG_WARN("CommandQueue::updateGlobalUBO: uboManager 为空"); E2D_WARN("CommandQueue::updateGlobalUBO: uboManager 为空");
return; return;
} }
// 填充全局 UBO 数据 // 填充全局 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[0] = 0.0f;
globalUBOData_.cameraPosition[1] = 0.0f; globalUBOData_.cameraPosition[1] = 0.0f;
globalUBOData_.cameraPosition[2] = 0.0f; globalUBOData_.cameraPosition[2] = 0.0f;
@ -450,12 +458,13 @@ void CommandQueue::updateGlobalUBO(const Mat4& viewProjection, float deltaTime,
globalUBOData_.screenSize[1] = static_cast<float>(screenHeight); globalUBOData_.screenSize[1] = static_cast<float>(screenHeight);
// 使用双缓冲更新 UBO // 使用双缓冲更新 UBO
uboManager_->updateGlobalUBO(&globalUBOData_, sizeof(globalUBOData_), frameIndex); uboManager_->updateGlobalUBO(&globalUBOData_, sizeof(globalUBOData_),
frameIndex);
} }
void CommandQueue::execute(uint32_t frameIndex) { void CommandQueue::execute(uint32_t frameIndex) {
if (!commandList_) { if (!commandList_) {
E2D_LOG_ERROR("CommandQueue::execute: commandList 为空"); E2D_ERROR("CommandQueue::execute: commandList 为空");
return; return;
} }
@ -477,7 +486,8 @@ void CommandQueue::execute(uint32_t frameIndex) {
commandList_->submit(); 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_) { if (!commandList_) {
return; return;
} }
@ -487,12 +497,12 @@ void CommandQueue::executeBatch(uint32_t batchIndex, const CommandBatch &batch,
commandList_->setPipeline(batch.pipeline.get()); commandList_->setPipeline(batch.pipeline.get());
stats_.pipelineBinds++; stats_.pipelineBinds++;
} else { } else {
E2D_LOG_WARN("批次没有有效的管线!"); E2D_WARN("批次没有有效的管线!");
} }
// 绑定全局 UBO (binding = 0) - 使用双缓冲 // 绑定全局 UBO (binding = 0) - 使用双缓冲
if (uboManager_) { if (uboManager_) {
UniformBuffer* globalUBO = uboManager_->getGlobalUBO(frameIndex); UniformBuffer *globalUBO = uboManager_->getGlobalUBO(frameIndex);
if (globalUBO) { if (globalUBO) {
commandList_->setUniformBuffer(0, globalUBO->getRHIBuffer()); commandList_->setUniformBuffer(0, globalUBO->getRHIBuffer());
stats_.bufferBinds++; stats_.bufferBinds++;
@ -518,7 +528,7 @@ void CommandQueue::executeBatch(uint32_t batchIndex, const CommandBatch &batch,
commandList_->setVertexBuffer(0, cmd.vertexBuffer.get(), 0); commandList_->setVertexBuffer(0, cmd.vertexBuffer.get(), 0);
stats_.bufferBinds++; stats_.bufferBinds++;
} else { } else {
E2D_LOG_WARN("绘制命令没有有效的顶点缓冲区!"); E2D_WARN("绘制命令没有有效的顶点缓冲区!");
} }
// 绑定索引缓冲区(如果有) // 绑定索引缓冲区(如果有)
@ -529,7 +539,9 @@ void CommandQueue::executeBatch(uint32_t batchIndex, const CommandBatch &batch,
// 绑定材质 UBO (binding = 1) // 绑定材质 UBO (binding = 1)
if (cmd.materialUBOSize > 0 && currentMaterialUBO_) { 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++; stats_.bufferBinds++;
} }

View File

@ -1,6 +1,6 @@
#include <cstring>
#include <renderer/material.h> #include <renderer/material.h>
#include <utils/logger.h> #include <utils/logger.h>
#include <cstring>
namespace extra2d { namespace extra2d {
@ -15,15 +15,15 @@ MaterialLayout::MaterialLayout() = default;
* @param name * @param name
* @param type * @param type
*/ */
void MaterialLayout::addParam(const std::string& name, MaterialParamType type) { void MaterialLayout::addParam(const std::string &name, MaterialParamType type) {
if (finalized_) { if (finalized_) {
E2D_LOG_WARN("无法向已完成的材质布局添加参数"); E2D_WARN("无法向已完成的材质布局添加参数");
return; return;
} }
// 检查是否已存在 // 检查是否已存在
if (paramIndexMap_.find(name) != paramIndexMap_.end()) { if (paramIndexMap_.find(name) != paramIndexMap_.end()) {
E2D_LOG_WARN("参数 '{}' 已存在于材质布局中", name); E2D_WARN("参数 '{}' 已存在于材质布局中", name);
return; return;
} }
@ -47,11 +47,12 @@ void MaterialLayout::addParam(const std::string& name, MaterialParamType type) {
* - 16 * - 16
*/ */
void MaterialLayout::finalize() { void MaterialLayout::finalize() {
if (finalized_) return; if (finalized_)
return;
uint32_t offset = 0; uint32_t offset = 0;
for (auto& pair : params_) { for (auto &pair : params_) {
auto& info = pair.second; auto &info = pair.second;
// 计算对齐要求 - std140规则 // 计算对齐要求 - std140规则
uint32_t alignment = 4; // 默认 4 字节对齐 uint32_t alignment = 4; // 默认 4 字节对齐
@ -93,7 +94,8 @@ void MaterialLayout::finalize() {
* @param name * @param name
* @return nullptr * @return nullptr
*/ */
const MaterialParamInfo* MaterialLayout::getParam(const std::string& name) const { const MaterialParamInfo *
MaterialLayout::getParam(const std::string &name) const {
auto mapIt = paramIndexMap_.find(name); auto mapIt = paramIndexMap_.find(name);
if (mapIt != paramIndexMap_.end()) { if (mapIt != paramIndexMap_.end()) {
return &params_[mapIt->second].second; return &params_[mapIt->second].second;
@ -122,9 +124,7 @@ void Material::setLayout(Ptr<MaterialLayout> layout) {
* @brief * @brief
* @param shader * @param shader
*/ */
void Material::setShader(Ptr<Shader> shader) { void Material::setShader(Ptr<Shader> shader) { shader_ = shader; }
shader_ = shader;
}
/** /**
* @brief RHI 线 * @brief RHI 线
@ -142,10 +142,11 @@ PipelineHandle Material::getPipeline() const {
* @param name * @param name
* @param value * @param value
*/ */
void Material::setFloat(const std::string& name, float value) { void Material::setFloat(const std::string &name, float value) {
if (!layout_) return; if (!layout_)
return;
const auto* param = layout_->getParam(name); const auto *param = layout_->getParam(name);
if (param && param->type == MaterialParamType::Float) { if (param && param->type == MaterialParamType::Float) {
std::memcpy(data_.data() + param->offset, &value, sizeof(float)); std::memcpy(data_.data() + param->offset, &value, sizeof(float));
} }
@ -156,10 +157,11 @@ void Material::setFloat(const std::string& name, float value) {
* @param name * @param name
* @param value * @param value
*/ */
void Material::setVec2(const std::string& name, const Vec2& value) { void Material::setVec2(const std::string &name, const Vec2 &value) {
if (!layout_) return; if (!layout_)
return;
const auto* param = layout_->getParam(name); const auto *param = layout_->getParam(name);
if (param && param->type == MaterialParamType::Vec2) { if (param && param->type == MaterialParamType::Vec2) {
std::memcpy(data_.data() + param->offset, &value.x, sizeof(float) * 2); std::memcpy(data_.data() + param->offset, &value.x, sizeof(float) * 2);
} }
@ -173,10 +175,12 @@ void Material::setVec2(const std::string& name, const Vec2& value) {
* @param z Z * @param z Z
* @param w W * @param w W
*/ */
void Material::setVec4(const std::string& name, float x, float y, float z, float w) { void Material::setVec4(const std::string &name, float x, float y, float z,
if (!layout_) return; float w) {
if (!layout_)
return;
const auto* param = layout_->getParam(name); const auto *param = layout_->getParam(name);
if (param && param->type == MaterialParamType::Vec4) { if (param && param->type == MaterialParamType::Vec4) {
float values[4] = {x, y, z, w}; float values[4] = {x, y, z, w};
std::memcpy(data_.data() + param->offset, values, sizeof(float) * 4); std::memcpy(data_.data() + param->offset, values, sizeof(float) * 4);
@ -188,10 +192,11 @@ void Material::setVec4(const std::string& name, float x, float y, float z, float
* @param name * @param name
* @param value * @param value
*/ */
void Material::setColor(const std::string& name, const Color& value) { void Material::setColor(const std::string &name, const Color &value) {
if (!layout_) return; if (!layout_)
return;
const auto* param = layout_->getParam(name); const auto *param = layout_->getParam(name);
if (param && param->type == MaterialParamType::Color) { if (param && param->type == MaterialParamType::Color) {
std::memcpy(data_.data() + param->offset, &value.r, sizeof(float) * 4); std::memcpy(data_.data() + param->offset, &value.r, sizeof(float) * 4);
} }
@ -202,10 +207,11 @@ void Material::setColor(const std::string& name, const Color& value) {
* @param name * @param name
* @param value * @param value
*/ */
void Material::setMat4(const std::string& name, const float* value) { void Material::setMat4(const std::string &name, const float *value) {
if (!layout_) return; if (!layout_)
return;
const auto* param = layout_->getParam(name); const auto *param = layout_->getParam(name);
if (param && param->type == MaterialParamType::Mat4) { if (param && param->type == MaterialParamType::Mat4) {
std::memcpy(data_.data() + param->offset, value, sizeof(float) * 16); std::memcpy(data_.data() + param->offset, value, sizeof(float) * 16);
} }
@ -217,9 +223,10 @@ void Material::setMat4(const std::string& name, const float* value) {
* @param texture * @param texture
* @param slot 0-15 * @param slot 0-15
*/ */
void Material::setTexture(const std::string& uniformName, Ptr<Texture> texture, uint32_t slot) { void Material::setTexture(const std::string &uniformName, Ptr<Texture> texture,
uint32_t slot) {
// 查找是否已存在相同名称的纹理 // 查找是否已存在相同名称的纹理
for (auto& texSlot : textures_) { for (auto &texSlot : textures_) {
if (texSlot.uniformName == uniformName) { if (texSlot.uniformName == uniformName) {
texSlot.texture = texture; texSlot.texture = texture;
texSlot.slot = slot; texSlot.slot = slot;
@ -234,8 +241,6 @@ void Material::setTexture(const std::string& uniformName, Ptr<Texture> texture,
/** /**
* @brief * @brief
*/ */
void Material::clearTextures() { void Material::clearTextures() { textures_.clear(); }
textures_.clear();
}
} // namespace extra2d } // namespace extra2d

View File

@ -20,13 +20,13 @@ void Mesh::setVertices(const Vertex *vertices, uint32_t count) {
// 获取 RHI 模块 // 获取 RHI 模块
auto *rhiModule = RHIModule::get(); auto *rhiModule = RHIModule::get();
if (!rhiModule) { if (!rhiModule) {
E2D_LOG_ERROR("RHI 模块不可用"); E2D_ERROR("RHI 模块不可用");
return; return;
} }
auto *device = rhiModule->getDevice(); auto *device = rhiModule->getDevice();
if (!device) { if (!device) {
E2D_LOG_ERROR("RHI 设备不可用"); E2D_ERROR("RHI 设备不可用");
return; return;
} }
@ -37,7 +37,7 @@ void Mesh::setVertices(const Vertex *vertices, uint32_t count) {
// 通过句柄获取缓冲区指针并更新数据 // 通过句柄获取缓冲区指针并更新数据
// 注意:这里假设可以通过某种方式获取缓冲区指针 // 注意:这里假设可以通过某种方式获取缓冲区指针
// 实际实现可能需要通过 RHI 命令列表来更新 // 实际实现可能需要通过 RHI 命令列表来更新
E2D_LOG_WARN("顶点缓冲区更新尚未实现"); E2D_WARN("顶点缓冲区更新尚未实现");
} else { } else {
// 需要创建新缓冲区 // 需要创建新缓冲区
vertexBuffer_ = BufferHandle(); vertexBuffer_ = BufferHandle();
@ -49,7 +49,7 @@ void Mesh::setVertices(const Vertex *vertices, uint32_t count) {
// 创建缓冲区 // 创建缓冲区
auto buffer = device->createBuffer(desc); auto buffer = device->createBuffer(desc);
if (!buffer) { if (!buffer) {
E2D_LOG_ERROR("创建顶点缓冲区失败"); E2D_ERROR("创建顶点缓冲区失败");
return; return;
} }
@ -62,7 +62,7 @@ void Mesh::setVertices(const Vertex *vertices, uint32_t count) {
} }
vertexCount_ = count; vertexCount_ = count;
E2D_LOG_INFO("设置了 {} 个顶点", count); E2D_INFO("设置了 {} 个顶点", count);
} }
void Mesh::setIndices(const uint16_t *indices, uint32_t 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 模块 // 获取 RHI 模块
auto *rhiModule = RHIModule::get(); auto *rhiModule = RHIModule::get();
if (!rhiModule) { if (!rhiModule) {
E2D_LOG_ERROR("RHI 模块不可用"); E2D_ERROR("RHI 模块不可用");
return; return;
} }
auto *device = rhiModule->getDevice(); auto *device = rhiModule->getDevice();
if (!device) { if (!device) {
E2D_LOG_ERROR("RHI 设备不可用"); E2D_ERROR("RHI 设备不可用");
return; return;
} }
@ -86,7 +86,7 @@ void Mesh::setIndices(const uint16_t *indices, uint32_t count) {
// 如果缓冲区已存在且容量足够,更新数据 // 如果缓冲区已存在且容量足够,更新数据
if (indexBuffer_.isValid() && indexCapacity_ >= count) { if (indexBuffer_.isValid() && indexCapacity_ >= count) {
E2D_LOG_WARN("索引缓冲区更新尚未实现"); E2D_WARN("索引缓冲区更新尚未实现");
} else { } else {
// 需要创建新缓冲区 // 需要创建新缓冲区
indexBuffer_ = BufferHandle(); indexBuffer_ = BufferHandle();
@ -98,7 +98,7 @@ void Mesh::setIndices(const uint16_t *indices, uint32_t count) {
// 创建缓冲区 // 创建缓冲区
auto buffer = device->createBuffer(desc); auto buffer = device->createBuffer(desc);
if (!buffer) { if (!buffer) {
E2D_LOG_ERROR("创建索引缓冲区失败"); E2D_ERROR("创建索引缓冲区失败");
return; return;
} }
@ -109,7 +109,7 @@ void Mesh::setIndices(const uint16_t *indices, uint32_t count) {
} }
indexCount_ = count; indexCount_ = count;
E2D_LOG_INFO("设置了 {} 个索引", count); E2D_INFO("设置了 {} 个索引", count);
} }
void Mesh::updateVertices(const Vertex *vertices, uint32_t count, void Mesh::updateVertices(const Vertex *vertices, uint32_t count,
@ -118,7 +118,7 @@ void Mesh::updateVertices(const Vertex *vertices, uint32_t count,
return; return;
if (offset + count > vertexCount_) { if (offset + count > vertexCount_) {
E2D_LOG_WARN("顶点更新超出边界"); E2D_WARN("顶点更新超出边界");
return; return;
} }
@ -134,7 +134,7 @@ void Mesh::updateVertices(const Vertex *vertices, uint32_t count,
// 通过句柄获取缓冲区并更新数据 // 通过句柄获取缓冲区并更新数据
// 注意:这里需要 RHI 提供更新缓冲区的方法 // 注意:这里需要 RHI 提供更新缓冲区的方法
// 暂时记录为未实现 // 暂时记录为未实现
E2D_LOG_WARN("updateVertices 尚未完全实现"); E2D_WARN("updateVertices 尚未完全实现");
} }
Ptr<Mesh> Mesh::createQuad(const Vec2 &size, const Rect &uv) { Ptr<Mesh> Mesh::createQuad(const Vec2 &size, const Rect &uv) {

View File

@ -95,11 +95,11 @@ RenderGraph &RenderGraph::operator=(RenderGraph &&other) noexcept {
bool RenderGraph::initialize() { bool RenderGraph::initialize() {
if (!commandQueue_.initialize()) { if (!commandQueue_.initialize()) {
E2D_LOG_ERROR("初始化命令队列失败"); E2D_ERROR("初始化命令队列失败");
return false; return false;
} }
E2D_LOG_INFO("渲染图已初始化"); E2D_INFO("渲染图已初始化");
return true; return true;
} }
@ -110,7 +110,7 @@ void RenderGraph::shutdown() {
commandQueue_.shutdown(); commandQueue_.shutdown();
compiled_ = false; compiled_ = false;
E2D_LOG_INFO("渲染图已关闭"); E2D_INFO("渲染图已关闭");
} }
RenderPass *RenderGraph::addPass(std::unique_ptr<RenderPass> pass) { RenderPass *RenderGraph::addPass(std::unique_ptr<RenderPass> pass) {
@ -174,15 +174,15 @@ bool RenderGraph::compile() {
createResources(); createResources();
compiled_ = true; compiled_ = true;
E2D_LOG_INFO("渲染图编译完成,共 {} 个通道", executionOrder_.size()); E2D_INFO("渲染图编译完成,共 {} 个通道", executionOrder_.size());
return true; return true;
} }
void RenderGraph::execute(float deltaTime, const Mat4& viewProjection) { void RenderGraph::execute(float deltaTime, const Mat4 &viewProjection) {
if (!compiled_) { if (!compiled_) {
if (!compile()) { if (!compile()) {
E2D_LOG_ERROR("编译渲染图失败"); E2D_ERROR("编译渲染图失败");
return; return;
} }
} }

View File

@ -12,7 +12,7 @@ RendererModule::RendererModule() = default;
RendererModule::~RendererModule() = default; RendererModule::~RendererModule() = default;
bool RendererModule::init() { bool RendererModule::init() {
E2D_LOG_INFO("正在初始化渲染模块..."); E2D_INFO("正在初始化渲染模块...");
// 绑定事件监听器 // 绑定事件监听器
onRenderBeginListener_.bind([this]() { onRenderBegin(); }); onRenderBeginListener_.bind([this]() { onRenderBegin(); });
@ -24,7 +24,7 @@ bool RendererModule::init() {
onResizeListener_.bind([this](int32 w, int32 h) { onResize(w, h); }); onResizeListener_.bind([this](int32 w, int32 h) { onResize(w, h); });
onShowListener_.bind([this]() { onWindowShow(); }); onShowListener_.bind([this]() { onWindowShow(); });
E2D_LOG_INFO("渲染模块已初始化 (等待窗口显示)"); E2D_INFO("渲染模块已初始化 (等待窗口显示)");
return true; return true;
} }
@ -33,25 +33,25 @@ void RendererModule::onWindowShow() {
return; return;
} }
E2D_LOG_INFO("正在初始化渲染模块上下文..."); E2D_INFO("正在初始化渲染模块上下文...");
// 初始化 RHI 模块 // 初始化 RHI 模块
auto *rhiModule = RHIModule::get(); auto *rhiModule = RHIModule::get();
if (!rhiModule) { if (!rhiModule) {
E2D_LOG_ERROR("RHI 模块不可用"); E2D_ERROR("RHI 模块不可用");
return; return;
} }
if (!rhiModule->getDevice()) { if (!rhiModule->getDevice()) {
// RHI 设备尚未初始化,这是正常的时序问题 // RHI 设备尚未初始化,这是正常的时序问题
// RHIModule 会在窗口显示后初始化设备,然后再次触发此函数 // RHIModule 会在窗口显示后初始化设备,然后再次触发此函数
E2D_LOG_INFO("RHI 设备尚未就绪,等待 RHI 初始化..."); E2D_INFO("RHI 设备尚未就绪,等待 RHI 初始化...");
return; return;
} }
// 初始化渲染图 // 初始化渲染图
if (!renderGraph_.initialize()) { if (!renderGraph_.initialize()) {
E2D_LOG_ERROR("初始化渲染图失败"); E2D_ERROR("初始化渲染图失败");
return; return;
} }
@ -61,22 +61,22 @@ void RendererModule::onWindowShow() {
auto geometryPass = std::make_unique<GeometryRenderPass>("Geometry"); auto geometryPass = std::make_unique<GeometryRenderPass>("Geometry");
renderGraph_.addPass(std::move(geometryPass)); renderGraph_.addPass(std::move(geometryPass));
E2D_LOG_INFO("已添加默认几何渲染通道"); E2D_INFO("已添加默认几何渲染通道");
auto windowModule = getModule<WindowModule>(); auto windowModule = getModule<WindowModule>();
if (!windowModule) { if (!windowModule) {
E2D_LOG_ERROR("窗口模块不可用"); E2D_ERROR("窗口模块不可用");
return; return;
} }
setViewport(0, 0, static_cast<int32>(windowModule->getSize().w), setViewport(0, 0, static_cast<int32>(windowModule->getSize().w),
static_cast<int32>(windowModule->getSize().h)); static_cast<int32>(windowModule->getSize().h));
initialized_ = true; initialized_ = true;
E2D_LOG_INFO("渲染模块上下文初始化成功"); E2D_INFO("渲染模块上下文初始化成功");
} }
void RendererModule::shutdown() { void RendererModule::shutdown() {
E2D_LOG_INFO("正在关闭渲染模块..."); E2D_INFO("正在关闭渲染模块...");
renderGraph_.shutdown(); renderGraph_.shutdown();
commandQueue_ = nullptr; commandQueue_ = nullptr;
@ -84,7 +84,7 @@ void RendererModule::shutdown() {
// 注意:事件监听器是值类型,会在析构时自动清理 // 注意:事件监听器是值类型,会在析构时自动清理
E2D_LOG_INFO("渲染模块关闭完成"); E2D_INFO("渲染模块关闭完成");
} }
RHIContext *RendererModule::getRHIContext() const { RHIContext *RendererModule::getRHIContext() const {
@ -162,7 +162,7 @@ void RendererModule::onRenderBegin() {
void RendererModule::onRenderSubmit(const RenderCommand &cmd) { void RendererModule::onRenderSubmit(const RenderCommand &cmd) {
if (!initialized_ || !commandQueue_) { if (!initialized_ || !commandQueue_) {
E2D_LOG_WARN("onRenderSubmit: 渲染模块未初始化或没有命令队列"); E2D_WARN("onRenderSubmit: 渲染模块未初始化或没有命令队列");
return; return;
} }
@ -194,8 +194,8 @@ void RendererModule::onRenderSubmit(const RenderCommand &cmd) {
transform, cmd.drawMesh.color); transform, cmd.drawMesh.color);
stats_.commandsSubmitted++; stats_.commandsSubmitted++;
} else { } else {
E2D_LOG_WARN("提交绘制命令失败: 材质={}, 网格={}", E2D_WARN("提交绘制命令失败: 材质={}, 网格={}", material ? "有效" : "",
material ? "有效" : "", mesh ? "有效" : ""); mesh ? "有效" : "");
} }
break; break;
} }
@ -226,7 +226,7 @@ void RendererModule::onRenderSetCamera(const Mat4 &viewProj) {
void RendererModule::onRenderEnd() { void RendererModule::onRenderEnd() {
if (!initialized_) { if (!initialized_) {
E2D_LOG_WARN("onRenderEnd: 渲染模块未初始化"); E2D_WARN("onRenderEnd: 渲染模块未初始化");
return; return;
} }
@ -241,7 +241,7 @@ void RendererModule::onRenderEnd() {
// 每60帧输出一次统计信息 // 每60帧输出一次统计信息
static uint32_t frameCount = 0; static uint32_t frameCount = 0;
if (++frameCount % 60 == 0) { if (++frameCount % 60 == 0) {
E2D_LOG_INFO("渲染统计: 绘制调用={}, 三角形数={}, 顶点数={}, " E2D_INFO("渲染统计: 绘制调用={}, 三角形数={}, 顶点数={}, "
"管线绑定={}, 纹理绑定={}, 缓冲区绑定={}", "管线绑定={}, 纹理绑定={}, 缓冲区绑定={}",
stats.drawCalls, stats.triangles, stats.vertices, stats.drawCalls, stats.triangles, stats.vertices,
stats.pipelineBinds, stats.textureBinds, stats.bufferBinds); stats.pipelineBinds, stats.textureBinds, stats.bufferBinds);

View File

@ -12,22 +12,22 @@ GLContext::GLContext(GLDevice *device)
GLContext::~GLContext() = default; GLContext::~GLContext() = default;
bool GLContext::initialize() { bool GLContext::initialize() {
E2D_LOG_INFO("正在初始化 OpenGL 上下文..."); E2D_INFO("正在初始化 OpenGL 上下文...");
// 创建默认帧缓冲(窗口帧缓冲) // 创建默认帧缓冲(窗口帧缓冲)
defaultFramebuffer_ = std::make_unique<GLFramebuffer>(); defaultFramebuffer_ = std::make_unique<GLFramebuffer>();
defaultFramebuffer_->setSize(800, 600); // 默认大小,会被更新 defaultFramebuffer_->setSize(800, 600); // 默认大小,会被更新
E2D_LOG_INFO("OpenGL 上下文初始化完成"); E2D_INFO("OpenGL 上下文初始化完成");
return true; return true;
} }
void GLContext::shutdown() { void GLContext::shutdown() {
E2D_LOG_INFO("正在关闭 OpenGL 上下文..."); E2D_INFO("正在关闭 OpenGL 上下文...");
defaultFramebuffer_.reset(); defaultFramebuffer_.reset();
E2D_LOG_INFO("OpenGL 上下文关闭完成"); E2D_INFO("OpenGL 上下文关闭完成");
} }
void GLContext::beginFrame() { void GLContext::beginFrame() {

View File

@ -7,8 +7,8 @@
#include <renderer/rhi/opengl/gl_texture.h> #include <renderer/rhi/opengl/gl_texture.h>
#include <renderer/rhi/opengl/gl_utils.h> #include <renderer/rhi/opengl/gl_utils.h>
#include <glad/glad.h>
#include <SDL.h> #include <SDL.h>
#include <glad/glad.h>
#include <utils/logger.h> #include <utils/logger.h>
namespace extra2d { namespace extra2d {
@ -21,19 +21,20 @@ class GLDevice;
*/ */
class GLDevice : public RHIDevice { class GLDevice : public RHIDevice {
public: public:
GLDevice() : window_(nullptr), glContext_(nullptr), context_(nullptr), stats_() {} GLDevice()
: window_(nullptr), glContext_(nullptr), context_(nullptr), stats_() {}
~GLDevice() override { shutdown(); } ~GLDevice() override { shutdown(); }
bool initialize(void* nativeWindow) override { bool initialize(void *nativeWindow) override {
E2D_LOG_INFO("正在初始化 OpenGL 设备..."); E2D_INFO("正在初始化 OpenGL 设备...");
if (!nativeWindow) { if (!nativeWindow) {
E2D_LOG_ERROR("原生窗口句柄为空"); E2D_ERROR("原生窗口句柄为空");
return false; return false;
} }
window_ = static_cast<SDL_Window*>(nativeWindow); window_ = static_cast<SDL_Window *>(nativeWindow);
// 创建 OpenGL ES 3.2 上下文 // 创建 OpenGL ES 3.2 上下文
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
@ -45,38 +46,39 @@ public:
glContext_ = SDL_GL_CreateContext(window_); glContext_ = SDL_GL_CreateContext(window_);
if (!glContext_) { if (!glContext_) {
E2D_LOG_ERROR("创建 OpenGL ES 上下文失败: {}", SDL_GetError()); E2D_ERROR("创建 OpenGL ES 上下文失败: {}", SDL_GetError());
return false; return false;
} }
// 初始化 GLAD // 初始化 GLAD
if (!gladLoadGLES2Loader((GLADloadproc)SDL_GL_GetProcAddress)) { if (!gladLoadGLES2Loader((GLADloadproc)SDL_GL_GetProcAddress)) {
E2D_LOG_ERROR("初始化 GLAD 失败"); E2D_ERROR("初始化 GLAD 失败");
SDL_GL_DeleteContext(glContext_); SDL_GL_DeleteContext(glContext_);
glContext_ = nullptr; glContext_ = nullptr;
return false; return false;
} }
E2D_LOG_INFO("OpenGL ES 上下文已创建: {}.{}", GLVersion.major, GLVersion.minor); E2D_INFO("OpenGL ES 上下文已创建: {}.{}", GLVersion.major, GLVersion.minor);
const char* version = reinterpret_cast<const char *>(glGetString(GL_VERSION)); const char *version =
reinterpret_cast<const char *>(glGetString(GL_VERSION));
if (!version) { if (!version) {
E2D_LOG_ERROR("获取 OpenGL 版本失败"); E2D_ERROR("获取 OpenGL 版本失败");
SDL_GL_DeleteContext(glContext_); SDL_GL_DeleteContext(glContext_);
glContext_ = nullptr; glContext_ = nullptr;
return false; return false;
} }
E2D_LOG_INFO("OpenGL 版本: {}", version); E2D_INFO("OpenGL 版本: {}", version);
E2D_LOG_INFO("OpenGL 供应商: {}", E2D_INFO("OpenGL 供应商: {}",
reinterpret_cast<const char *>(glGetString(GL_VENDOR))); reinterpret_cast<const char *>(glGetString(GL_VENDOR)));
E2D_LOG_INFO("OpenGL 渲染器: {}", E2D_INFO("OpenGL 渲染器: {}",
reinterpret_cast<const char *>(glGetString(GL_RENDERER))); reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
// 创建上下文管理器 // 创建上下文管理器
context_ = std::make_unique<GLContext>(this); context_ = std::make_unique<GLContext>(this);
if (!context_->initialize()) { if (!context_->initialize()) {
E2D_LOG_ERROR("初始化 GL 上下文失败"); E2D_ERROR("初始化 GL 上下文失败");
SDL_GL_DeleteContext(glContext_); SDL_GL_DeleteContext(glContext_);
glContext_ = nullptr; glContext_ = nullptr;
return false; return false;
@ -86,12 +88,12 @@ public:
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
E2D_LOG_INFO("OpenGL 设备初始化成功"); E2D_INFO("OpenGL 设备初始化成功");
return true; return true;
} }
void shutdown() override { void shutdown() override {
E2D_LOG_INFO("正在关闭 OpenGL 设备..."); E2D_INFO("正在关闭 OpenGL 设备...");
if (context_) { if (context_) {
context_->shutdown(); context_->shutdown();
@ -105,7 +107,7 @@ public:
window_ = nullptr; window_ = nullptr;
E2D_LOG_INFO("OpenGL 设备关闭完成"); E2D_INFO("OpenGL 设备关闭完成");
} }
std::unique_ptr<RHIBuffer> createBuffer(const BufferDesc &desc) override { std::unique_ptr<RHIBuffer> createBuffer(const BufferDesc &desc) override {
@ -127,7 +129,7 @@ public:
std::unique_ptr<RHIShader> createShader(const ShaderDesc &desc) override { std::unique_ptr<RHIShader> createShader(const ShaderDesc &desc) override {
auto shader = std::make_unique<GLShader>(desc); auto shader = std::make_unique<GLShader>(desc);
if (!shader->compile()) { if (!shader->compile()) {
E2D_LOG_ERROR("着色器编译失败: {}", shader->getCompileLog()); E2D_ERROR("着色器编译失败: {}", shader->getCompileLog());
return nullptr; return nullptr;
} }
return shader; return shader;
@ -142,9 +144,9 @@ public:
// 获取 vertex shader 的 program ID // 获取 vertex shader 的 program ID
if (desc.vertexShader.isValid()) { if (desc.vertexShader.isValid()) {
RHIShader* shader = desc.vertexShader.get(); RHIShader *shader = desc.vertexShader.get();
if (shader) { if (shader) {
auto* glShader = static_cast<GLShader*>(shader); auto *glShader = static_cast<GLShader *>(shader);
pipeline->setGLProgram(glShader->getGLProgram()); pipeline->setGLProgram(glShader->getGLProgram());
} }
} }
@ -186,7 +188,7 @@ public:
void incrementRenderPassSwitches() { stats_.renderPassSwitches++; } void incrementRenderPassSwitches() { stats_.renderPassSwitches++; }
private: private:
SDL_Window* window_; SDL_Window *window_;
SDL_GLContext glContext_; SDL_GLContext glContext_;
std::unique_ptr<GLContext> context_; std::unique_ptr<GLContext> context_;
RenderStats stats_; RenderStats stats_;

View File

@ -26,13 +26,13 @@ RHIModule::~RHIModule() {
} }
bool RHIModule::init() { bool RHIModule::init() {
E2D_LOG_INFO("正在初始化 RHI 模块..."); E2D_INFO("正在初始化 RHI 模块...");
// 注册窗口显示事件监听,在窗口显示时创建 OpenGL 上下文 // 注册窗口显示事件监听,在窗口显示时创建 OpenGL 上下文
onShowListener_ = std::make_unique<events::OnShow::Listener>(); onShowListener_ = std::make_unique<events::OnShow::Listener>();
onShowListener_->bind([this]() { this->onWindowShow(); }); onShowListener_->bind([this]() { this->onWindowShow(); });
E2D_LOG_INFO("RHI 模块已初始化 (等待窗口显示)"); E2D_INFO("RHI 模块已初始化 (等待窗口显示)");
return true; return true;
} }
@ -41,54 +41,45 @@ void RHIModule::onWindowShow() {
return; return;
} }
E2D_LOG_INFO("RHI 模块: 正在创建 OpenGL 设备..."); E2D_INFO("RHI 模块: 正在创建 OpenGL 设备...");
// 获取窗口模块 // 获取窗口模块
auto *windowModule = getModule<WindowModule>(); auto *windowModule = getModule<WindowModule>();
if (!windowModule) { if (!windowModule) {
E2D_LOG_ERROR("窗口模块不可用"); E2D_ERROR("窗口模块不可用");
return; return;
} }
// 等待窗口创建完成 // 等待窗口创建完成
if (!windowModule->handle()) { if (!windowModule->handle()) {
E2D_LOG_ERROR("窗口尚未创建"); E2D_ERROR("窗口尚未创建");
return; return;
} }
// 创建 OpenGL 设备并传入窗口句柄 // 创建 OpenGL 设备并传入窗口句柄
device_ = CreateGLDevice(); device_ = CreateGLDevice();
if (!device_) { if (!device_) {
E2D_LOG_ERROR("创建 RHI 设备失败"); E2D_ERROR("创建 RHI 设备失败");
return; return;
} }
if (!device_->initialize(windowModule->handle())) { if (!device_->initialize(windowModule->handle())) {
E2D_LOG_ERROR("初始化 RHI 设备失败"); E2D_ERROR("初始化 RHI 设备失败");
device_.reset(); device_.reset();
return; return;
} }
context_ = device_->getContext(); context_ = device_->getContext();
if (!context_) { if (!context_) {
E2D_LOG_ERROR("获取 RHI 上下文失败"); E2D_ERROR("获取 RHI 上下文失败");
device_->shutdown(); device_->shutdown();
device_.reset(); device_.reset();
return; return;
} }
// 注意context 已在 GLDevice::initialize() 中初始化,这里不需要再次初始化
// 初始化上下文
if (!context_->initialize()) {
E2D_LOG_ERROR("初始化 RHI 上下文失败");
device_->shutdown();
device_.reset();
context_ = nullptr;
return;
}
initialized_ = true; initialized_ = true;
E2D_LOG_INFO("RHIModule initialized successfully (backend: {})", E2D_INFO("RHI模块 初始化成功 (后端:{})", device_->getBackendName());
device_->getBackendName());
// RHI 初始化完成,再次触发 OnShow 事件通知其他模块 // RHI 初始化完成,再次触发 OnShow 事件通知其他模块
// 这样 RendererModule 等依赖 RHI 的模块可以完成初始化 // 这样 RendererModule 等依赖 RHI 的模块可以完成初始化
@ -96,7 +87,7 @@ void RHIModule::onWindowShow() {
} }
void RHIModule::shutdown() { void RHIModule::shutdown() {
E2D_LOG_INFO("Shutting down RHIModule..."); E2D_INFO("正在关闭 RHI模块...");
// 清理事件监听器 // 清理事件监听器
onShowListener_.reset(); onShowListener_.reset();
@ -113,14 +104,14 @@ void RHIModule::shutdown() {
initialized_ = false; initialized_ = false;
E2D_LOG_INFO("RHIModule shutdown complete"); E2D_INFO("RHI模块 关闭完成");
} }
RHIModule *RHIModule::get() { return g_rhiModule; } RHIModule *RHIModule::get() { return g_rhiModule; }
std::unique_ptr<RHIBuffer> RHIModule::createBuffer(const BufferDesc &desc) { std::unique_ptr<RHIBuffer> RHIModule::createBuffer(const BufferDesc &desc) {
if (!device_) { if (!device_) {
E2D_LOG_ERROR("Cannot create buffer: RHI device not initialized"); E2D_ERROR("无法创建缓冲区RHI 设备未初始化");
return nullptr; return nullptr;
} }
return device_->createBuffer(desc); return device_->createBuffer(desc);
@ -128,7 +119,7 @@ std::unique_ptr<RHIBuffer> RHIModule::createBuffer(const BufferDesc &desc) {
std::unique_ptr<RHITexture> RHIModule::createTexture(const TextureDesc &desc) { std::unique_ptr<RHITexture> RHIModule::createTexture(const TextureDesc &desc) {
if (!device_) { if (!device_) {
E2D_LOG_ERROR("无法创建纹理: RHI 设备未初始化"); E2D_ERROR("无法创建纹理: RHI 设备未初始化");
return nullptr; return nullptr;
} }
return device_->createTexture(desc); return device_->createTexture(desc);
@ -136,7 +127,7 @@ std::unique_ptr<RHITexture> RHIModule::createTexture(const TextureDesc &desc) {
std::unique_ptr<RHIShader> RHIModule::createShader(const ShaderDesc &desc) { std::unique_ptr<RHIShader> RHIModule::createShader(const ShaderDesc &desc) {
if (!device_) { if (!device_) {
E2D_LOG_ERROR("无法创建着色器: RHI 设备未初始化"); E2D_ERROR("无法创建着色器: RHI 设备未初始化");
return nullptr; return nullptr;
} }
return device_->createShader(desc); return device_->createShader(desc);
@ -145,7 +136,7 @@ std::unique_ptr<RHIShader> RHIModule::createShader(const ShaderDesc &desc) {
std::unique_ptr<RHIPipeline> std::unique_ptr<RHIPipeline>
RHIModule::createPipeline(const PipelineDesc &desc) { RHIModule::createPipeline(const PipelineDesc &desc) {
if (!device_) { if (!device_) {
E2D_LOG_ERROR("无法创建管线: RHI 设备未初始化"); E2D_ERROR("无法创建管线: RHI 设备未初始化");
return nullptr; return nullptr;
} }
return device_->createPipeline(desc); return device_->createPipeline(desc);
@ -154,7 +145,7 @@ RHIModule::createPipeline(const PipelineDesc &desc) {
std::unique_ptr<RHIFramebuffer> std::unique_ptr<RHIFramebuffer>
RHIModule::createFramebuffer(const RenderPassDesc &desc) { RHIModule::createFramebuffer(const RenderPassDesc &desc) {
if (!device_) { if (!device_) {
E2D_LOG_ERROR("无法创建帧缓冲区: RHI 设备未初始化"); E2D_ERROR("无法创建帧缓冲区: RHI 设备未初始化");
return nullptr; return nullptr;
} }
return device_->createFramebuffer(desc); return device_->createFramebuffer(desc);
@ -162,7 +153,7 @@ RHIModule::createFramebuffer(const RenderPassDesc &desc) {
std::unique_ptr<RHICommandList> RHIModule::createCommandList() { std::unique_ptr<RHICommandList> RHIModule::createCommandList() {
if (!device_) { if (!device_) {
E2D_LOG_ERROR("无法创建命令列表: RHI 设备未初始化"); E2D_ERROR("无法创建命令列表: RHI 设备未初始化");
return nullptr; return nullptr;
} }
return device_->createCommandList(); return device_->createCommandList();

View File

@ -35,13 +35,13 @@ bool Shader::loadFromSourceWithLayout(const std::string &vsSource,
// 获取 RHI 设备 // 获取 RHI 设备
auto *rhiModule = RHIModule::get(); auto *rhiModule = RHIModule::get();
if (!rhiModule) { if (!rhiModule) {
E2D_LOG_ERROR("RHI 模块不可用"); E2D_ERROR("RHI 模块不可用");
return false; return false;
} }
auto *device = rhiModule->getDevice(); auto *device = rhiModule->getDevice();
if (!device) { if (!device) {
E2D_LOG_ERROR("RHI 设备不可用"); E2D_ERROR("RHI 设备不可用");
return false; return false;
} }
@ -57,7 +57,7 @@ bool Shader::loadFromSourceWithLayout(const std::string &vsSource,
// 创建着色器 // 创建着色器
auto shader = device->createShader(shaderDesc); auto shader = device->createShader(shaderDesc);
if (!shader) { if (!shader) {
E2D_LOG_ERROR("创建着色器失败"); E2D_ERROR("创建着色器失败");
return false; return false;
} }
@ -76,7 +76,7 @@ bool Shader::loadFromSourceWithLayout(const std::string &vsSource,
// 创建管线 // 创建管线
auto pipeline = device->createPipeline(pipelineDesc); auto pipeline = device->createPipeline(pipelineDesc);
if (!pipeline) { if (!pipeline) {
E2D_LOG_ERROR("创建管线失败"); E2D_ERROR("创建管线失败");
handle_ = ShaderHandle(); handle_ = ShaderHandle();
return false; return false;
} }
@ -84,7 +84,7 @@ bool Shader::loadFromSourceWithLayout(const std::string &vsSource,
// 获取管线句柄 // 获取管线句柄
pipeline_ = PipelineHandle(pipeline.release()); pipeline_ = PipelineHandle(pipeline.release());
E2D_LOG_INFO("着色器创建成功"); E2D_INFO("着色器创建成功");
return true; return true;
} }
@ -127,13 +127,13 @@ bool Shader::reloadFromSourceWithLayout(const std::string &vsSource,
// 获取 RHI 设备 // 获取 RHI 设备
auto *rhiModule = RHIModule::get(); auto *rhiModule = RHIModule::get();
if (!rhiModule) { if (!rhiModule) {
E2D_LOG_ERROR("RHI 模块不可用"); E2D_ERROR("RHI 模块不可用");
return false; return false;
} }
auto *device = rhiModule->getDevice(); auto *device = rhiModule->getDevice();
if (!device) { if (!device) {
E2D_LOG_ERROR("RHI 设备不可用"); E2D_ERROR("RHI 设备不可用");
return false; return false;
} }
@ -149,7 +149,7 @@ bool Shader::reloadFromSourceWithLayout(const std::string &vsSource,
// 创建着色器 // 创建着色器
auto shader = device->createShader(shaderDesc); auto shader = device->createShader(shaderDesc);
if (!shader) { if (!shader) {
E2D_LOG_ERROR("重载时创建着色器失败"); E2D_ERROR("重载时创建着色器失败");
return false; return false;
} }
@ -168,7 +168,7 @@ bool Shader::reloadFromSourceWithLayout(const std::string &vsSource,
// 创建管线 // 创建管线
auto pipeline = device->createPipeline(pipelineDesc); auto pipeline = device->createPipeline(pipelineDesc);
if (!pipeline) { if (!pipeline) {
E2D_LOG_ERROR("重载时创建管线失败"); E2D_ERROR("重载时创建管线失败");
handle_ = ShaderHandle(); handle_ = ShaderHandle();
return false; return false;
} }
@ -176,7 +176,7 @@ bool Shader::reloadFromSourceWithLayout(const std::string &vsSource,
// 获取管线句柄 // 获取管线句柄
pipeline_ = PipelineHandle(pipeline.release()); pipeline_ = PipelineHandle(pipeline.release());
E2D_LOG_INFO("着色器重载成功"); E2D_INFO("着色器重载成功");
return true; return true;
} }

View File

@ -1,5 +1,5 @@
#include <renderer/texture.h>
#include <renderer/rhi_module.h> #include <renderer/rhi_module.h>
#include <renderer/texture.h>
#include <utils/logger.h> #include <utils/logger.h>
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h> #include <stb/stb_image.h>
@ -14,38 +14,50 @@ Texture::~Texture() {
handle_ = TextureHandle(); handle_ = TextureHandle();
} }
bool Texture::loadFromFile(const std::string& path) { bool Texture::loadFromFile(const std::string &path) {
// 加载图片 // 加载图片
int channels; int channels;
stbi_set_flip_vertically_on_load(true); stbi_set_flip_vertically_on_load(true);
unsigned char* data = stbi_load(path.c_str(), &width_, &height_, &channels, 0); unsigned char *data =
stbi_load(path.c_str(), &width_, &height_, &channels, 0);
if (!data) { if (!data) {
E2D_LOG_ERROR("加载纹理失败: {}", path); E2D_ERROR("加载纹理失败: {}", path);
return false; return false;
} }
// 根据通道数确定格式 // 根据通道数确定格式
TextureFormat format; TextureFormat format;
switch (channels) { switch (channels) {
case 1: format = TextureFormat::R8; break; case 1:
case 2: format = TextureFormat::RG8; break; format = TextureFormat::R8;
case 3: format = TextureFormat::RGB8; break; break;
case 4: format = TextureFormat::RGBA8; break; case 2:
default: format = TextureFormat::RGBA8; break; 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); bool result = loadFromMemory(data, width_, height_, format);
stbi_image_free(data); stbi_image_free(data);
if (result) { if (result) {
E2D_LOG_DEBUG("纹理已加载: {} ({}x{})", path, width_, height_); E2D_DEBUG("纹理已加载: {} ({}x{})", path, width_, height_);
} }
return result; return result;
} }
bool Texture::loadFromMemory(const uint8_t* data, int width, int height, TextureFormat format) { bool Texture::loadFromMemory(const uint8_t *data, int width, int height,
TextureFormat format) {
// 释放旧纹理 // 释放旧纹理
handle_ = TextureHandle(); handle_ = TextureHandle();
@ -54,15 +66,15 @@ bool Texture::loadFromMemory(const uint8_t* data, int width, int height, Texture
format_ = format; format_ = format;
// 获取 RHI 设备 // 获取 RHI 设备
auto* rhiModule = RHIModule::get(); auto *rhiModule = RHIModule::get();
if (!rhiModule) { if (!rhiModule) {
E2D_LOG_ERROR("RHI 模块不可用"); E2D_ERROR("RHI 模块不可用");
return false; return false;
} }
auto* device = rhiModule->getDevice(); auto *device = rhiModule->getDevice();
if (!device) { if (!device) {
E2D_LOG_ERROR("RHI 设备不可用"); E2D_ERROR("RHI 设备不可用");
return false; return false;
} }
@ -76,7 +88,7 @@ bool Texture::loadFromMemory(const uint8_t* data, int width, int height, Texture
// 创建 RHI 纹理 // 创建 RHI 纹理
auto texture = device->createTexture(desc); auto texture = device->createTexture(desc);
if (!texture) { if (!texture) {
E2D_LOG_ERROR("创建 RHI 纹理失败"); E2D_ERROR("创建 RHI 纹理失败");
return false; return false;
} }
@ -84,7 +96,8 @@ bool Texture::loadFromMemory(const uint8_t* data, int width, int height, Texture
if (data) { if (data) {
// 注意update 方法的参数需要根据实际 RHI 接口调整 // 注意update 方法的参数需要根据实际 RHI 接口调整
// 这里假设 update 接受数据指针 // 这里假设 update 接受数据指针
texture->update(data, static_cast<size_t>(width * height * getBytesPerPixel(format))); texture->update(
data, static_cast<size_t>(width * height * getBytesPerPixel(format)));
// 生成 mipmap // 生成 mipmap
// 注意generateMipmap 方法需要在 RHI 接口中实现 // 注意generateMipmap 方法需要在 RHI 接口中实现
} }
@ -104,15 +117,15 @@ bool Texture::create(int width, int height, TextureFormat format) {
format_ = format; format_ = format;
// 获取 RHI 设备 // 获取 RHI 设备
auto* rhiModule = RHIModule::get(); auto *rhiModule = RHIModule::get();
if (!rhiModule) { if (!rhiModule) {
E2D_LOG_ERROR("RHI 模块不可用"); E2D_ERROR("RHI 模块不可用");
return false; return false;
} }
auto* device = rhiModule->getDevice(); auto *device = rhiModule->getDevice();
if (!device) { if (!device) {
E2D_LOG_ERROR("RHI 设备不可用"); E2D_ERROR("RHI 设备不可用");
return false; return false;
} }
@ -126,7 +139,7 @@ bool Texture::create(int width, int height, TextureFormat format) {
// 创建 RHI 纹理 // 创建 RHI 纹理
auto texture = device->createTexture(desc); auto texture = device->createTexture(desc);
if (!texture) { if (!texture) {
E2D_LOG_ERROR("创建 RHI 纹理失败"); E2D_ERROR("创建 RHI 纹理失败");
return false; return false;
} }
@ -136,53 +149,65 @@ bool Texture::create(int width, int height, TextureFormat format) {
return true; return true;
} }
bool Texture::reloadFromFile(const std::string& path) { bool Texture::reloadFromFile(const std::string &path) {
// 加载图片 // 加载图片
int channels; int channels;
stbi_set_flip_vertically_on_load(true); stbi_set_flip_vertically_on_load(true);
unsigned char* data = stbi_load(path.c_str(), &width_, &height_, &channels, 0); unsigned char *data =
stbi_load(path.c_str(), &width_, &height_, &channels, 0);
if (!data) { if (!data) {
E2D_LOG_ERROR("重载纹理失败: {}", path); E2D_ERROR("重载纹理失败: {}", path);
return false; return false;
} }
// 根据通道数确定格式 // 根据通道数确定格式
TextureFormat format; TextureFormat format;
switch (channels) { switch (channels) {
case 1: format = TextureFormat::R8; break; case 1:
case 2: format = TextureFormat::RG8; break; format = TextureFormat::R8;
case 3: format = TextureFormat::RGB8; break; break;
case 4: format = TextureFormat::RGBA8; break; case 2:
default: format = TextureFormat::RGBA8; break; 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); bool result = reloadFromMemory(data, width_, height_, format);
stbi_image_free(data); stbi_image_free(data);
if (result) { if (result) {
E2D_LOG_INFO("纹理已重载: {} ({}x{})", path, width_, height_); E2D_INFO("纹理已重载: {} ({}x{})", path, width_, height_);
} }
return result; return result;
} }
bool Texture::reloadFromMemory(const uint8_t* data, int width, int height, TextureFormat format) { bool Texture::reloadFromMemory(const uint8_t *data, int width, int height,
TextureFormat format) {
// 更新尺寸和格式 // 更新尺寸和格式
width_ = width; width_ = width;
height_ = height; height_ = height;
format_ = format; format_ = format;
// 获取 RHI 设备 // 获取 RHI 设备
auto* rhiModule = RHIModule::get(); auto *rhiModule = RHIModule::get();
if (!rhiModule) { if (!rhiModule) {
E2D_LOG_ERROR("RHI 模块不可用"); E2D_ERROR("RHI 模块不可用");
return false; return false;
} }
auto* device = rhiModule->getDevice(); auto *device = rhiModule->getDevice();
if (!device) { if (!device) {
E2D_LOG_ERROR("RHI 设备不可用"); E2D_ERROR("RHI 设备不可用");
return false; return false;
} }
@ -196,13 +221,14 @@ bool Texture::reloadFromMemory(const uint8_t* data, int width, int height, Textu
// 创建新的 RHI 纹理 // 创建新的 RHI 纹理
auto texture = device->createTexture(desc); auto texture = device->createTexture(desc);
if (!texture) { if (!texture) {
E2D_LOG_ERROR("重载时创建 RHI 纹理失败"); E2D_ERROR("重载时创建 RHI 纹理失败");
return false; return false;
} }
// 上传纹理数据 // 上传纹理数据
if (data) { if (data) {
texture->update(data, static_cast<size_t>(width * height * getBytesPerPixel(format))); texture->update(
data, static_cast<size_t>(width * height * getBytesPerPixel(format)));
} }
// 替换旧的纹理句柄 // 替换旧的纹理句柄
@ -214,17 +240,27 @@ bool Texture::reloadFromMemory(const uint8_t* data, int width, int height, Textu
// 辅助函数:获取每个像素的字节数 // 辅助函数:获取每个像素的字节数
uint32_t Texture::getBytesPerPixel(TextureFormat format) { uint32_t Texture::getBytesPerPixel(TextureFormat format) {
switch (format) { switch (format) {
case TextureFormat::R8: return 1; case TextureFormat::R8:
case TextureFormat::RG8: return 2; return 1;
case TextureFormat::RGB8: return 3; case TextureFormat::RG8:
return 2;
case TextureFormat::RGB8:
return 3;
case TextureFormat::RGBA8: case TextureFormat::RGBA8:
case TextureFormat::RGBA8_SRGB: return 4; case TextureFormat::RGBA8_SRGB:
case TextureFormat::Depth16: return 2; return 4;
case TextureFormat::Depth24: return 3; case TextureFormat::Depth16:
case TextureFormat::Depth32F: return 4; return 2;
case TextureFormat::Depth24Stencil8: return 4; case TextureFormat::Depth24:
case TextureFormat::Depth32FStencil8: return 5; return 3;
default: return 4; case TextureFormat::Depth32F:
return 4;
case TextureFormat::Depth24Stencil8:
return 4;
case TextureFormat::Depth32FStencil8:
return 5;
default:
return 4;
} }
} }

View File

@ -1,7 +1,7 @@
#include <renderer/texture_atlas.h>
#include <utils/logger.h>
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <renderer/texture_atlas.h>
#include <utils/logger.h>
namespace extra2d { namespace extra2d {
@ -11,25 +11,21 @@ namespace extra2d {
TextureAtlas::TextureAtlas() = default; TextureAtlas::TextureAtlas() = default;
TextureAtlas::~TextureAtlas() { TextureAtlas::~TextureAtlas() { shutdown(); }
shutdown();
}
TextureAtlas::TextureAtlas(TextureAtlas&& other) noexcept TextureAtlas::TextureAtlas(TextureAtlas &&other) noexcept
: width_(other.width_) : width_(other.width_), height_(other.height_),
, height_(other.height_) atlasTexture_(std::move(other.atlasTexture_)),
, atlasTexture_(std::move(other.atlasTexture_)) regions_(std::move(other.regions_)),
, regions_(std::move(other.regions_)) pendingTextures_(std::move(other.pendingTextures_)),
, pendingTextures_(std::move(other.pendingTextures_)) packContext_(std::move(other.packContext_)),
, packContext_(std::move(other.packContext_)) packNodes_(std::move(other.packNodes_)), finalized_(other.finalized_) {
, packNodes_(std::move(other.packNodes_))
, finalized_(other.finalized_) {
other.width_ = 0; other.width_ = 0;
other.height_ = 0; other.height_ = 0;
other.finalized_ = false; other.finalized_ = false;
} }
TextureAtlas& TextureAtlas::operator=(TextureAtlas&& other) noexcept { TextureAtlas &TextureAtlas::operator=(TextureAtlas &&other) noexcept {
if (this != &other) { if (this != &other) {
shutdown(); shutdown();
@ -53,7 +49,7 @@ bool TextureAtlas::initialize(int width, int height) {
shutdown(); shutdown();
if (width <= 0 || height <= 0) { if (width <= 0 || height <= 0) {
E2D_LOG_ERROR("TextureAtlas::initialize: 无效的尺寸 {}x{}", width, height); E2D_ERROR("TextureAtlas::initialize: 无效的尺寸 {}x{}", width, height);
return false; return false;
} }
@ -63,9 +59,10 @@ bool TextureAtlas::initialize(int width, int height) {
// 初始化 stb_rect_pack // 初始化 stb_rect_pack
packContext_ = std::make_unique<stbrp_context>(); packContext_ = std::make_unique<stbrp_context>();
packNodes_.resize(width); packNodes_.resize(width);
stbrp_init_target(packContext_.get(), width, height, packNodes_.data(), width); stbrp_init_target(packContext_.get(), width, height, packNodes_.data(),
width);
E2D_LOG_DEBUG("纹理图集已初始化: {}x{}", width, height); E2D_DEBUG("纹理图集已初始化: {}x{}", width, height);
return true; return true;
} }
@ -80,19 +77,19 @@ void TextureAtlas::shutdown() {
finalized_ = false; finalized_ = false;
} }
bool TextureAtlas::addTexture(const std::string& name, Ptr<Texture> texture) { bool TextureAtlas::addTexture(const std::string &name, Ptr<Texture> texture) {
if (finalized_) { if (finalized_) {
E2D_LOG_WARN("TextureAtlas::addTexture: 无法向已完成的图集添加纹理"); E2D_WARN("TextureAtlas::addTexture: 无法向已完成的图集添加纹理");
return false; return false;
} }
if (!texture) { if (!texture) {
E2D_LOG_WARN("TextureAtlas::addTexture: 纹理为空"); E2D_WARN("TextureAtlas::addTexture: 纹理为空");
return false; return false;
} }
if (regions_.find(name) != regions_.end()) { if (regions_.find(name) != regions_.end()) {
E2D_LOG_WARN("TextureAtlas::addTexture: 纹理 '{}' 已存在", name); E2D_WARN("TextureAtlas::addTexture: 纹理 '{}' 已存在", name);
return false; return false;
} }
@ -101,13 +98,14 @@ bool TextureAtlas::addTexture(const std::string& name, Ptr<Texture> texture) {
int texHeight = static_cast<int>(texture->getHeight()); int texHeight = static_cast<int>(texture->getHeight());
if (texWidth <= 0 || texHeight <= 0) { if (texWidth <= 0 || texHeight <= 0) {
E2D_LOG_WARN("TextureAtlas::addTexture: 无效的纹理尺寸 {}x{}", texWidth, texHeight); E2D_WARN("TextureAtlas::addTexture: 无效的纹理尺寸 {}x{}", texWidth,
texHeight);
return false; return false;
} }
// 检查纹理是否适合图集 // 检查纹理是否适合图集
if (texWidth > width_ || texHeight > height_) { if (texWidth > width_ || texHeight > height_) {
E2D_LOG_WARN("TextureAtlas::addTexture: 纹理 {}x{} 太大,无法放入图集 {}x{}", E2D_WARN("TextureAtlas::addTexture: 纹理 {}x{} 太大,无法放入图集 {}x{}",
texWidth, texHeight, width_, height_); texWidth, texHeight, width_, height_);
return false; return false;
} }
@ -129,29 +127,30 @@ bool TextureAtlas::addTexture(const std::string& name, Ptr<Texture> texture) {
pendingTextures_.push_back(std::move(pending)); pendingTextures_.push_back(std::move(pending));
E2D_LOG_DEBUG("纹理图集: 已添加纹理 '{}' ({}x{})", name, texWidth, texHeight); E2D_DEBUG("纹理图集: 已添加纹理 '{}' ({}x{})", name, texWidth, texHeight);
return true; 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) { int width, int height, TextureFormat format) {
if (finalized_) { if (finalized_) {
E2D_LOG_WARN("TextureAtlas::addTextureData: 无法向已完成的图集添加纹理"); E2D_WARN("TextureAtlas::addTextureData: 无法向已完成的图集添加纹理");
return false; return false;
} }
if (!data || width <= 0 || height <= 0) { if (!data || width <= 0 || height <= 0) {
E2D_LOG_WARN("TextureAtlas::addTextureData: 无效参数"); E2D_WARN("TextureAtlas::addTextureData: 无效参数");
return false; return false;
} }
if (regions_.find(name) != regions_.end()) { if (regions_.find(name) != regions_.end()) {
E2D_LOG_WARN("TextureAtlas::addTextureData: 纹理 '{}' 已存在", name); E2D_WARN("TextureAtlas::addTextureData: 纹理 '{}' 已存在", name);
return false; return false;
} }
if (width > width_ || height > height_) { if (width > width_ || height > height_) {
E2D_LOG_WARN("TextureAtlas::addTextureData: 纹理 {}x{} 太大,无法放入图集 {}x{}", E2D_WARN(
"TextureAtlas::addTextureData: 纹理 {}x{} 太大,无法放入图集 {}x{}",
width, height, width_, height_); width, height, width_, height_);
return false; return false;
} }
@ -170,7 +169,7 @@ bool TextureAtlas::addTextureData(const std::string& name, const uint8_t* data,
pendingTextures_.push_back(std::move(pending)); pendingTextures_.push_back(std::move(pending));
E2D_LOG_DEBUG("纹理图集: 已添加纹理数据 '{}' ({}x{})", name, width, height); E2D_DEBUG("纹理图集: 已添加纹理数据 '{}' ({}x{})", name, width, height);
return true; return true;
} }
@ -180,7 +179,7 @@ bool TextureAtlas::finalize() {
} }
if (pendingTextures_.empty()) { if (pendingTextures_.empty()) {
E2D_LOG_WARN("TextureAtlas::finalize: 没有要打包的纹理"); E2D_WARN("TextureAtlas::finalize: 没有要打包的纹理");
return false; return false;
} }
@ -200,10 +199,11 @@ bool TextureAtlas::finalize() {
} }
// 执行打包 // 执行打包
int result = stbrp_pack_rects(packContext_.get(), rects.data(), static_cast<int>(rects.size())); int result = stbrp_pack_rects(packContext_.get(), rects.data(),
static_cast<int>(rects.size()));
if (!result) { if (!result) {
E2D_LOG_ERROR("TextureAtlas::finalize: 打包所有纹理失败"); E2D_ERROR("TextureAtlas::finalize: 打包所有纹理失败");
return false; return false;
} }
@ -211,13 +211,13 @@ bool TextureAtlas::finalize() {
std::vector<uint8_t> atlasData(width_ * height_ * 4, 0); // RGBA 黑色背景 std::vector<uint8_t> atlasData(width_ * height_ * 4, 0); // RGBA 黑色背景
// 处理打包结果 // 处理打包结果
for (const auto& rect : rects) { for (const auto &rect : rects) {
if (!rect.was_packed) { if (!rect.was_packed) {
E2D_LOG_WARN("TextureAtlas::finalize: 纹理 {} 未被打包", rect.id); E2D_WARN("TextureAtlas::finalize: 纹理 {} 未被打包", rect.id);
continue; continue;
} }
const auto& pending = pendingTextures_[rect.id]; const auto &pending = pendingTextures_[rect.id];
// 创建区域信息 // 创建区域信息
AtlasRegion region; AtlasRegion region;
@ -246,14 +246,15 @@ bool TextureAtlas::finalize() {
} }
} }
E2D_LOG_DEBUG("纹理图集: 已打包 '{}' 在 ({}, {}) 尺寸 {}x{}", E2D_DEBUG("纹理图集: 已打包 '{}' 在 ({}, {}) 尺寸 {}x{}", pending.name,
pending.name, rect.x, rect.y, rect.w, rect.h); rect.x, rect.y, rect.w, rect.h);
} }
// 创建图集纹理 // 创建图集纹理
atlasTexture_ = makePtr<Texture>(); atlasTexture_ = makePtr<Texture>();
if (!atlasTexture_->loadFromMemory(atlasData.data(), width_, height_, TextureFormat::RGBA8)) { if (!atlasTexture_->loadFromMemory(atlasData.data(), width_, height_,
E2D_LOG_ERROR("TextureAtlas::finalize: 创建图集纹理失败"); TextureFormat::RGBA8)) {
E2D_ERROR("TextureAtlas::finalize: 创建图集纹理失败");
return false; return false;
} }
@ -261,14 +262,14 @@ bool TextureAtlas::finalize() {
pendingTextures_.clear(); pendingTextures_.clear();
finalized_ = true; finalized_ = true;
E2D_LOG_INFO("纹理图集完成: {} 个纹理打包到 {}x{} 图集 (使用率 {}%)", E2D_INFO("纹理图集完成: {} 个纹理打包到 {}x{} 图集 (使用率 {}%)",
regions_.size(), width_, height_, regions_.size(), width_, height_,
static_cast<int>(getUsageRatio() * 100)); static_cast<int>(getUsageRatio() * 100));
return true; return true;
} }
const AtlasRegion* TextureAtlas::getRegion(const std::string& name) const { const AtlasRegion *TextureAtlas::getRegion(const std::string &name) const {
auto it = regions_.find(name); auto it = regions_.find(name);
if (it != regions_.end()) { if (it != regions_.end()) {
return &it->second; return &it->second;
@ -276,15 +277,15 @@ const AtlasRegion* TextureAtlas::getRegion(const std::string& name) const {
return nullptr; return nullptr;
} }
Rect TextureAtlas::getUVRect(const std::string& name) const { Rect TextureAtlas::getUVRect(const std::string &name) const {
const AtlasRegion* region = getRegion(name); const AtlasRegion *region = getRegion(name);
if (region) { if (region) {
return region->getUVRect(width_, height_); return region->getUVRect(width_, height_);
} }
return Rect(0.0f, 0.0f, 1.0f, 1.0f); return Rect(0.0f, 0.0f, 1.0f, 1.0f);
} }
bool TextureAtlas::hasTexture(const std::string& name) const { bool TextureAtlas::hasTexture(const std::string &name) const {
return regions_.find(name) != regions_.end(); return regions_.find(name) != regions_.end();
} }
@ -294,7 +295,7 @@ float TextureAtlas::getUsageRatio() const {
} }
int totalArea = 0; int totalArea = 0;
for (const auto& pair : regions_) { for (const auto &pair : regions_) {
totalArea += pair.second.width * pair.second.height; totalArea += pair.second.width * pair.second.height;
} }
@ -307,7 +308,7 @@ float TextureAtlas::getUsageRatio() const {
Ptr<TextureAtlas> AtlasBuilder::build() { Ptr<TextureAtlas> AtlasBuilder::build() {
if (textures_.empty()) { if (textures_.empty()) {
E2D_LOG_WARN("AtlasBuilder::build: No textures to build"); E2D_WARN("AtlasBuilder::build: No textures to build");
return nullptr; return nullptr;
} }
@ -316,7 +317,7 @@ Ptr<TextureAtlas> AtlasBuilder::build() {
return nullptr; return nullptr;
} }
for (const auto& pair : textures_) { for (const auto &pair : textures_) {
atlas->addTexture(pair.first, pair.second); atlas->addTexture(pair.first, pair.second);
} }
@ -329,7 +330,7 @@ Ptr<TextureAtlas> AtlasBuilder::build() {
Ptr<TextureAtlas> AtlasBuilder::buildAuto() { Ptr<TextureAtlas> AtlasBuilder::buildAuto() {
if (textures_.empty()) { if (textures_.empty()) {
E2D_LOG_WARN("AtlasBuilder::buildAuto: No textures to build"); E2D_WARN("AtlasBuilder::buildAuto: No textures to build");
return nullptr; return nullptr;
} }
@ -338,7 +339,7 @@ Ptr<TextureAtlas> AtlasBuilder::buildAuto() {
int maxWidth = 0; int maxWidth = 0;
int maxHeight = 0; int maxHeight = 0;
for (const auto& pair : textures_) { for (const auto &pair : textures_) {
if (pair.second) { if (pair.second) {
int w = static_cast<int>(pair.second->getWidth()); int w = static_cast<int>(pair.second->getWidth());
int h = static_cast<int>(pair.second->getHeight()); int h = static_cast<int>(pair.second->getHeight());
@ -350,10 +351,11 @@ Ptr<TextureAtlas> AtlasBuilder::buildAuto() {
// 选择合适的大小2 的幂) // 选择合适的大小2 的幂)
int atlasSize = 64; int atlasSize = 64;
while (atlasSize < maxWidth || atlasSize < maxHeight || atlasSize * atlasSize < totalArea * 1.5f) { while (atlasSize < maxWidth || atlasSize < maxHeight ||
atlasSize * atlasSize < totalArea * 1.5f) {
atlasSize *= 2; atlasSize *= 2;
if (atlasSize > 8192) { if (atlasSize > 8192) {
E2D_LOG_ERROR("AtlasBuilder::buildAuto: Textures too large for atlas"); E2D_ERROR("AtlasBuilder::buildAuto: Textures too large for atlas");
return nullptr; return nullptr;
} }
} }

View File

@ -15,13 +15,13 @@ bool UniformBuffer::create(uint32_t size, uint32_t binding) {
// 获取 RHI 设备 // 获取 RHI 设备
auto *rhiModule = RHIModule::get(); auto *rhiModule = RHIModule::get();
if (!rhiModule) { if (!rhiModule) {
E2D_LOG_ERROR("RHI 模块不可用"); E2D_ERROR("RHI 模块不可用");
return false; return false;
} }
auto *device = rhiModule->getDevice(); auto *device = rhiModule->getDevice();
if (!device) { if (!device) {
E2D_LOG_ERROR("RHI 设备不可用"); E2D_ERROR("RHI 设备不可用");
return false; return false;
} }
@ -34,14 +34,14 @@ bool UniformBuffer::create(uint32_t size, uint32_t binding) {
// 创建缓冲区 // 创建缓冲区
auto buffer = device->createBuffer(desc); auto buffer = device->createBuffer(desc);
if (!buffer) { if (!buffer) {
E2D_LOG_ERROR("创建 uniform 缓冲区失败"); E2D_ERROR("创建 uniform 缓冲区失败");
return false; return false;
} }
// 获取缓冲区句柄 // 获取缓冲区句柄
handle_ = BufferHandle(buffer.release()); handle_ = BufferHandle(buffer.release());
E2D_LOG_DEBUG("UBO 已创建: 大小={}, 绑定槽={}", size, binding); E2D_DEBUG("UBO 已创建: 大小={}, 绑定槽={}", size, binding);
return true; return true;
} }
@ -57,8 +57,8 @@ void UniformBuffer::update(const void *data, uint32_t size, uint32_t offset) {
return; return;
if (offset + size > size_) { if (offset + size > size_) {
E2D_LOG_WARN("UBO 更新超出边界: 偏移={}, 大小={}, 缓冲区大小={}", E2D_WARN("UBO 更新超出边界: 偏移={}, 大小={}, 缓冲区大小={}", offset, size,
offset, size, size_); size_);
return; return;
} }
@ -123,7 +123,7 @@ bool UniformBufferManager::initialize() {
globalUBOs_[i] = std::make_unique<UniformBuffer>(); globalUBOs_[i] = std::make_unique<UniformBuffer>();
if (!globalUBOs_[i]->create(UniformBufferManager::GLOBAL_UBO_SIZE, if (!globalUBOs_[i]->create(UniformBufferManager::GLOBAL_UBO_SIZE,
UniformBufferManager::GLOBAL_UBO_BINDING)) { UniformBufferManager::GLOBAL_UBO_BINDING)) {
E2D_LOG_ERROR("创建全局 UBO {} 失败", i); E2D_ERROR("创建全局 UBO {} 失败", i);
return false; return false;
} }
} }
@ -134,13 +134,13 @@ bool UniformBufferManager::initialize() {
// 预分配材质 UBO CPU 缓冲区 // 预分配材质 UBO CPU 缓冲区
materialUBOBuffer_.resize(MATERIAL_UBO_BUFFER_SIZE); materialUBOBuffer_.resize(MATERIAL_UBO_BUFFER_SIZE);
E2D_LOG_INFO("UniformBufferManager 已初始化,使用双缓冲"); E2D_INFO("UniformBufferManager 已初始化,使用双缓冲");
return true; return true;
} }
void UniformBufferManager::shutdown() { void UniformBufferManager::shutdown() {
materialUBOPool_.clear(); materialUBOPool_.clear();
for (auto& ubo : globalUBOs_) { for (auto &ubo : globalUBOs_) {
ubo.reset(); ubo.reset();
} }
currentUBOIndex_ = 0; currentUBOIndex_ = 0;
@ -148,7 +148,7 @@ void UniformBufferManager::shutdown() {
materialUBOBufferOffset_ = 0; materialUBOBufferOffset_ = 0;
currentMaterialUBO_ = nullptr; currentMaterialUBO_ = nullptr;
E2D_LOG_INFO("UniformBufferManager 已关闭"); E2D_INFO("UniformBufferManager 已关闭");
} }
UniformBuffer *UniformBufferManager::getGlobalUBO(uint32_t frameIndex) { UniformBuffer *UniformBufferManager::getGlobalUBO(uint32_t frameIndex) {
@ -169,7 +169,7 @@ UniformBuffer *UniformBufferManager::acquireMaterialUBO(uint32_t size) {
// 需要创建新的 UBO // 需要创建新的 UBO
auto ubo = std::make_unique<UniformBuffer>(); auto ubo = std::make_unique<UniformBuffer>();
if (!ubo->create(size, UniformBufferManager::MATERIAL_UBO_BINDING)) { if (!ubo->create(size, UniformBufferManager::MATERIAL_UBO_BINDING)) {
E2D_LOG_ERROR("创建材质 UBO 失败"); E2D_ERROR("创建材质 UBO 失败");
return nullptr; return nullptr;
} }
@ -186,7 +186,8 @@ void UniformBufferManager::resetMaterialUBOs() {
currentMaterialUBO_ = nullptr; 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 // 使用双缓冲更新全局 UBO
size_t index = frameIndex % 2; size_t index = frameIndex % 2;
if (globalUBOs_[index]) { 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()) { if (!data || size == 0 || offset + size > materialUBOBuffer_.size()) {
E2D_LOG_WARN("无效的批量更新参数"); E2D_WARN("无效的批量更新参数");
return; return;
} }
@ -211,7 +214,8 @@ void UniformBufferManager::flushMaterialUBO() {
} }
// 一次性将 CPU 缓冲区数据更新到 GPU // 一次性将 CPU 缓冲区数据更新到 GPU
currentMaterialUBO_->update(materialUBOBuffer_.data(), materialUBOBufferOffset_, 0); currentMaterialUBO_->update(materialUBOBuffer_.data(),
materialUBOBufferOffset_, 0);
materialUBOBufferOffset_ = 0; materialUBOBufferOffset_ = 0;
} }

View File

@ -47,8 +47,8 @@ void CameraComponent::setOrtho(float left, float right, float bottom, float top,
far_ = far; far_ = far;
markProjDirty(); markProjDirty();
E2D_LOG_DEBUG("正交投影已设置: 左={}, 右={}, 下={}, 上={}, 近={}, 远={}", E2D_DEBUG("正交投影已设置: 左={}, 右={}, 下={}, 上={}, 近={}, 远={}", left,
left, right, bottom, top, near, far); right, bottom, top, near, far);
} }
/** /**

View File

@ -132,7 +132,7 @@ void Director::render() {
Mat4 viewProj = camera->getViewProjectionMatrix(); Mat4 viewProj = camera->getViewProjectionMatrix();
events::OnRenderSetCamera::emit(viewProj); events::OnRenderSetCamera::emit(viewProj);
} else { } else {
E2D_LOG_WARN("Director::render: 未设置主相机!"); E2D_WARN("Director::render: 未设置主相机!");
} }
runningScene_->render(); runningScene_->render();

View File

@ -1,65 +1,25 @@
#include <utils/logger.h> #include <utils/logger.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#ifdef _WIN32 #ifdef _WIN32
#include <fcntl.h>
#include <io.h>
#include <windows.h> #include <windows.h>
#endif #endif
namespace extra2d { namespace extra2d {
// 静态成员定义 std::shared_ptr<spdlog::logger> Logger::logger_ = nullptr;
LogLevel Logger::level_ = LogLevel::Info;
bool Logger::initialized_ = false; bool Logger::initialized_ = false;
bool Logger::consoleOutput_ = true; bool Logger::consoleOutput_ = true;
bool Logger::fileOutput_ = false; bool Logger::fileOutput_ = false;
std::string Logger::logFile_; 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 * @brief
*
* Windows Nintendo Switch Switch
* / spdlog
*/ */
void Logger::init() { void Logger::init() {
if (initialized_) { if (initialized_) {
@ -67,41 +27,59 @@ void Logger::init() {
} }
#ifdef _WIN32 #ifdef _WIN32
// 获取标准输出句柄
HANDLE hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hConsoleOut == INVALID_HANDLE_VALUE) {
return;
}
// 设置控制台输出代码页为UTF-8 (65001是UTF-8的代码页编号)
SetConsoleOutputCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8);
// 设置控制台模式确保支持UTF-8输出可选但能提升兼容性
DWORD consoleMode;
GetConsoleMode(hConsoleOut, &consoleMode);
consoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; // 启用ANSI转义序列可选
SetConsoleMode(hConsoleOut, consoleMode);
#endif #endif
#ifdef __SWITCH__ #ifdef __SWITCH__
// Switch 平台:初始化控制台并设置 SDL 日志重定向
consoleInit(NULL); consoleInit(NULL);
SDL_LogSetOutputFunction(SwitchLogOutput, nullptr);
#else
// 其他平台:设置 SDL 日志级别为详细模式
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_VERBOSE);
#endif #endif
std::vector<spdlog::sink_ptr> sinks;
if (consoleOutput_) {
auto consoleSink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
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<spdlog::sinks::basic_file_sink_mt>(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<spdlog::sinks::stdout_color_sink_mt>();
consoleSink->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] %v");
sinks.push_back(consoleSink);
}
logger_ =
std::make_shared<spdlog::logger>("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; initialized_ = true;
log(LogLevel::Info, "日志系统已初始化"); log(LogLevel::Info, "日志系统已初始化");
} }
/** /**
* @brief * @brief
*
* spdlog Nintendo Switch
*/ */
void Logger::shutdown() { void Logger::shutdown() {
if (initialized_) { if (initialized_) {
log(LogLevel::Info, "日志系统正在关闭"); log(LogLevel::Info, "日志系统正在关闭");
spdlog::shutdown();
logger_.reset();
#ifdef __SWITCH__ #ifdef __SWITCH__
consoleExit(NULL); consoleExit(NULL);
#endif #endif
@ -111,45 +89,53 @@ void Logger::shutdown() {
/** /**
* @brief * @brief
* @param level * @param level
*
*
*/ */
void Logger::setLevel(LogLevel level) { void Logger::setLevel(LogLevel level) {
level_ = level; if (logger_) {
// 同时设置 SDL 的日志级别 logger_->set_level(static_cast<spdlog::level::level_enum>(level));
if (level != LogLevel::Off) {
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION,
static_cast<SDL_LogPriority>(level));
} }
} }
/** /**
* @brief * @brief
* @param enable * @param enable true false
*/ */
void Logger::setConsoleOutput(bool enable) { void Logger::setConsoleOutput(bool enable) { consoleOutput_ = 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<SDL_LogPriority>(level_));
}
}
/** /**
* @brief * @brief
* @param filename * @param filename
*/ */
void Logger::setFileOutput(const std::string &filename) { void Logger::setFileOutput(const std::string &filename) {
logFile_ = filename; logFile_ = filename;
fileOutput_ = !filename.empty(); fileOutput_ = !filename.empty();
}
if (fileOutput_) { /**
// SDL2 使用 SDL_LogSetOutputFunction 可以重定向日志输出 * @brief
// 这里我们记录文件路径,实际文件输出可以通过自定义回调实现 * @return Info
log(LogLevel::Info, "文件输出已配置: {}", filename); */
LogLevel Logger::getLevel() {
if (logger_) {
return static_cast<LogLevel>(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<spdlog::level::level_enum>(level);
logger_->log(spdLevel, msg);
} }
} // namespace extra2d } // namespace extra2d

View File

@ -15,10 +15,14 @@ function define_extra2d_engine()
add_files("src/**.cpp") add_files("src/**.cpp")
add_files("third_party/glad/src/glad.c") add_files("third_party/glad/src/glad.c")
add_files("third_party/spdlog/src/*.cpp")
add_includedirs("include", {public = true}) add_includedirs("include", {public = true})
add_includedirs("third_party", {public = true}) add_includedirs("third_party", {public = true})
add_includedirs("third_party/glad/include", {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() local plat = get_current_plat()
if plat == "mingw" then if plat == "mingw" then
@ -47,7 +51,7 @@ function define_extra2d_engine()
add_cxxflags("-Wno-deprecated-copy", "-Wno-class-memaccess", {force = true}) add_cxxflags("-Wno-deprecated-copy", "-Wno-class-memaccess", {force = true})
if is_mode("debug") then if is_mode("debug") then
add_defines("E2D_DEBUG", "_DEBUG", {public = true}) add_defines("_DEBUG", {public = true})
add_cxxflags("-O0", "-g", {force = true}) add_cxxflags("-O0", "-g", {force = true})
else else
add_defines("NDEBUG", {public = true}) add_defines("NDEBUG", {public = true})