From ac42683f585468f3d161014cd08a0559d19bb8de Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Wed, 1 Nov 2017 04:01:02 +0000 Subject: [PATCH] r_world.c: rewrite R_DrawTextureChains_Multitexture_VBO to use GLSL git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1524 af15c1b1-3010-417e-b628-4374ebc0bcbd --- Quake/gl_vidsdl.c | 1 + Quake/glquake.h | 1 + Quake/r_world.c | 214 ++++++++++++++++++++++++++++++++-------------- 3 files changed, 152 insertions(+), 64 deletions(-) diff --git a/Quake/gl_vidsdl.c b/Quake/gl_vidsdl.c index 29a3fc10..f09e3e06 100644 --- a/Quake/gl_vidsdl.c +++ b/Quake/gl_vidsdl.c @@ -1345,6 +1345,7 @@ static void GL_Init (void) //johnfitz GLAlias_CreateShaders (); + GLWorld_CreateShaders (); GL_ClearBufferBindings (); } diff --git a/Quake/glquake.h b/Quake/glquake.h index 7f9d4bce..e9d250ea 100644 --- a/Quake/glquake.h +++ b/Quake/glquake.h @@ -370,6 +370,7 @@ GLint GL_GetUniformLocation (GLuint *programPtr, const char *name); GLuint GL_CreateProgram (const GLchar *vertSource, const GLchar *fragSource, int numbindings, const glsl_attrib_binding_t *bindings); void R_DeleteShaders (void); +void GLWorld_CreateShaders (void); void GLAlias_CreateShaders (void); void GL_DrawAliasShadow (entity_t *e); void DrawGLTriangleFan (glpoly_t *p); diff --git a/Quake/r_world.c b/Quake/r_world.c index 365e74dd..e39f33dc 100644 --- a/Quake/r_world.c +++ b/Quake/r_world.c @@ -795,17 +795,111 @@ void R_DrawLightmapChains (void) } } +static GLuint r_world_program; + +// uniforms used in vert shader + +// uniforms used in frag shader +static GLuint texLoc; +static GLuint LMTexLoc; +static GLuint fullbrightTexLoc; +static GLuint useFullbrightTexLoc; +static GLuint useOverbrightLoc; +static GLuint useAlphaTestLoc; +static GLuint alphaLoc; + +#define vertAttrIndex 0 +#define texCoordsAttrIndex 1 +#define LMCoordsAttrIndex 2 + +/* +============= +GLWorld_CreateShaders +============= +*/ +void GLWorld_CreateShaders (void) +{ + const glsl_attrib_binding_t bindings[] = { + { "Vert", vertAttrIndex }, + { "TexCoords", texCoordsAttrIndex }, + { "LMCoords", LMCoordsAttrIndex } + }; + + const GLchar *vertSource = \ + "#version 110\n" + "\n" + "attribute vec3 Vert;\n" + "attribute vec2 TexCoords;\n" + "attribute vec2 LMCoords;\n" + "\n" + "void main()\n" + "{\n" + " gl_TexCoord[0] = vec4(TexCoords, 0.0, 0.0);\n" + " gl_TexCoord[1] = vec4(LMCoords, 0.0, 0.0);\n" + " gl_Position = gl_ModelViewProjectionMatrix * vec4(Vert, 1.0);\n" + " // fog\n" + " vec3 ecPosition = vec3(gl_ModelViewMatrix * vec4(Vert, 1.0));\n" + " gl_FogFragCoord = abs(ecPosition.z);\n" + "}\n"; + + const GLchar *fragSource = \ + "#version 110\n" + "\n" + "uniform sampler2D Tex;\n" + "uniform sampler2D LMTex;\n" + "uniform sampler2D FullbrightTex;\n" + "uniform bool UseFullbrightTex;\n" + "uniform bool UseOverbright;\n" + "uniform bool UseAlphaTest;\n" + "uniform float Alpha;\n" + "void main()\n" + "{\n" + " vec4 result = texture2D(Tex, gl_TexCoord[0].xy);\n" + " if (UseAlphaTest && (result.a < 0.666))\n" + " discard;\n" + " result *= texture2D(LMTex, gl_TexCoord[1].xy);\n" + " if (UseOverbright)\n" + " result.rgb *= 2.0;\n" + " if (UseFullbrightTex)\n" + " result += texture2D(FullbrightTex, gl_TexCoord[0].xy);\n" + " result = clamp(result, 0.0, 1.0);\n" + " // apply GL_EXP2 fog (from the orange book)\n" + " float fog = exp(-gl_Fog.density * gl_Fog.density * gl_FogFragCoord * gl_FogFragCoord);\n" + " fog = clamp(fog, 0.0, 1.0);\n" + " result = mix(gl_Fog.color, result, fog);\n" + " result.a = Alpha;\n" + " gl_FragColor = result;\n" + "}\n"; + + if (!gl_glsl_alias_able) + return; + + r_world_program = GL_CreateProgram (vertSource, fragSource, sizeof(bindings)/sizeof(bindings[0]), bindings); + + if (r_world_program != 0) + { + // get uniform locations + texLoc = GL_GetUniformLocation (&r_world_program, "Tex"); + LMTexLoc = GL_GetUniformLocation (&r_world_program, "LMTex"); + fullbrightTexLoc = GL_GetUniformLocation (&r_world_program, "FullbrightTex"); + useFullbrightTexLoc = GL_GetUniformLocation (&r_world_program, "UseFullbrightTex"); + useOverbrightLoc = GL_GetUniformLocation (&r_world_program, "UseOverbright"); + useAlphaTestLoc = GL_GetUniformLocation (&r_world_program, "UseAlphaTest"); + alphaLoc = GL_GetUniformLocation (&r_world_program, "Alpha"); + } +} + extern GLuint gl_bmodel_vbo; /* ================ -R_DrawTextureChains_Multitexture_VBO -- ericw +R_DrawTextureChains_GLSL -- ericw Draw lightmapped surfaces with fulbrights in one pass, using VBO. -Requires 3 TMUs, GL_COMBINE_EXT, and GL_ADD. +Requires 3 TMUs, OpenGL 2.0 ================ */ -void R_DrawTextureChains_Multitexture_VBO (qmodel_t *model, entity_t *ent, texchain_t chain) +void R_DrawTextureChains_GLSL (qmodel_t *model, entity_t *ent, texchain_t chain) { int i; msurface_t *s; @@ -813,41 +907,40 @@ void R_DrawTextureChains_Multitexture_VBO (qmodel_t *model, entity_t *ent, texch qboolean bound; int lastlightmap; gltexture_t *fullbright = NULL; + float entalpha; + + entalpha = (ent != NULL) ? ENTALPHA_DECODE(ent->alpha) : 1.0f; + +// enable blending / disable depth writes + if (entalpha < 1) + { + glDepthMask (GL_FALSE); + glEnable (GL_BLEND); + } + + GL_UseProgramFunc (r_world_program); // Bind the buffers GL_BindBuffer (GL_ARRAY_BUFFER, gl_bmodel_vbo); GL_BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0); // indices come from client memory! -// Setup vertex array pointers - glVertexPointer (3, GL_FLOAT, VERTEXSIZE * sizeof(float), ((float *)0)); - glEnableClientState (GL_VERTEX_ARRAY); - - GL_ClientActiveTextureFunc (GL_TEXTURE0_ARB); - glTexCoordPointer (2, GL_FLOAT, VERTEXSIZE * sizeof(float), ((float *)0) + 3); - glEnableClientState (GL_TEXTURE_COORD_ARRAY); - - GL_ClientActiveTextureFunc (GL_TEXTURE1_ARB); - glTexCoordPointer (2, GL_FLOAT, VERTEXSIZE * sizeof(float), ((float *)0) + 5); - glEnableClientState (GL_TEXTURE_COORD_ARRAY); - -// TMU 2 is for fullbrights; same texture coordinates as TMU 0 - GL_ClientActiveTextureFunc (GL_TEXTURE2_ARB); - glTexCoordPointer (2, GL_FLOAT, VERTEXSIZE * sizeof(float), ((float *)0) + 3); - glEnableClientState (GL_TEXTURE_COORD_ARRAY); - -// Setup TMU 1 (lightmap) - GL_SelectTexture (GL_TEXTURE1_ARB); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE); - glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, gl_overbright.value ? 2.0f : 1.0f); - glEnable(GL_TEXTURE_2D); - -// Setup TMU 2 (fullbrights) - GL_SelectTexture (GL_TEXTURE2_ARB); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); - + GL_EnableVertexAttribArrayFunc (vertAttrIndex); + GL_EnableVertexAttribArrayFunc (texCoordsAttrIndex); + GL_EnableVertexAttribArrayFunc (LMCoordsAttrIndex); + + GL_VertexAttribPointerFunc (vertAttrIndex, 3, GL_FLOAT, GL_FALSE, VERTEXSIZE * sizeof(float), ((float *)0)); + GL_VertexAttribPointerFunc (texCoordsAttrIndex, 2, GL_FLOAT, GL_FALSE, VERTEXSIZE * sizeof(float), ((float *)0) + 3); + GL_VertexAttribPointerFunc (LMCoordsAttrIndex, 2, GL_FLOAT, GL_FALSE, VERTEXSIZE * sizeof(float), ((float *)0) + 5); + +// set uniforms + GL_Uniform1iFunc (texLoc, 0); + GL_Uniform1iFunc (LMTexLoc, 1); + GL_Uniform1iFunc (fullbrightTexLoc, 2); + GL_Uniform1iFunc (useFullbrightTexLoc, 0); + GL_Uniform1iFunc (useOverbrightLoc, (int)gl_overbright.value); + GL_Uniform1iFunc (useAlphaTestLoc, 0); + GL_Uniform1fFunc (alphaLoc, entalpha); + for (i=0 ; inumtextures ; i++) { t = model->textures[i]; @@ -856,14 +949,15 @@ void R_DrawTextureChains_Multitexture_VBO (qmodel_t *model, entity_t *ent, texch continue; // Enable/disable TMU 2 (fullbrights) - GL_SelectTexture (GL_TEXTURE2_ARB); + // FIXME: Move below to where we bind GL_TEXTURE0 if (gl_fullbrights.value && (fullbright = R_TextureAnimation(t, ent != NULL ? ent->frame : 0)->fullbright)) { - glEnable(GL_TEXTURE_2D); + GL_SelectTexture (GL_TEXTURE2); GL_Bind (fullbright); + GL_Uniform1iFunc (useFullbrightTexLoc, 1); } else - glDisable(GL_TEXTURE_2D); + GL_Uniform1iFunc (useFullbrightTexLoc, 0); R_ClearBatch (); @@ -874,11 +968,11 @@ void R_DrawTextureChains_Multitexture_VBO (qmodel_t *model, entity_t *ent, texch { if (!bound) //only bind once we are sure we need this texture { - GL_SelectTexture (GL_TEXTURE0_ARB); + GL_SelectTexture (GL_TEXTURE0); GL_Bind ((R_TextureAnimation(t, ent != NULL ? ent->frame : 0))->gltexture); if (t->texturechains[chain]->flags & SURF_DRAWFENCE) - glEnable (GL_ALPHA_TEST); // Flip alpha test back on + GL_Uniform1iFunc (useAlphaTestLoc, 1); // Flip alpha test back on bound = true; lastlightmap = s->lightmaptexturenum; @@ -887,7 +981,7 @@ void R_DrawTextureChains_Multitexture_VBO (qmodel_t *model, entity_t *ent, texch if (s->lightmaptexturenum != lastlightmap) R_FlushBatch (); - GL_SelectTexture (GL_TEXTURE1_ARB); + GL_SelectTexture (GL_TEXTURE1); GL_Bind (lightmap_textures[s->lightmaptexturenum]); lastlightmap = s->lightmaptexturenum; R_BatchSurface (s); @@ -898,32 +992,22 @@ void R_DrawTextureChains_Multitexture_VBO (qmodel_t *model, entity_t *ent, texch R_FlushBatch (); if (bound && t->texturechains[chain]->flags & SURF_DRAWFENCE) - glDisable (GL_ALPHA_TEST); // Flip alpha test back off + GL_Uniform1iFunc (useAlphaTestLoc, 0); // Flip alpha test back off } -// Reset TMU states - GL_SelectTexture (GL_TEXTURE2_ARB); - glDisable (GL_TEXTURE_2D); - - GL_SelectTexture (GL_TEXTURE1_ARB); - glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glDisable (GL_TEXTURE_2D); + // clean up + GL_DisableVertexAttribArrayFunc (vertAttrIndex); + GL_DisableVertexAttribArrayFunc (texCoordsAttrIndex); + GL_DisableVertexAttribArrayFunc (LMCoordsAttrIndex); - GL_SelectTexture (GL_TEXTURE0_ARB); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - -// Disable client state - glDisableClientState (GL_VERTEX_ARRAY); - - GL_ClientActiveTextureFunc (GL_TEXTURE0_ARB); - glDisableClientState (GL_TEXTURE_COORD_ARRAY); - - GL_ClientActiveTextureFunc (GL_TEXTURE1_ARB); - glDisableClientState (GL_TEXTURE_COORD_ARRAY); - - GL_ClientActiveTextureFunc (GL_TEXTURE2_ARB); - glDisableClientState (GL_TEXTURE_COORD_ARRAY); + GL_UseProgramFunc (0); + GL_SelectTexture (GL_TEXTURE0); + + if (entalpha < 1) + { + glDepthMask (GL_TRUE); + glDisable (GL_BLEND); + } } /* @@ -985,10 +1069,12 @@ void R_DrawTextureChains (qmodel_t *model, entity_t *ent, texchain_t chain) R_DrawTextureChains_NoTexture (model, chain); - if (gl_vbo_able && gl_texture_env_combine && gl_texture_env_add && gl_mtexable && gl_max_texture_units >= 3) + // OpenGL 2 fast path + if (r_world_program != 0) { - R_DrawTextureChains_Multitexture_VBO (model, ent, chain); R_EndTransparentDrawing (entalpha); + + R_DrawTextureChains_GLSL (model, ent, chain); return; }