diff --git a/Quake/gl_texmgr.c b/Quake/gl_texmgr.c index 6584b9eb..298cfe73 100644 --- a/Quake/gl_texmgr.c +++ b/Quake/gl_texmgr.c @@ -1401,7 +1401,8 @@ void TexMgr_ReloadNobrightImages (void) ================================================================================ */ -static GLuint currenttexture = (GLuint)-1; // to avoid unnecessary texture sets +static GLuint currenttexture[3] = {-1, -1, -1}; // to avoid unnecessary texture sets +static GLenum currenttarget = GL_TEXTURE0_ARB; qboolean mtexenabled = false; /* @@ -1409,27 +1410,12 @@ qboolean mtexenabled = false; GL_SelectTexture -- johnfitz -- rewritten ================ */ -static void GL_SelectTexture (GLenum target) +void GL_SelectTexture (GLenum target) { - static GLenum currenttarget; - static GLuint ct0, ct1; - if (target == currenttarget) return; - + GL_SelectTextureFunc(target); - - if (target == GL_TEXTURE0_ARB) - { - ct1 = currenttexture; - currenttexture = ct0; - } - else //target == GL_TEXTURE1_ARB - { - ct0 = currenttexture; - currenttexture = ct1; - } - currenttarget = target; } @@ -1473,10 +1459,10 @@ void GL_Bind (gltexture_t *texture) if (!texture) texture = nulltexture; - if (texture->texnum != currenttexture) + if (texture->texnum != currenttexture[currenttarget - GL_TEXTURE0_ARB]) { - currenttexture = texture->texnum; - glBindTexture (GL_TEXTURE_2D, currenttexture); + currenttexture[currenttarget - GL_TEXTURE0_ARB] = texture->texnum; + glBindTexture (GL_TEXTURE_2D, texture->texnum); texture->visframe = r_framecount; } } diff --git a/Quake/gl_texmgr.h b/Quake/gl_texmgr.h index a36f9f0a..1738f4aa 100644 --- a/Quake/gl_texmgr.h +++ b/Quake/gl_texmgr.h @@ -98,6 +98,7 @@ int TexMgr_PadConditional (int s); // TEXTURE BINDING & TEXTURE UNIT SWITCHING +void GL_SelectTexture (GLenum target); void GL_DisableMultitexture (void); //selects texture unit 0 void GL_EnableMultitexture (void); //selects texture unit 1 void GL_Bind (gltexture_t *texture); diff --git a/Quake/gl_vidsdl.c b/Quake/gl_vidsdl.c index dd9ddf58..25135917 100644 --- a/Quake/gl_vidsdl.c +++ b/Quake/gl_vidsdl.c @@ -93,6 +93,7 @@ qboolean gl_anisotropy_able = false; //johnfitz float gl_max_anisotropy; //johnfitz qboolean gl_texture_NPOT = false; //ericw qboolean gl_vbo_able = false; //ericw +GLint gl_max_texture_units = 0; //ericw PFNGLMULTITEXCOORD2FARBPROC GL_MTexCoord2fFunc = NULL; //johnfitz PFNGLACTIVETEXTUREARBPROC GL_SelectTextureFunc = NULL; //johnfitz @@ -831,6 +832,9 @@ static void GL_CheckExtensions (void) { Con_Printf("FOUND: ARB_multitexture\n"); gl_mtexable = true; + + glGetIntegerv(GL_MAX_TEXTURE_UNITS, &gl_max_texture_units); + Con_Printf("GL_MAX_TEXTURE_UNITS: %d\n", (int)gl_max_texture_units); } else { diff --git a/Quake/glquake.h b/Quake/glquake.h index e4918009..0b9b4756 100644 --- a/Quake/glquake.h +++ b/Quake/glquake.h @@ -155,6 +155,7 @@ extern qboolean gl_mtexable; extern PFNGLMULTITEXCOORD2FARBPROC GL_MTexCoord2fFunc; extern PFNGLACTIVETEXTUREARBPROC GL_SelectTextureFunc; extern PFNGLCLIENTACTIVETEXTUREARBPROC GL_ClientActiveTextureFunc; +extern GLint gl_max_texture_units; //ericw //johnfitz -- anisotropic filtering #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE diff --git a/Quake/r_brush.c b/Quake/r_brush.c index 8c03f98d..a5088c4f 100644 --- a/Quake/r_brush.c +++ b/Quake/r_brush.c @@ -975,7 +975,7 @@ void GL_BuildVBOs (void) qmodel_t *m; float *varray; - if (!(gl_vbo_able && gl_mtexable)) + if (!(gl_vbo_able && gl_mtexable && gl_max_texture_units >= 3)) return; // ask GL for a name for our VBO @@ -1024,7 +1024,7 @@ void GL_BuildVBOs (void) // setup vertex array. this will need to move if we use vertex arrays for other things 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); @@ -1032,6 +1032,11 @@ void GL_BuildVBOs (void) 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); } /* diff --git a/Quake/r_world.c b/Quake/r_world.c index 0ec3426a..0a1f12c8 100644 --- a/Quake/r_world.c +++ b/Quake/r_world.c @@ -416,29 +416,6 @@ void R_DrawTextureChains_Glow (qmodel_t *model, entity_t *ent, texchain_t chain) // //============================================================================== -/* -================ -R_MultitexturedDrawGLPoly - -Fallback immediate mode code to draw a multitexutred glpoly_t -================ -*/ -static void R_MultitexturedDrawGLPoly (glpoly_t *p) -{ - float *v; - int j; - - glBegin(GL_POLYGON); - v = p->verts[0]; - for (j=0 ; jnumverts ; j++, v+= VERTEXSIZE) - { - GL_MTexCoord2fFunc (GL_TEXTURE0_ARB, v[3], v[4]); - GL_MTexCoord2fFunc (GL_TEXTURE1_ARB, v[5], v[6]); - glVertex3fv (v); - } - glEnd (); -} - static unsigned int R_NumTriangleIndicesForSurf (msurface_t *s) { return 3 * (s->numedges - 2); @@ -475,8 +452,6 @@ R_ClearBatch */ static void R_ClearBatch () { - if (!(gl_vbo_able && gl_mtexable)) return; - num_vbo_indices = 0; } @@ -489,8 +464,6 @@ Draw the current batch if non-empty and clears it, ready for more R_BatchSurface */ static void R_FlushBatch () { - if (!(gl_vbo_able && gl_mtexable)) return; - if (num_vbo_indices > 0) { glDrawElements (GL_TRIANGLES, num_vbo_indices, GL_UNSIGNED_INT, vbo_indices); @@ -509,13 +482,7 @@ using VBOs. static void R_BatchSurface (msurface_t *s) { int num_surf_indices; - - if (!(gl_vbo_able && gl_mtexable)) - { - R_MultitexturedDrawGLPoly (s->polys); - return; - } - + num_surf_indices = R_NumTriangleIndicesForSurf (s); if (num_vbo_indices + num_surf_indices > MAX_BATCH_SIZE) @@ -532,11 +499,11 @@ R_DrawTextureChains_Multitexture -- johnfitz */ void R_DrawTextureChains_Multitexture (qmodel_t *model, entity_t *ent, texchain_t chain) { - int i; + int i, j; msurface_t *s; texture_t *t; + float *v; qboolean bound; - int lastlightmap; for (i=0 ; inumtextures ; i++) { @@ -545,10 +512,7 @@ void R_DrawTextureChains_Multitexture (qmodel_t *model, entity_t *ent, texchain_ if (!t || !t->texturechains[chain] || t->texturechains[chain]->flags & (SURF_DRAWTILED | SURF_NOTEXTURE)) continue; - R_ClearBatch (); - bound = false; - lastlightmap = 0; // avoid compiler warning for (s = t->texturechains[chain]; s; s = s->texturechain) if (!s->culled) { @@ -561,22 +525,20 @@ void R_DrawTextureChains_Multitexture (qmodel_t *model, entity_t *ent, texchain_ GL_EnableMultitexture(); // selects TEXTURE1 bound = true; - lastlightmap = s->lightmaptexturenum; } R_RenderDynamicLightmaps (s); - - if (s->lightmaptexturenum != lastlightmap) - R_FlushBatch (); - GL_Bind (lightmap_textures[s->lightmaptexturenum]); - lastlightmap = s->lightmaptexturenum; - R_BatchSurface (s); - + glBegin(GL_POLYGON); + v = s->polys->verts[0]; + for (j=0 ; jpolys->numverts ; j++, v+= VERTEXSIZE) + { + GL_MTexCoord2fFunc (GL_TEXTURE0_ARB, v[3], v[4]); + GL_MTexCoord2fFunc (GL_TEXTURE1_ARB, v[5], v[6]); + glVertex3fv (v); + } + glEnd (); rs_brushpasses++; } - - R_FlushBatch (); - GL_DisableMultitexture(); // selects TEXTURE0 if (bound && t->texturechains[chain]->flags & SURF_DRAWFENCE) @@ -807,6 +769,103 @@ void R_DrawLightmapChains (void) } } +/* +================ +R_DrawTextureChains_Multitexture_VBO -- ericw + +Draw lightmapped surfaces with fulbrights in one pass, using VBO. +Requires 3 TMUs, GL_COMBINE_EXT, and GL_ADD. +================ +*/ +void R_DrawTextureChains_Multitexture_VBO (qmodel_t *model, entity_t *ent, texchain_t chain) +{ + int i; + msurface_t *s; + texture_t *t; + qboolean bound; + int lastlightmap; + gltexture_t *fullbright = NULL; + +// 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); + + for (i=0 ; inumtextures ; i++) + { + t = model->textures[i]; + + if (!t || !t->texturechains[chain] || t->texturechains[chain]->flags & (SURF_DRAWTILED | SURF_NOTEXTURE)) + continue; + + // Enable/disable TMU 2 (fullbrights) + GL_SelectTexture (GL_TEXTURE2_ARB); + if (gl_fullbrights.value && (fullbright = R_TextureAnimation(t, ent != NULL ? ent->frame : 0)->fullbright)) + { + glEnable(GL_TEXTURE_2D); + GL_Bind (fullbright); + } + else + glDisable(GL_TEXTURE_2D); + + R_ClearBatch (); + + bound = false; + lastlightmap = 0; // avoid compiler warning + for (s = t->texturechains[chain]; s; s = s->texturechain) + if (!s->culled) + { + if (!bound) //only bind once we are sure we need this texture + { + GL_SelectTexture (GL_TEXTURE0_ARB); + 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 + + bound = true; + lastlightmap = s->lightmaptexturenum; + } + R_RenderDynamicLightmaps (s); + + if (s->lightmaptexturenum != lastlightmap) + R_FlushBatch (); + + GL_SelectTexture (GL_TEXTURE1_ARB); + GL_Bind (lightmap_textures[s->lightmaptexturenum]); + lastlightmap = s->lightmaptexturenum; + R_BatchSurface (s); + + rs_brushpasses++; + } + + R_FlushBatch (); + + if (bound && t->texturechains[chain]->flags & SURF_DRAWFENCE) + glDisable (GL_ALPHA_TEST); // 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); + + GL_SelectTexture (GL_TEXTURE0_ARB); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); +} + /* ============= R_DrawWorld -- johnfitz -- rewritten @@ -859,6 +918,13 @@ 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) + { + R_DrawTextureChains_Multitexture_VBO (model, ent, chain); + R_EndTransparentDrawing (entalpha); + return; + } + if (gl_overbright.value) { if (gl_texture_env_combine && gl_mtexable) //case 1: texture and lightmap in one pass, overbright using texture combiners