#pragma once #include #include #include namespace extra2d { /** * @brief OpenGL 错误检查宏 */ #define GL_CHECK(call) do { \ call; \ GLenum err = glGetError(); \ if (err != GL_NO_ERROR) { \ E2D_LOG_ERROR("OpenGL 错误在 {}: {} ({})", #call, getGLErrorString(err), err); \ } \ } while(0) /** * @brief 获取 OpenGL 错误字符串 * @param error OpenGL 错误码 * @return 错误描述字符串 */ inline const char* getGLErrorString(GLenum error) { switch (error) { case GL_NO_ERROR: return "GL_NO_ERROR"; case GL_INVALID_ENUM: return "GL_INVALID_ENUM"; case GL_INVALID_VALUE: return "GL_INVALID_VALUE"; case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION"; case GL_STACK_OVERFLOW: return "GL_STACK_OVERFLOW"; case GL_STACK_UNDERFLOW: return "GL_STACK_UNDERFLOW"; case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY"; case GL_INVALID_FRAMEBUFFER_OPERATION: return "GL_INVALID_FRAMEBUFFER_OPERATION"; default: return "Unknown Error"; } } /** * @brief 将 BufferType 转换为 OpenGL 缓冲区目标 */ inline GLenum bufferTypeToGL(BufferType type) { switch (type) { case BufferType::Vertex: return GL_ARRAY_BUFFER; case BufferType::Index: return GL_ELEMENT_ARRAY_BUFFER; case BufferType::Uniform: return GL_UNIFORM_BUFFER; case BufferType::Storage: return GL_SHADER_STORAGE_BUFFER; case BufferType::Staging: return GL_ARRAY_BUFFER; default: return GL_ARRAY_BUFFER; } } /** * @brief 将 BufferUsage 转换为 OpenGL 使用模式 */ inline GLenum bufferUsageToGL(BufferUsage usage) { switch (usage) { case BufferUsage::Static: return GL_STATIC_DRAW; case BufferUsage::Dynamic: return GL_DYNAMIC_DRAW; case BufferUsage::Stream: return GL_STREAM_DRAW; default: return GL_STATIC_DRAW; } } /** * @brief 将 TextureFormat 转换为 OpenGL 内部格式 */ inline GLenum textureFormatToGLInternal(TextureFormat format) { switch (format) { case TextureFormat::R8: return GL_R8; case TextureFormat::RG8: return GL_RG8; case TextureFormat::RGB8: return GL_RGB8; case TextureFormat::RGBA8: return GL_RGBA8; case TextureFormat::RGBA8_SRGB: return GL_SRGB8_ALPHA8; case TextureFormat::Depth16: return GL_DEPTH_COMPONENT16; case TextureFormat::Depth24: return GL_DEPTH_COMPONENT24; case TextureFormat::Depth32F: return GL_DEPTH_COMPONENT32F; case TextureFormat::Depth24Stencil8: return GL_DEPTH24_STENCIL8; case TextureFormat::Depth32FStencil8:return GL_DEPTH32F_STENCIL8; case TextureFormat::BC1: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; case TextureFormat::BC3: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; case TextureFormat::BC5: return 0x8DBD; // GL_COMPRESSED_RG_RGTC2 default: return GL_RGBA8; } } /** * @brief 将 TextureFormat 转换为 OpenGL 格式 */ inline GLenum textureFormatToGLFormat(TextureFormat format) { switch (format) { case TextureFormat::R8: return GL_RED; case TextureFormat::RG8: return GL_RG; case TextureFormat::RGB8: return GL_RGB; case TextureFormat::RGBA8: case TextureFormat::RGBA8_SRGB: return GL_RGBA; case TextureFormat::Depth16: case TextureFormat::Depth24: case TextureFormat::Depth32F: return GL_DEPTH_COMPONENT; case TextureFormat::Depth24Stencil8: case TextureFormat::Depth32FStencil8:return GL_DEPTH_STENCIL; default: return GL_RGBA; } } /** * @brief 将 TextureFormat 转换为 OpenGL 数据类型 */ inline GLenum textureFormatToGLType(TextureFormat format) { switch (format) { case TextureFormat::R8: case TextureFormat::RG8: case TextureFormat::RGB8: case TextureFormat::RGBA8: case TextureFormat::RGBA8_SRGB: return GL_UNSIGNED_BYTE; case TextureFormat::Depth16: return GL_UNSIGNED_SHORT; case TextureFormat::Depth24: return GL_UNSIGNED_INT; case TextureFormat::Depth32F: return GL_FLOAT; case TextureFormat::Depth24Stencil8: return GL_UNSIGNED_INT_24_8; case TextureFormat::Depth32FStencil8:return GL_FLOAT_32_UNSIGNED_INT_24_8_REV; default: return GL_UNSIGNED_BYTE; } } /** * @brief 将 TextureFilter 转换为 OpenGL 过滤模式 */ inline GLenum textureFilterToGLMin(TextureFilter filter) { switch (filter) { case TextureFilter::Nearest: return GL_NEAREST; case TextureFilter::Linear: return GL_LINEAR; case TextureFilter::NearestMipmapNearest: return GL_NEAREST_MIPMAP_NEAREST; case TextureFilter::LinearMipmapNearest: return GL_LINEAR_MIPMAP_NEAREST; case TextureFilter::NearestMipmapLinear: return GL_NEAREST_MIPMAP_LINEAR; case TextureFilter::LinearMipmapLinear: return GL_LINEAR_MIPMAP_LINEAR; default: return GL_LINEAR; } } inline GLenum textureFilterToGLMag(TextureFilter filter) { // Mag filter doesn't support mipmaps switch (filter) { case TextureFilter::Nearest: case TextureFilter::NearestMipmapNearest: case TextureFilter::NearestMipmapLinear: return GL_NEAREST; case TextureFilter::Linear: case TextureFilter::LinearMipmapNearest: case TextureFilter::LinearMipmapLinear: default: return GL_LINEAR; } } /** * @brief 将 TextureWrap 转换为 OpenGL 环绕模式 */ inline GLenum textureWrapToGL(TextureWrap wrap) { switch (wrap) { case TextureWrap::Repeat: return GL_REPEAT; case TextureWrap::ClampToEdge: return GL_CLAMP_TO_EDGE; case TextureWrap::ClampToBorder: return GL_CLAMP_TO_BORDER; case TextureWrap::MirroredRepeat: return GL_MIRRORED_REPEAT; default: return GL_REPEAT; } } /** * @brief 将 VertexFormat 转换为 OpenGL 格式 */ inline void vertexFormatToGL(VertexFormat format, GLint& components, GLenum& type, GLboolean& normalized) { switch (format) { case VertexFormat::Float1: components = 1; type = GL_FLOAT; normalized = GL_FALSE; break; case VertexFormat::Float2: components = 2; type = GL_FLOAT; normalized = GL_FALSE; break; case VertexFormat::Float3: components = 3; type = GL_FLOAT; normalized = GL_FALSE; break; case VertexFormat::Float4: components = 4; type = GL_FLOAT; normalized = GL_FALSE; break; case VertexFormat::Int1: components = 1; type = GL_INT; normalized = GL_FALSE; break; case VertexFormat::Int2: components = 2; type = GL_INT; normalized = GL_FALSE; break; case VertexFormat::Int3: components = 3; type = GL_INT; normalized = GL_FALSE; break; case VertexFormat::Int4: components = 4; type = GL_INT; normalized = GL_FALSE; break; case VertexFormat::UInt1: components = 1; type = GL_UNSIGNED_INT; normalized = GL_FALSE; break; case VertexFormat::UInt2: components = 2; type = GL_UNSIGNED_INT; normalized = GL_FALSE; break; case VertexFormat::UInt3: components = 3; type = GL_UNSIGNED_INT; normalized = GL_FALSE; break; case VertexFormat::UInt4: components = 4; type = GL_UNSIGNED_INT; normalized = GL_FALSE; break; case VertexFormat::Byte4: components = 4; type = GL_BYTE; normalized = GL_FALSE; break; case VertexFormat::Byte4Normalized: components = 4; type = GL_BYTE; normalized = GL_TRUE; break; case VertexFormat::UByte4: components = 4; type = GL_UNSIGNED_BYTE; normalized = GL_FALSE; break; case VertexFormat::UByte4Normalized:components = 4; type = GL_UNSIGNED_BYTE; normalized = GL_TRUE; break; default: components = 4; type = GL_FLOAT; normalized = GL_FALSE; break; } } /** * @brief 将 IndexType 转换为 OpenGL 类型 */ inline GLenum indexTypeToGL(IndexType type) { switch (type) { case IndexType::UInt16: return GL_UNSIGNED_SHORT; case IndexType::UInt32: return GL_UNSIGNED_INT; default: return GL_UNSIGNED_SHORT; } } /** * @brief 将 PrimitiveType 转换为 OpenGL 图元类型 */ inline GLenum primitiveTypeToGL(PrimitiveType type) { switch (type) { case PrimitiveType::Points: return GL_POINTS; case PrimitiveType::Lines: return GL_LINES; case PrimitiveType::LineStrip: return GL_LINE_STRIP; case PrimitiveType::Triangles: return GL_TRIANGLES; case PrimitiveType::TriangleStrip: return GL_TRIANGLE_STRIP; case PrimitiveType::TriangleFan: return GL_TRIANGLE_FAN; default: return GL_TRIANGLES; } } /** * @brief 将 BlendFactor 转换为 OpenGL 混合因子 */ inline GLenum blendFactorToGL(BlendFactor factor) { switch (factor) { case BlendFactor::Zero: return GL_ZERO; case BlendFactor::One: return GL_ONE; case BlendFactor::SrcColor: return GL_SRC_COLOR; case BlendFactor::OneMinusSrcColor: return GL_ONE_MINUS_SRC_COLOR; case BlendFactor::DstColor: return GL_DST_COLOR; case BlendFactor::OneMinusDstColor: return GL_ONE_MINUS_DST_COLOR; case BlendFactor::SrcAlpha: return GL_SRC_ALPHA; case BlendFactor::OneMinusSrcAlpha: return GL_ONE_MINUS_SRC_ALPHA; case BlendFactor::DstAlpha: return GL_DST_ALPHA; case BlendFactor::OneMinusDstAlpha: return GL_ONE_MINUS_DST_ALPHA; default: return GL_ONE; } } /** * @brief 将 BlendOp 转换为 OpenGL 混合操作 */ inline GLenum blendOpToGL(BlendOp op) { switch (op) { case BlendOp::Add: return GL_FUNC_ADD; case BlendOp::Subtract: return GL_FUNC_SUBTRACT; case BlendOp::ReverseSubtract: return GL_FUNC_REVERSE_SUBTRACT; case BlendOp::Min: return GL_MIN; case BlendOp::Max: return GL_MAX; default: return GL_FUNC_ADD; } } /** * @brief 将 CompareFunc 转换为 OpenGL 比较函数 */ inline GLenum compareFuncToGL(CompareFunc func) { switch (func) { case CompareFunc::Never: return GL_NEVER; case CompareFunc::Less: return GL_LESS; case CompareFunc::Equal: return GL_EQUAL; case CompareFunc::LessEqual: return GL_LEQUAL; case CompareFunc::Greater: return GL_GREATER; case CompareFunc::NotEqual: return GL_NOTEQUAL; case CompareFunc::GreaterEqual: return GL_GEQUAL; case CompareFunc::Always: return GL_ALWAYS; default: return GL_LESS; } } /** * @brief 将 ShaderType 转换为 OpenGL 着色器类型 */ inline GLenum shaderTypeToGL(ShaderType type) { switch (type) { case ShaderType::Vertex: return GL_VERTEX_SHADER; case ShaderType::Fragment: return GL_FRAGMENT_SHADER; case ShaderType::Geometry: return GL_GEOMETRY_SHADER; case ShaderType::Compute: return GL_COMPUTE_SHADER; default: return GL_VERTEX_SHADER; } } /** * @brief 获取 VertexFormat 的大小(字节) */ inline uint32_t getVertexFormatSize(VertexFormat format) { switch (format) { case VertexFormat::Float1: return sizeof(float) * 1; case VertexFormat::Float2: return sizeof(float) * 2; case VertexFormat::Float3: return sizeof(float) * 3; case VertexFormat::Float4: return sizeof(float) * 4; case VertexFormat::Int1: return sizeof(int32_t) * 1; case VertexFormat::Int2: return sizeof(int32_t) * 2; case VertexFormat::Int3: return sizeof(int32_t) * 3; case VertexFormat::Int4: return sizeof(int32_t) * 4; case VertexFormat::UInt1: return sizeof(uint32_t) * 1; case VertexFormat::UInt2: return sizeof(uint32_t) * 2; case VertexFormat::UInt3: return sizeof(uint32_t) * 3; case VertexFormat::UInt4: return sizeof(uint32_t) * 4; case VertexFormat::Byte4: case VertexFormat::Byte4Normalized: return sizeof(int8_t) * 4; case VertexFormat::UByte4: case VertexFormat::UByte4Normalized: return sizeof(uint8_t) * 4; default: return sizeof(float) * 4; } } } // namespace extra2d