From addf0d9beadba289fffe233ff2ab61bd3fcf88d6 Mon Sep 17 00:00:00 2001 From: llbraughler Date: Sat, 4 Oct 2025 12:38:29 -0400 Subject: [PATCH] Implement ShowNormals in RendererGL2 --- code/renderergl2/tr_shade.c | 135 +++++++++++++++++++++++++++++++++++- 1 file changed, 134 insertions(+), 1 deletion(-) diff --git a/code/renderergl2/tr_shade.c b/code/renderergl2/tr_shade.c index dec35e52..34207418 100644 --- a/code/renderergl2/tr_shade.c +++ b/code/renderergl2/tr_shade.c @@ -141,7 +141,140 @@ Draws vertex normals for debugging ================ */ static void DrawNormals (shaderCommands_t *input) { - //FIXME: implement this + if (!input) return; + + const int vertexCount = input->numVertexes; + if (vertexCount <= 0 || !input->xyz || !input->normal) return; + if (!input->shader || input->shader->isSky) return; // do not draw over sky/clouds + if (input->shader->numDeforms > 0) return; // skip vertex-deformed surfaces + + // Skip animated entities that are interpolating; otherwise normals will appear to "swim". + if (backEnd.currentEntity != &tr.worldEntity) { + const trRefEntity_t* refEnt = backEnd.currentEntity; + if (refEnt && refEnt->e.backlerp > 0) return; + } + + const float lineLength = 6.0f; + + // xyz is vec4_t (x,y,z,1) + const float* positionsXYZW = (const float*)input->xyz; + const int16_t* packedNormals = (const int16_t*)input->normal; + const float* floatNormals = (const float*)input->normal; + + const vao_t* boundVao = glState.currentVao; + qboolean usePacked = qfalse; + + if (boundVao) { + const vaoAttrib_t* a = &boundVao->attribs[ATTR_INDEX_NORMAL]; + usePacked = (a->type == GL_SHORT && a->normalized); + } + else { + const float sx = packedNormals[0] * (1.0f / 32767.0f); + const float sy = packedNormals[1] * (1.0f / 32767.0f); + const float sz = packedNormals[2] * (1.0f / 32767.0f); + + const float lp = sx * sx + sy * sy + sz * sz; + const float lf = floatNormals[0] * floatNormals[0] + + floatNormals[1] * floatNormals[1] + + floatNormals[2] * floatNormals[2]; + + usePacked = fabsf(lp - 1.0f) <= fabsf(lf - 1.0f); + } + + const GLsizeiptr floatsPerVertex = 6; + const GLsizeiptr maxFloatCount = floatsPerVertex * (GLsizeiptr)vertexCount; + const GLsizeiptr maxByteCount = (GLsizeiptr)sizeof(float) * maxFloatCount; + + float* lineVertices = (float*)ri.Hunk_AllocateTempMemory((int)maxByteCount); + float* writePtr = lineVertices; + + // Build the line list + for (int i = 0; i < vertexCount; ++i, positionsXYZW += 4) { + vec3_t n; + + if (usePacked) { + R_VaoUnpackNormal(n, (int16_t*)packedNormals); + packedNormals += 4; + } + else { + n[0] = floatNormals[0]; + n[1] = floatNormals[1]; + n[2] = floatNormals[2]; + floatNormals += 4; + } + + // endpoints in object/world space + const float startX = positionsXYZW[0]; + const float startY = positionsXYZW[1]; + const float startZ = positionsXYZW[2]; + + const float endX = startX + n[0] * lineLength; + const float endY = startY + n[1] * lineLength; + const float endZ = startZ + n[2] * lineLength; + + + // emit line + *writePtr++ = startX; *writePtr++ = startY; *writePtr++ = startZ; + *writePtr++ = endX; *writePtr++ = endY; *writePtr++ = endZ; + } + + const GLsizei numVerts = (GLsizei)((writePtr - lineVertices) / 3); + if (numVerts == 0) { + ri.Hunk_FreeTempMemory(lineVertices); + return; + } + + // save bindings + GLint prevProg = 0, prevVao = 0, prevArrayBuf = 0; + qglGetIntegerv(GL_CURRENT_PROGRAM, &prevProg); + qglGetIntegerv(GL_VERTEX_ARRAY_BINDING, &prevVao); + qglGetIntegerv(GL_ARRAY_BUFFER_BINDING, &prevArrayBuf); + + GL_BindToTMU(tr.whiteImage, TB_COLORMAP); + GL_State(GLS_POLYMODE_LINE); + GLboolean prevDepthMask; + qglGetBooleanv(GL_DEPTH_WRITEMASK, &prevDepthMask); + qglDepthMask(GL_FALSE); + + + R_BindNullVao(); + + // temp VAO/VBO + GLuint vao = 0, vbo = 0; + qglGenVertexArrays(1, &vao); + qglBindVertexArray(vao); + + qglGenBuffers(1, &vbo); + qglBindBuffer(GL_ARRAY_BUFFER, vbo); + qglBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * numVerts, lineVertices, GL_STREAM_DRAW); + + shaderProgram_t* program = &tr.textureColorShader; + GLSL_BindProgram(program); + GLSL_SetUniformMat4(program, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + + vec4_t white; + VectorSet4(white, 1, 1, 1, 1); + GLSL_SetUniformVec4(program, UNIFORM_COLOR, white); + + // position at location 0 in this backend + qglEnableVertexAttribArray(ATTR_INDEX_POSITION); + qglVertexAttribPointer(ATTR_INDEX_POSITION, 3, GL_FLOAT, GL_FALSE, 0, (const void*)0); + + qglDrawArrays(GL_LINES, 0, numVerts); + + qglDisableVertexAttribArray(ATTR_INDEX_POSITION); + + // restore + qglDepthMask(prevDepthMask); + qglBindBuffer(GL_ARRAY_BUFFER, prevArrayBuf); + qglBindVertexArray(prevVao); + qglDeleteBuffers(1, &vbo); + qglDeleteVertexArrays(1, &vao); + + if (prevProg) qglUseProgram((GLuint)prevProg); + else qglUseProgram(0); + + ri.Hunk_FreeTempMemory(lineVertices); } /*