fixed deluxemapping
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 19 Mar 2006 21:15:02 +0000 (21:15 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 19 Mar 2006 21:15:02 +0000 (21:15 +0000)
added r_glsl_deluxemapping cvar (2 forces fake deluxemapping on any level, kind of interesting to see)
added modelspace deluxemapping (automatically detects whether deluxemaps are modelspace or tangentspace at load time)
changed offsetmapping shader to be more perspective correct

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@6141 d7cf8633-e32d-0410-b094-e92efae38249

gl_rmain.c
model_brush.c
model_shared.h
render.h

index 7960642..36cc3ae 100644 (file)
@@ -104,6 +104,7 @@ cvar_t r_glsl_offsetmapping_scale = {0, "r_glsl_offsetmapping_scale", "-0.04", "
 cvar_t r_glsl_offsetmapping_bias = {0, "r_glsl_offsetmapping_bias", "0.04", "pushes the effect closer/further"};
 cvar_t r_glsl_usehalffloat = {0, "r_glsl_usehalffloat", "0", "use half and hvec variables in GLSL shader for a speed gain (NVIDIA only)"};
 cvar_t r_glsl_surfacenormalize = {0, "r_glsl_surfacenormalize", "1", "normalize bumpmap texels in GLSL shader, produces a more rounded look on small bumps and dents"};
+cvar_t r_glsl_deluxemapping = {0, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
 
 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1", "enables animation smoothing on sprites (requires r_lerpmodels 1)"};
 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
@@ -444,6 +445,12 @@ static const char *builtinshaderstring =
 "varying vec3 EyeVector;\n"
 "#endif\n"
 "\n"
+"#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
+"varying myhvec3 VectorS; // direction of S texcoord (sometimes crudely called tangent)\n"
+"varying myhvec3 VectorT; // direction of T texcoord (sometimes crudely called binormal)\n"
+"varying myhvec3 VectorR; // direction of R texcoord (surface normal)\n"
+"#endif\n"
+"\n"
 "\n"
 "\n"
 "\n"
@@ -501,6 +508,12 @@ static const char *builtinshaderstring =
 "      EyeVector.z = dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
 "#endif\n"
 "\n"
+"#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
+"      VectorS = gl_MultiTexCoord1.xyz;\n"
+"      VectorT = gl_MultiTexCoord2.xyz;\n"
+"      VectorR = gl_MultiTexCoord3.xyz;\n"
+"#endif\n"
+"\n"
 "      // transform vertex to camera space, using ftransform to match non-VS\n"
 "      // rendering\n"
 "      gl_Position = ftransform();\n"
@@ -520,7 +533,7 @@ static const char *builtinshaderstring =
 "uniform myhalf OffsetMapping_Bias;\n"
 "#endif\n"
 "\n"
-"#if defined(MODE_LIGHTSOURCE) || defined(MODE_LIGHTDIRECTIONMAP) || defined(MODE_LIGHTDIRECTION) || defined(USEOFFSETMAPPING)\n"
+"#if defined(MODE_LIGHTSOURCE) || defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE) || defined(MODE_LIGHTDIRECTION) || defined(USEOFFSETMAPPING)\n"
 "uniform sampler2D Texture_Normal;\n"
 "#endif\n"
 "\n"
@@ -535,7 +548,7 @@ static const char *builtinshaderstring =
 "#if !defined(MODE_LIGHTSOURCE) && !defined(MODE_LIGHTDIRECTION)\n"
 "uniform sampler2D Texture_Lightmap;\n"
 "#endif\n"
-"#ifdef MODE_LIGHTDIRECTIONMAP\n"
+"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n"
 "uniform sampler2D Texture_Deluxemap;\n"
 "#endif\n"
 "\n"
@@ -595,8 +608,11 @@ static const char *builtinshaderstring =
 "{\n"
 "      // apply offsetmapping\n"
 "#ifdef USEOFFSETMAPPING\n"
+"      myhvec3 eyedir = myhvec3(normalize(EyeVector));\n"
+"      myhalf depthbias = 1.0 - eyedir.z; // should this be a -?\n"
+"      depthbias = 1.0 - depthbias * depthbias;\n"
 "      // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
-"      myhvec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
+"      myhvec2 OffsetVector = (EyeVector.xy * (1.0 / EyeVector.z) * depthbias) * vec2(-0.333, 0.333);\n"
 "      myhvec2 TexCoordOffset = TexCoord + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).w);\n"
 "      TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
 "      TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(Texture_Normal, TexCoordOffset).w);\n"
@@ -673,8 +689,33 @@ static const char *builtinshaderstring =
 "\n"
 "\n"
 "\n"
-"#elif defined(MODE_LIGHTDIRECTIONMAP)\n"
-"      // deluxemap lightmapping\n"
+"#elif defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE)\n"
+"      // deluxemap lightmapping using light vectors in modelspace (evil q3map2)\n"
+"\n"
+"      // get the surface normal and light normal\n"
+"#ifdef SURFACENORMALIZE\n"
+"      myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - 0.5);\n"
+"#else\n"
+"      myhvec3 surfacenormal = -1.0 + 2.0 * myhvec3(texture2D(Texture_Normal, TexCoord));\n"
+"#endif\n"
+"      myhvec3 diffusenormal_modelspace = myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - 0.5;\n"
+"      myhvec3 diffusenormal = normalize(myhvec3(dot(diffusenormal_modelspace, VectorS), dot(diffusenormal_modelspace, VectorT), dot(diffusenormal_modelspace, VectorR)));\n"
+"\n"
+"      // calculate directional shading\n"
+"      myhvec3 tempcolor = color.rgb * (DiffuseScale * max(dot(surfacenormal, diffusenormal), 0.0));\n"
+"#ifdef USESPECULAR\n"
+"      myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));\n"
+"      tempcolor += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(max(dot(surfacenormal, specularnormal), 0.0), SpecularPower);\n"
+"#endif\n"
+"\n"
+"      // apply lightmap color\n"
+"      color.rgb = tempcolor * myhvec3(texture2D(Texture_Lightmap, TexCoordLightmap)) + color.rgb * myhvec3(AmbientScale);\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"#elif defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n"
+"      // deluxemap lightmapping using light vectors in tangentspace\n"
 "\n"
 "      // get the surface normal and light normal\n"
 "#ifdef SURFACENORMALIZE\n"
@@ -743,11 +784,17 @@ void R_GLSL_CompilePermutation(int permutation)
                fragstrings_list[fragstrings_count++] = "#define MODE_LIGHTSOURCE\n";
                strlcat(permutationname, " lightsource", sizeof(permutationname));
        }
-       if (permutation & SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP)
+       if (permutation & SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE)
        {
-               vertstrings_list[vertstrings_count++] = "#define MODE_LIGHTDIRECTIONMAP\n";
-               fragstrings_list[fragstrings_count++] = "#define MODE_LIGHTDIRECTIONMAP\n";
-               strlcat(permutationname, " lightdirectionmap", sizeof(permutationname));
+               vertstrings_list[vertstrings_count++] = "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n";
+               fragstrings_list[fragstrings_count++] = "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n";
+               strlcat(permutationname, " lightdirectionmap_modelspace", sizeof(permutationname));
+       }
+       if (permutation & SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)
+       {
+               vertstrings_list[vertstrings_count++] = "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n";
+               fragstrings_list[fragstrings_count++] = "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n";
+               strlcat(permutationname, " lightdirectionmap_tangentspace", sizeof(permutationname));
        }
        if (permutation & SHADERPERMUTATION_MODE_LIGHTDIRECTION)
        {
@@ -891,20 +938,19 @@ void R_SetupSurfaceShader(const entity_render_t *ent, const texture_t *texture,
                if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
                        permutation |= SHADERPERMUTATION_CUBEFILTER;
        }
-       else if (modellighting)
-       {
-               permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTION;
-               if (texture->skin.glow)
-                       permutation |= SHADERPERMUTATION_GLOW;
-       }
-       else if (r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping)
-       {
-               permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP;
-               if (texture->skin.glow)
-                       permutation |= SHADERPERMUTATION_GLOW;
-       }
        else
        {
+               if (modellighting)
+                       permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTION;
+               else if (r_glsl_deluxemapping.integer >= 1 && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping)
+               {
+                       if (r_refdef.worldmodel->brushq3.deluxemapping_modelspace)
+                               permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE;
+                       else
+                               permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
+               }
+               else if (r_glsl_deluxemapping.integer >= 2) // fake mode
+                       permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
                if (texture->skin.glow)
                        permutation |= SHADERPERMUTATION_GLOW;
        }
@@ -1113,6 +1159,7 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_glsl_offsetmapping_bias);
        Cvar_RegisterVariable(&r_glsl_usehalffloat);
        Cvar_RegisterVariable(&r_glsl_surfacenormalize);
+       Cvar_RegisterVariable(&r_glsl_deluxemapping);
        Cvar_RegisterVariable(&r_lerpsprites);
        Cvar_RegisterVariable(&r_lerpmodels);
        Cvar_RegisterVariable(&r_waterscroll);
@@ -2789,8 +2836,7 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                                {
                                        R_Mesh_TexBind(7, R_GetTexture(surface->lightmaptexture));
                                        if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
-                                               R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
-                                               //R_Mesh_TexBind(8, R_GetTexture(surface->deluxemaptexture));
+                                               R_Mesh_TexBind(8, R_GetTexture(surface->deluxemaptexture));
                                        R_Mesh_ColorPointer(NULL);
                                }
                                else
index 3faac50..deab35f 100644 (file)
@@ -2034,6 +2034,7 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
                        surface->lightmapinfo->styles[i] = in->styles[i];
                surface->lightmapinfo->lightmaptexturestride = 0;
                surface->lightmaptexture = NULL;
+               surface->deluxemaptexture = r_texture_blanknormalmap;
                i = LittleLong(in->lightofs);
                if (i == -1)
                {
@@ -2070,11 +2071,13 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
                        {
                                surface->lightmapinfo->lightmaptexturestride = ssize;
                                surface->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surface->lightmapinfo->lightmaptexturestride, tsize, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP | TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+                               surface->deluxemaptexture = r_texture_blanknormalmap;
                        }
                        else
                        {
                                surface->lightmapinfo->lightmaptexturestride = R_CompatibleFragmentWidth(ssize, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
                                surface->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surface->lightmapinfo->lightmaptexturestride, tsize, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+                               surface->deluxemaptexture = r_texture_blanknormalmap;
                        }
                        R_FragmentLocation(surface->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
                        uscale = (uscale - ubase) / ssize;
@@ -4289,17 +4292,28 @@ static void Mod_Q3BSP_LoadLightmaps(lump_t *l)
        loadmodel->brushq3.data_lightmaps = out;
        loadmodel->brushq3.num_lightmaps = count;
 
+       loadmodel->brushq3.deluxemapping_modelspace = false;
        for (i = 0;i < count;i++, in++, out++)
+       {
+               // if this may be a deluxemap, check if it's in modelspace or not
+               if ((i & 1) && !loadmodel->brushq3.deluxemapping_modelspace)
+               {
+                       int j;
+                       unsigned char *b = in->rgb;
+                       for (j = 2;j < 128*128*3;j += 3)
+                       {
+                               // if this is definitely negative Z, it is not facing outward,
+                               // and thus must be in modelspace, as negative Z would never
+                               // occur in tangentspace
+                               if (b[j] < 120)
+                               {
+                                       loadmodel->brushq3.deluxemapping_modelspace = true;
+                                       break;
+                               }
+                       }
+               }
                *out = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%04i", i), 128, 128, in->rgb, TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
-       // deluxemapped bsp files have an even number of lightmaps, and surfaces
-       // always index even numbered ones (0, 2, 4, ...), the odd numbered
-       // lightmaps are the deluxemaps (light direction textures), so if we
-       // encounter any odd numbered lightmaps it is not a deluxemapped bsp, it
-       // is also not a deluxemapped bsp if it has an odd number of lightmaps or
-       // less than 2
-       loadmodel->brushq3.deluxemapping = true;
-       if ((count & 1) || count < 2)
-               loadmodel->brushq3.deluxemapping = false;
+       }
 }
 
 static void Mod_Q3BSP_LoadFaces(lump_t *l)
@@ -4328,6 +4342,29 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l)
        loadmodel->data_surfaces = out;
        loadmodel->num_surfaces = count;
 
+       // deluxemapped q3bsp files have an even number of lightmaps, and surfaces
+       // always index even numbered ones (0, 2, 4, ...), the odd numbered
+       // lightmaps are the deluxemaps (light direction textures), so if we
+       // encounter any odd numbered lightmaps it is not a deluxemapped bsp, it
+       // is also not a deluxemapped bsp if it has an odd number of lightmaps or
+       // less than 2
+       loadmodel->brushq3.deluxemapping = true;
+       if (count >= 2 && !(count & 1))
+       {
+               for (i = 0;i < count;i++)
+               {
+                       n = LittleLong(in[i].lightmapindex);
+                       if (n >= 0 && ((n & 1) || n + 1 >= loadmodel->brushq3.num_lightmaps))
+                       {
+                               loadmodel->brushq3.deluxemapping = false;
+                               break;
+                       }
+               }
+       }
+       else
+               loadmodel->brushq3.deluxemapping = false;
+       Con_DPrintf("%s is %sdeluxemapped\n", loadmodel->name, loadmodel->brushq3.deluxemapping ? "" : "not ");
+
        i = 0;
        for (meshnum = 0;i < count;meshnum++)
        {
@@ -4376,15 +4413,17 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l)
                        else if (n < 0)
                                n = -1;
                        if (n == -1)
+                       {
                                out->lightmaptexture = NULL;
+                               out->deluxemaptexture = r_texture_blanknormalmap;
+                       }
                        else
                        {
-                               // deluxemapped q3bsp files have lightmaps and deluxemaps in
-                               // pairs, no odd numbers ever appear, so if we encounter an
-                               // odd lightmap index, it's not deluxemapped.
-                               if (n & 1)
-                                       loadmodel->brushq3.deluxemapping = false;
                                out->lightmaptexture = loadmodel->brushq3.data_lightmaps[n];
+                               if (loadmodel->brushq3.deluxemapping)
+                                       out->deluxemaptexture = loadmodel->brushq3.data_lightmaps[n+1];
+                               else
+                                       out->deluxemaptexture = r_texture_blanknormalmap;
                        }
 
                        firstvertex = LittleLong(in->firstvertex);
index 0ee9735..206c9c9 100644 (file)
@@ -265,6 +265,8 @@ typedef struct msurface_s
        texture_t *texture;
        // the lightmap texture fragment to use on the rendering mesh
        rtexture_t *lightmaptexture;
+       // the lighting direction texture fragment to use on the rendering mesh
+       rtexture_t *deluxemaptexture;
 
        // this surface is part of this mesh
        surfmesh_t *groupmesh;
@@ -482,6 +484,9 @@ typedef struct model_brushq3_s
        // (lightmap texture pairs, every odd one is never directly refernced,
        //  and contains lighting normals, not colors)
        qboolean deluxemapping;
+       // true if the detected deluxemaps are the modelspace kind, rather than
+       // the faster tangentspace kind
+       qboolean deluxemapping_modelspace;
 }
 model_brushq3_t;
 
index 3f989a7..848a66c 100644 (file)
--- a/render.h
+++ b/render.h
@@ -227,6 +227,7 @@ extern cvar_t r_glsl_offsetmapping_scale;
 extern cvar_t r_glsl_offsetmapping_bias;
 extern cvar_t r_glsl_usehalffloat;
 extern cvar_t r_glsl_surfacenormalize;
+extern cvar_t r_glsl_deluxemapping;
 
 extern cvar_t gl_polyblend;
 extern cvar_t gl_dither;
@@ -266,17 +267,18 @@ void R_QueueTextureSurfaceList(entity_render_t *ent, struct texture_s *texture,
 void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces);
 
 #define SHADERPERMUTATION_MODE_LIGHTSOURCE (1<<0) // (lightsource) use directional pixel shading from light source (rtlight)
-#define SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP (1<<1) // (lightmap) use directional pixel shading from texture containing light directions (deluxemap)
-#define SHADERPERMUTATION_MODE_LIGHTDIRECTION (1<<2) // (lightmap) use directional pixel shading from fixed light direction (q3bsp)
-#define SHADERPERMUTATION_GLOW (1<<3) // (lightmap) blend in an additive glow texture
-#define SHADERPERMUTATION_FOG (1<<4) // tint the color by fog color or black if using additive blend mode
-#define SHADERPERMUTATION_COLORMAPPING (1<<5) // indicates this is a colormapped skin
-#define SHADERPERMUTATION_SPECULAR (1<<6) // (lightsource or deluxemapping) render specular effects
-#define SHADERPERMUTATION_CUBEFILTER (1<<7) // (lightsource) use cubemap light filter
-#define SHADERPERMUTATION_OFFSETMAPPING (1<<8) // adjust texcoords to roughly simulate a displacement mapped surface
-#define SHADERPERMUTATION_SURFACENORMALIZE (1<<9) // (lightsource or deluxemapping) improved bumpmapping
-#define SHADERPERMUTATION_GEFORCEFX (1<<10) // use half vector types if available (NVIDIA specific)
-#define SHADERPERMUTATION_COUNT (1<<11) // how many permutations are possible
+#define SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE (1<<1) // (lightmap) use directional pixel shading from texture containing modelspace light directions (deluxemap)
+#define SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE (1<<2) // (lightmap) use directional pixel shading from texture containing tangentspace light directions (deluxemap)
+#define SHADERPERMUTATION_MODE_LIGHTDIRECTION (1<<3) // (lightmap) use directional pixel shading from fixed light direction (q3bsp)
+#define SHADERPERMUTATION_GLOW (1<<4) // (lightmap) blend in an additive glow texture
+#define SHADERPERMUTATION_FOG (1<<5) // tint the color by fog color or black if using additive blend mode
+#define SHADERPERMUTATION_COLORMAPPING (1<<6) // indicates this is a colormapped skin
+#define SHADERPERMUTATION_SPECULAR (1<<7) // (lightsource or deluxemapping) render specular effects
+#define SHADERPERMUTATION_CUBEFILTER (1<<8) // (lightsource) use cubemap light filter
+#define SHADERPERMUTATION_OFFSETMAPPING (1<<9) // adjust texcoords to roughly simulate a displacement mapped surface
+#define SHADERPERMUTATION_SURFACENORMALIZE (1<<10) // (lightsource or deluxemapping) improved bumpmapping
+#define SHADERPERMUTATION_GEFORCEFX (1<<11) // use half vector types if available (NVIDIA specific)
+#define SHADERPERMUTATION_COUNT (1<<12) // how many permutations are possible
 
 typedef struct r_glsl_permutation_s
 {