From 2be194c147e733e3e4407cc473efd1706cdb4ae0 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 22 Aug 2025 15:47:14 +0800 Subject: [PATCH] [Feat] (MG_State/Program): glUniformMatrix* without transpose --- .../MG_Impl/GLImpl/Program/GL_Program.cpp | 96 ++++++++++++++++++- MobileGL/MG_Test/Program/ProgramTest.cpp | 55 +++++++++++ 2 files changed, 148 insertions(+), 3 deletions(-) diff --git a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp index 9708004f..5e389b15 100644 --- a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp +++ b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp @@ -546,15 +546,105 @@ namespace MobileGL { } void UniformMatrix2fv_State(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { - THROW_UNIMPL_EXCEPTION; + // For 2x2 matrices, we have 4 elements per matrix + // If transpose is GL_TRUE, we need to transpose the matrix data + if (location == -1) + return; + + auto programObject = MG_State::pGLContext->GetCurrentProgram(); + if (programObject == nullptr) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", __func__, + "There is no current program object.")); + return; + } + + if (location >= programObject->GetUniformCount() || location < -1) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", __func__, + "`location` is an invalid uniform location for the current program object and `location` is not equal to -1.")); + return; + } + + // For matrix uniforms, we handle each matrix individually + for (GLint i = 0; i < count; i++) { + // Note: In this implementation, we're not actually transposing the matrix data + // as we're directly copying to UBO. The transpose parameter is typically used + // in OpenGL to indicate whether the matrix should be transposed before being + // loaded into the uniform variable. In our case, we assume the shader compiler + // has handled the appropriate matrix layout. + Uniform_State<4>(*programObject, location + i, value + i * 4); + } } void UniformMatrix3fv_State(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { - THROW_UNIMPL_EXCEPTION; + // For 3x3 matrices, we have 9 elements per matrix + // If transpose is GL_TRUE, we need to transpose the matrix data + if (location == -1) + return; + + auto programObject = MG_State::pGLContext->GetCurrentProgram(); + if (programObject == nullptr) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", __func__, + "There is no current program object.")); + return; + } + + if (location >= programObject->GetUniformCount() || location < -1) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", __func__, + "`location` is an invalid uniform location for the current program object and `location` is not equal to -1.")); + return; + } + + // For matrix uniforms, we handle each matrix individually + for (GLint i = 0; i < count; i++) { + // Note: In this implementation, we're not actually transposing the matrix data + // as we're directly copying to UBO. The transpose parameter is typically used + // in OpenGL to indicate whether the matrix should be transposed before being + // loaded into the uniform variable. In our case, we assume the shader compiler + // has handled the appropriate matrix layout. + Uniform_State<9>(*programObject, location + i, value + i * 9); + } } void UniformMatrix4fv_State(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { - THROW_UNIMPL_EXCEPTION; + // For 4x4 matrices, we have 16 elements per matrix + // If transpose is GL_TRUE, we need to transpose the matrix data + if (location == -1) + return; + + auto programObject = MG_State::pGLContext->GetCurrentProgram(); + if (programObject == nullptr) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", __func__, + "There is no current program object.")); + return; + } + + if (location >= programObject->GetUniformCount() || location < -1) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", __func__, + "`location` is an invalid uniform location for the current program object and `location` is not equal to -1.")); + return; + } + + // For matrix uniforms, we handle each matrix individually + for (GLint i = 0; i < count; i++) { + // Note: In this implementation, we're not actually transposing the matrix data + // as we're directly copying to UBO. The transpose parameter is typically used + // in OpenGL to indicate whether the matrix should be transposed before being + // loaded into the uniform variable. In our case, we assume the shader compiler + // has handled the appropriate matrix layout. + Uniform_State<16>(*programObject, location + i, value + i * 16); + } } void ValidateProgram_State(GLuint program) { diff --git a/MobileGL/MG_Test/Program/ProgramTest.cpp b/MobileGL/MG_Test/Program/ProgramTest.cpp index 52120260..1a3d6b87 100644 --- a/MobileGL/MG_Test/Program/ProgramTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramTest.cpp @@ -169,3 +169,58 @@ TEST_F(ProgramTest, CompileAndLink) { GetUniformiv(program, locInt, &intVal); EXPECT_EQ(intVal, 114514); } + +TEST_F(ProgramTest, UniformMatrixFunctions) { + char infoLog[1024] = ""; + + GLuint vs = CreateShader(GL_VERTEX_SHADER); + ShaderSource(vs, 1, &vsSrc, NULL); + printf("Compiling vertex shader: %s\n", vsSrc); + CompileShader(vs); + GLint vsStatus = GL_FALSE; + GetShaderiv(vs, GL_COMPILE_STATUS, &vsStatus); + GetShaderInfoLog(vs, 1024, nullptr, infoLog); + ASSERT_EQ(vsStatus, GL_TRUE) << infoLog; + printf("Compiled vertex shader.\n"); + + GLuint fs = CreateShader(GL_FRAGMENT_SHADER); + ShaderSource(fs, 1, &fsSrc, NULL); + printf("Compiling fragment shader: %s\n", fsSrc); + CompileShader(fs); + GLint fsStatus = GL_FALSE; + GetShaderiv(fs, GL_COMPILE_STATUS, &fsStatus); + GetShaderInfoLog(fs, 1024, nullptr, infoLog); + ASSERT_EQ(fsStatus, GL_TRUE) << infoLog; + printf("Compiled fragment shader.\n"); + + GLuint program = CreateProgram(); + AttachShader(program, vs); + AttachShader(program, fs); + + BindAttribLocation(program, 1, "fIn1"); + BindAttribLocation(program, 3, "fIn3"); + BindAttribLocation(program, 5, "fIn5"); + printf("Linking program...\n"); + LinkProgram(program); + printf("Program linked.\n"); + + UseProgram(program); + + // Test UniformMatrix2fv + auto locProjMat = GetUniformLocation(program, "ProjMat"); + ASSERT_NE(locProjMat, -1); + + // 4x4 matrix (16 elements) + GLfloat matrix4x4[16] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + + // Test UniformMatrix4fv with count = 1 + UniformMatrix4fv(locProjMat, 1, GL_FALSE, matrix4x4); + + // Test with multiple matrices (count > 1) + // For this test, we would need uniforms that are arrays of matrices +}