]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
OGG_FreeSfx and WAV_FreeSfx no longer reference sfx_t
[xonotic/darkplaces.git] / gl_rmain.c
index 8243ef922522c66c10c6af88509f6542718c9b1a..5ce992d643668ea89922fb5aa398d03abe76f9ba 100644 (file)
@@ -143,6 +143,7 @@ svbsp_t r_svbsp;
 
 rtexture_t *r_texture_blanknormalmap;
 rtexture_t *r_texture_white;
+rtexture_t *r_texture_grey128;
 rtexture_t *r_texture_black;
 rtexture_t *r_texture_notexture;
 rtexture_t *r_texture_whitecube;
@@ -235,6 +236,11 @@ static void R_BuildBlankTextures(void)
        data[2] = 255;
        data[3] = 255;
        r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
+       data[0] = 128;
+       data[1] = 128;
+       data[2] = 128;
+       data[3] = 255;
+       r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
        data[0] = 0;
        data[1] = 0;
        data[2] = 0;
@@ -656,7 +662,7 @@ static const char *builtinshaderstring =
 "#endif\n"
 "\n"
 "#ifdef USECONTRASTBOOST\n"
-"      color.rgb = SceneBrightness / (ContrastBoostCoeff + 1 / color.rgb);\n"
+"      color.rgb = color.rgb * SceneBrightness / (ContrastBoostCoeff * color.rgb + myhvec3(1, 1, 1));\n"
 "#else\n"
 "      color.rgb *= SceneBrightness;\n"
 "#endif\n"
@@ -807,7 +813,7 @@ void R_GLSL_CompilePermutation(const char *filename, int permutation)
                qglUseProgramObjectARB(0);CHECKGLERROR
        }
        else
-               Con_Printf("permutation%s failed for shader %s, some features may not work properly!\n", permutationname, "glsl/default.glsl");
+               Con_Printf("permutation%s failed for shader %s, some features may not work properly!\n", permutationname, filename);
        if (shaderstring)
                Mem_Free(shaderstring);
 }
@@ -821,6 +827,28 @@ void R_GLSL_Restart_f(void)
        memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
 }
 
+void R_GLSL_DumpShader_f(void)
+{
+       int i;
+
+       qfile_t *file = FS_Open("glsl/default.glsl", "w", false, false);
+       if(!file)
+       {
+               Con_Printf("failed to write to glsl/default.glsl\n");
+               return;
+       }
+
+       FS_Print(file, "// The engine may define the following macros:\n");
+       FS_Print(file, "// #define VERTEX_SHADER\n// #define GEOMETRY_SHADER\n// #define FRAGMENT_SHADER\n");
+       for (i = 0;permutationinfo[i][0];i++)
+               FS_Printf(file, "// %s", permutationinfo[i][0]);
+       FS_Print(file, "\n");
+       FS_Print(file, builtinshaderstring);
+       FS_Close(file);
+
+       Con_Printf("glsl/default.glsl written\n");
+}
+
 extern rtexture_t *r_shadow_attenuationgradienttexture;
 extern rtexture_t *r_shadow_attenuation2dtexture;
 extern rtexture_t *r_shadow_attenuation3dtexture;
@@ -832,6 +860,7 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, fl
        // fragment shader on features that are not being used
        const char *shaderfilename = NULL;
        unsigned int permutation = 0;
+       rtexture_t *nmap;
        r_glsl_permutation = NULL;
        // TODO: implement geometry-shader based shadow volumes someday
        if (rsurface.rtlight)
@@ -855,7 +884,7 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, fl
                        if (r_glsl_offsetmapping_reliefmapping.integer)
                                permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
                }
-               if(r_glsl_contrastboost.value != 1 && r_glsl_contrastboost.value != 0)
+               if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
                        permutation |= SHADERPERMUTATION_CONTRASTBOOST;
        }
        else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
@@ -875,7 +904,7 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, fl
                        if (r_glsl_offsetmapping_reliefmapping.integer)
                                permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
                }
-               if(r_glsl_contrastboost.value != 1 && r_glsl_contrastboost.value != 0)
+               if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
                        permutation |= SHADERPERMUTATION_CONTRASTBOOST;
        }
        else if (modellighting)
@@ -898,7 +927,7 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, fl
                        if (r_glsl_offsetmapping_reliefmapping.integer)
                                permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
                }
-               if(r_glsl_contrastboost.value != 1 && r_glsl_contrastboost.value != 0)
+               if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
                        permutation |= SHADERPERMUTATION_CONTRASTBOOST;
        }
        else
@@ -940,7 +969,7 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, fl
                        if (r_glsl_offsetmapping_reliefmapping.integer)
                                permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
                }
-               if(r_glsl_contrastboost.value != 1 && r_glsl_contrastboost.value != 0)
+               if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
                        permutation |= SHADERPERMUTATION_CONTRASTBOOST;
        }
        if (!r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].program)
@@ -951,14 +980,18 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, fl
                {
                        // remove features until we find a valid permutation
                        unsigned int i;
-                       for (i = SHADERPERMUTATION_MASK;;i>>=1)
+                       for (i = (SHADERPERMUTATION_MAX >> 1);;i>>=1)
                        {
                                if (!i)
-                                       return 0; // utterly failed
+                               {
+                                       Con_Printf("OpenGL 2.0 shaders disabled - unable to find a working shader permutation fallback on this driver (set r_glsl 1 if you want to try again)\n");
+                                       Cvar_SetValueQuick(&r_glsl, 0);
+                                       return 0; // no bit left to clear
+                               }
                                // reduce i more quickly whenever it would not remove any bits
-                               if (permutation < i)
+                               if (!(permutation & i))
                                        continue;
-                               permutation &= i;
+                               permutation &= ~i;
                                if (!r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].compiled)
                                        R_GLSL_CompilePermutation(shaderfilename, permutation);
                                if (r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].program)
@@ -1007,7 +1040,10 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, fl
                if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, r_refdef.lightmapintensity * 2.0f);
                if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, r_refdef.lightmapintensity * specularscale * 2.0f);
        }
-       if (r_glsl_permutation->loc_Texture_Normal >= 0) R_Mesh_TexBind(0, R_GetTexture(rsurface.texture->currentskinframe->nmap));
+       nmap = rsurface.texture->currentskinframe->nmap;
+       if (gl_lightmaps.integer)
+               nmap = r_texture_blanknormalmap;
+       if (r_glsl_permutation->loc_Texture_Normal >= 0) R_Mesh_TexBind(0, R_GetTexture(nmap));
        if (r_glsl_permutation->loc_Texture_Color >= 0) R_Mesh_TexBind(1, R_GetTexture(rsurface.texture->basetexture));
        if (r_glsl_permutation->loc_Texture_Gloss >= 0) R_Mesh_TexBind(2, R_GetTexture(rsurface.texture->glosstexture));
        //if (r_glsl_permutation->loc_Texture_Cube >= 0 && permutation & SHADERPERMUTATION_MODE_LIGHTSOURCE) R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap));
@@ -1206,7 +1242,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
 
        basepixels_width = image_width;
        basepixels_height = image_height;
-       skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);
+       skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, TEXTYPE_RGBA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);
 
        if (textureflags & TEXF_ALPHA)
        {
@@ -1224,7 +1260,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
                                pixels[j+2] = 255;
                                pixels[j+3] = basepixels[j+3];
                        }
-                       skinframe->fog = R_LoadTexture2D (r_main_texturepool, va("%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);
+                       skinframe->fog = R_LoadTexture2D (r_main_texturepool, va("%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);
                        Mem_Free(pixels);
                }
        }
@@ -1234,7 +1270,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
        {
                if ((pixels = loadimagepixels(va("%s_norm", skinframe->basename), false, 0, 0)) != NULL)
                {
-                       skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);
+                       skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags & (gl_texturecompression_normal.integer ? ~0 : ~TEXF_COMPRESS), NULL);
                        Mem_Free(pixels);
                        pixels = NULL;
                }
@@ -1242,7 +1278,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
                {
                        pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
                        Image_HeightmapToNormalmap(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
-                       skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);
+                       skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags & (gl_texturecompression_normal.integer ? ~0 : ~TEXF_COMPRESS), NULL);
                        Mem_Free(pixels);
                        Mem_Free(bumppixels);
                }
@@ -1250,17 +1286,17 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
                {
                        pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
                        Image_HeightmapToNormalmap(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
-                       skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);
+                       skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_RGBA, skinframe->textureflags & (gl_texturecompression_normal.integer ? ~0 : ~TEXF_COMPRESS), NULL);
                        Mem_Free(pixels);
                }
        }
        // _luma is supported for tenebrae compatibility
        // (I think it's a very stupid name, but oh well)
        // _glow is the preferred name
-       if (loadglow          && ((pixels = loadimagepixels(va("%s_glow", skinframe->basename), false, 0, 0)) != NULL || (pixels = loadimagepixels(va("%s_luma", skinframe->basename), false, 0, 0)) != NULL)) {skinframe->glow = R_LoadTexture2D (r_main_texturepool, va("%s_glow", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);Mem_Free(pixels);pixels = NULL;}
-       if (loadgloss         && (pixels = loadimagepixels(va("%s_gloss", skinframe->basename), false, 0, 0)) != NULL) {skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va("%s_gloss", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);Mem_Free(pixels);pixels = NULL;}
-       if (loadpantsandshirt && (pixels = loadimagepixels(va("%s_pants", skinframe->basename), false, 0, 0)) != NULL) {skinframe->pants = R_LoadTexture2D (r_main_texturepool, va("%s_pants", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);Mem_Free(pixels);pixels = NULL;}
-       if (loadpantsandshirt && (pixels = loadimagepixels(va("%s_shirt", skinframe->basename), false, 0, 0)) != NULL) {skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va("%s_shirt", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);Mem_Free(pixels);pixels = NULL;}
+       if (loadglow          && ((pixels = loadimagepixels(va("%s_glow", skinframe->basename), false, 0, 0)) != NULL || (pixels = loadimagepixels(va("%s_luma", skinframe->basename), false, 0, 0)) != NULL)) {skinframe->glow = R_LoadTexture2D (r_main_texturepool, va("%s_glow", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags & (gl_texturecompression_glow.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
+       if (loadgloss         && (pixels = loadimagepixels(va("%s_gloss", skinframe->basename), false, 0, 0)) != NULL) {skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va("%s_gloss", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags & (gl_texturecompression_gloss.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
+       if (loadpantsandshirt && (pixels = loadimagepixels(va("%s_pants", skinframe->basename), false, 0, 0)) != NULL) {skinframe->pants = R_LoadTexture2D (r_main_texturepool, va("%s_pants", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
+       if (loadpantsandshirt && (pixels = loadimagepixels(va("%s_shirt", skinframe->basename), false, 0, 0)) != NULL) {skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va("%s_shirt", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
 
        if (basepixels)
                Mem_Free(basepixels);
@@ -1317,10 +1353,10 @@ skinframe_t *R_SkinFrame_LoadInternal(const char *name, int textureflags, int lo
                        temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
                        temp2 = temp1 + width * height * 4;
                        Image_HeightmapToNormalmap(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
-                       skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_RGBA, textureflags | TEXF_ALPHA, NULL);
+                       skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_RGBA, skinframe->textureflags | TEXF_ALPHA, NULL);
                        Mem_Free(temp1);
                }
-               skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_RGBA, textureflags, NULL);
+               skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_RGBA, skinframe->textureflags, NULL);
                if (textureflags & TEXF_ALPHA)
                {
                        for (i = 3;i < width * height * 4;i += 4)
@@ -1332,7 +1368,7 @@ skinframe_t *R_SkinFrame_LoadInternal(const char *name, int textureflags, int lo
                                memcpy(fogpixels, skindata, width * height * 4);
                                for (i = 0;i < width * height * 4;i += 4)
                                        fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
-                               skinframe->fog = R_LoadTexture2D(r_main_texturepool, va("%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_RGBA, textureflags, NULL);
+                               skinframe->fog = R_LoadTexture2D(r_main_texturepool, va("%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);
                                Mem_Free(fogpixels);
                        }
                }
@@ -1351,20 +1387,20 @@ skinframe_t *R_SkinFrame_LoadInternal(const char *name, int textureflags, int lo
                                Image_Copy8bitRGBA(skindata, temp1, width * height, palette ? palette : palette_complete);
                                Image_HeightmapToNormalmap(temp1, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
                        }
-                       skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_RGBA, textureflags | TEXF_ALPHA, NULL);
+                       skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_RGBA, skinframe->textureflags | TEXF_ALPHA, NULL);
                        Mem_Free(temp1);
                }
                // use either a custom palette, or the quake palette
-               skinframe->base = skinframe->merged = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_merged", skinframe->basename), palette ? palette : (loadglowtexture ? palette_nofullbrights : ((textureflags & TEXF_ALPHA) ? palette_transparent : palette_complete)), textureflags, true); // all
+               skinframe->base = skinframe->merged = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_merged", skinframe->basename), palette ? palette : (loadglowtexture ? palette_nofullbrights : ((skinframe->textureflags & TEXF_ALPHA) ? palette_transparent : palette_complete)), skinframe->textureflags, true); // all
                if (!palette && loadglowtexture)
-                       skinframe->glow = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_glow", skinframe->basename), palette_onlyfullbrights, textureflags, false); // glow
+                       skinframe->glow = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_glow", skinframe->basename), palette_onlyfullbrights, skinframe->textureflags, false); // glow
                if (!palette && loadpantsandshirt)
                {
-                       skinframe->pants = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_pants", skinframe->basename), palette_pantsaswhite, textureflags, false); // pants
-                       skinframe->shirt = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_shirt", skinframe->basename), palette_shirtaswhite, textureflags, false); // shirt
+                       skinframe->pants = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_pants", skinframe->basename), palette_pantsaswhite, skinframe->textureflags, false); // pants
+                       skinframe->shirt = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_shirt", skinframe->basename), palette_shirtaswhite, skinframe->textureflags, false); // shirt
                }
                if (skinframe->pants || skinframe->shirt)
-                       skinframe->base = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_nospecial", skinframe->basename),loadglowtexture ? palette_nocolormapnofullbrights : palette_nocolormap, textureflags, false); // no special colors
+                       skinframe->base = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_nospecial", skinframe->basename),loadglowtexture ? palette_nocolormapnofullbrights : palette_nocolormap, skinframe->textureflags, false); // no special colors
                if (textureflags & TEXF_ALPHA)
                {
                        // if not using a custom alphapalette, use the quake one
@@ -1374,7 +1410,7 @@ skinframe_t *R_SkinFrame_LoadInternal(const char *name, int textureflags, int lo
                                if (((unsigned char *)alphapalette)[skindata[i]*4+3] < 255)
                                        break;
                        if (i < width * height)
-                               skinframe->fog = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_fog", skinframe->basename), alphapalette, textureflags, true); // fog mask
+                               skinframe->fog = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_fog", skinframe->basename), alphapalette, skinframe->textureflags, true); // fog mask
                }
        }
 
@@ -1453,6 +1489,7 @@ void gl_main_shutdown(void)
        R_FreeTexturePool(&r_main_texturepool);
        r_texture_blanknormalmap = NULL;
        r_texture_white = NULL;
+       r_texture_grey128 = NULL;
        r_texture_black = NULL;
        r_texture_whitecube = NULL;
        r_texture_normalizationcube = NULL;
@@ -1490,6 +1527,7 @@ void GL_Main_Init(void)
        r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
 
        Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
+       Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
        // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
        if (gamemode == GAME_NEHAHRA)
        {
@@ -1927,34 +1965,48 @@ static void R_View_SetFrustum(void)
 
 
 
-       slopex = 1.0 / r_view.frustum_x;
-       slopey = 1.0 / r_view.frustum_y;
-       VectorMA(r_view.forward, -slopex, r_view.left, r_view.frustum[0].normal);
-       VectorMA(r_view.forward,  slopex, r_view.left, r_view.frustum[1].normal);
-       VectorMA(r_view.forward, -slopey, r_view.up  , r_view.frustum[2].normal);
-       VectorMA(r_view.forward,  slopey, r_view.up  , r_view.frustum[3].normal);
-       VectorCopy(r_view.forward, r_view.frustum[4].normal);
-       VectorNormalize(r_view.frustum[0].normal);
-       VectorNormalize(r_view.frustum[1].normal);
-       VectorNormalize(r_view.frustum[2].normal);
-       VectorNormalize(r_view.frustum[3].normal);
-       r_view.frustum[0].dist = DotProduct (r_view.origin, r_view.frustum[0].normal);
-       r_view.frustum[1].dist = DotProduct (r_view.origin, r_view.frustum[1].normal);
-       r_view.frustum[2].dist = DotProduct (r_view.origin, r_view.frustum[2].normal);
-       r_view.frustum[3].dist = DotProduct (r_view.origin, r_view.frustum[3].normal);
-       r_view.frustum[4].dist = DotProduct (r_view.origin, r_view.frustum[4].normal) + r_refdef.nearclip;
+       if (r_view.useperspective)
+       {
+               slopex = 1.0 / r_view.frustum_x;
+               slopey = 1.0 / r_view.frustum_y;
+               VectorMA(r_view.forward, -slopex, r_view.left, r_view.frustum[0].normal);
+               VectorMA(r_view.forward,  slopex, r_view.left, r_view.frustum[1].normal);
+               VectorMA(r_view.forward, -slopey, r_view.up  , r_view.frustum[2].normal);
+               VectorMA(r_view.forward,  slopey, r_view.up  , r_view.frustum[3].normal);
+               VectorCopy(r_view.forward, r_view.frustum[4].normal);
+
+               // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
+               VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[0]);
+               VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward,  1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[1]);
+               VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left,  1024 * slopey, r_view.up, r_view.frustumcorner[2]);
+               VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward,  1024 * slopex, r_view.left,  1024 * slopey, r_view.up, r_view.frustumcorner[3]);
+
+               r_view.frustum[0].dist = DotProduct (r_view.origin, r_view.frustum[0].normal);
+               r_view.frustum[1].dist = DotProduct (r_view.origin, r_view.frustum[1].normal);
+               r_view.frustum[2].dist = DotProduct (r_view.origin, r_view.frustum[2].normal);
+               r_view.frustum[3].dist = DotProduct (r_view.origin, r_view.frustum[3].normal);
+               r_view.frustum[4].dist = DotProduct (r_view.origin, r_view.frustum[4].normal) + r_refdef.nearclip;
+       }
+       else
+       {
+               VectorScale(r_view.left, -r_view.ortho_x, r_view.frustum[0].normal);
+               VectorScale(r_view.left,  r_view.ortho_x, r_view.frustum[1].normal);
+               VectorScale(r_view.up, -r_view.ortho_y, r_view.frustum[2].normal);
+               VectorScale(r_view.up,  r_view.ortho_y, r_view.frustum[3].normal);
+               VectorCopy(r_view.forward, r_view.frustum[4].normal);
+               r_view.frustum[0].dist = DotProduct (r_view.origin, r_view.frustum[0].normal) + r_view.ortho_x;
+               r_view.frustum[1].dist = DotProduct (r_view.origin, r_view.frustum[1].normal) + r_view.ortho_x;
+               r_view.frustum[2].dist = DotProduct (r_view.origin, r_view.frustum[2].normal) + r_view.ortho_y;
+               r_view.frustum[3].dist = DotProduct (r_view.origin, r_view.frustum[3].normal) + r_view.ortho_y;
+               r_view.frustum[4].dist = DotProduct (r_view.origin, r_view.frustum[4].normal) + r_refdef.nearclip;
+       }
+
        PlaneClassify(&r_view.frustum[0]);
        PlaneClassify(&r_view.frustum[1]);
        PlaneClassify(&r_view.frustum[2]);
        PlaneClassify(&r_view.frustum[3]);
        PlaneClassify(&r_view.frustum[4]);
 
-       // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
-       VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[0]);
-       VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward,  1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[1]);
-       VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left,  1024 * slopey, r_view.up, r_view.frustumcorner[2]);
-       VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward,  1024 * slopex, r_view.left,  1024 * slopey, r_view.up, r_view.frustumcorner[3]);
-
        // LordHavoc: note to all quake engine coders, Quake had a special case
        // for 90 degrees which assumed a square view (wrong), so I removed it,
        // Quake2 has it disabled as well.
@@ -1994,7 +2046,9 @@ void R_View_Update(void)
 
 void R_SetupView(const matrix4x4_t *matrix)
 {
-       if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows)
+       if (!r_view.useperspective)
+               GL_SetupView_Mode_Ortho(-r_view.ortho_x, -r_view.ortho_y, r_view.ortho_x, r_view.ortho_y, -r_refdef.farclip, r_refdef.farclip);
+       else if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows)
                GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip);
        else
                GL_SetupView_Mode_Perspective(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip, r_refdef.farclip);
@@ -3239,7 +3293,7 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
                {
                        // use an alternate animation if the entity's frame is not 0,
                        // and only if the texture has an alternate animation
-                       if (ent->frame != 0 && t->anim_total[1])
+                       if (ent->frame2 != 0 && t->anim_total[1])
                                t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[1]) : 0];
                        else
                                t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[0]) : 0];
@@ -3254,7 +3308,7 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
                {
                        strlcpy(r_qwskincache[i], cl.scores[i].qw_skin, sizeof(r_qwskincache[i]));
                        Con_DPrintf("loading skins/%s\n", r_qwskincache[i]);
-                       r_qwskincache_skinframe[i] = R_SkinFrame_LoadExternal(va("skins/%s", r_qwskincache[i]), TEXF_PRECACHE | (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, developer.integer > 0);
+                       r_qwskincache_skinframe[i] = R_SkinFrame_LoadExternal(va("skins/%s", r_qwskincache[i]), TEXF_PRECACHE | (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP | TEXF_COMPRESS, developer.integer > 0);
                }
                t->currentskinframe = r_qwskincache_skinframe[i];
                if (t->currentskinframe == NULL)
@@ -3361,15 +3415,24 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
                        t->specularscale = r_shadow_gloss2intensity.value;
        }
 
-       t->currentpolygonfactor = r_refdef.polygonfactor;
-       t->currentpolygonoffset = r_refdef.polygonoffset;
+       // lightmaps mode looks bad with dlights using actual texturing, so turn
+       // off the colormap and glossmap, but leave the normalmap on as it still
+       // accurately represents the shading involved
+       if (gl_lightmaps.integer && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
+       {
+               t->basetexture = r_texture_white;
+               t->specularscale = 0;
+       }
+
+       t->currentpolygonfactor = r_refdef.polygonfactor + t->basepolygonfactor;
+       t->currentpolygonoffset = r_refdef.polygonoffset + t->basepolygonoffset;
        // submodels are biased to avoid z-fighting with world surfaces that they
        // may be exactly overlapping (avoids z-fighting artifacts on certain
        // doors and things in Quake maps)
        if (ent->model->brush.submodel)
        {
-               t->currentpolygonfactor = r_refdef.polygonfactor + r_polygonoffset_submodel_factor.value;
-               t->currentpolygonoffset = r_refdef.polygonoffset + r_polygonoffset_submodel_offset.value;
+               t->currentpolygonfactor += r_polygonoffset_submodel_factor.value;
+               t->currentpolygonoffset += r_polygonoffset_submodel_offset.value;
        }
 
        VectorClear(t->dlightcolor);
@@ -3425,6 +3488,7 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
                                        // q3bsp has no lightmap updates, so the lightstylevalue that
                                        // would normally be baked into the lightmap must be
                                        // applied to the color
+                                       // FIXME: r_glsl 1 rendering doesn't support overbright lightstyles with this (the default light style is not overbright)
                                        if (ent->model->type == mod_brushq3)
                                                colorscale *= r_refdef.lightstylevalue[0] * (1.0f / 256.0f);
                                        colorscale *= r_refdef.lightmapintensity;
@@ -3813,13 +3877,16 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta
                        {
                                const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
                                const float *v1, *v2;
+                               vec3_t start, end;
                                float f, l;
                                struct
                                {
                                        float length2;
-                                       int quadedge;
+                                       const float *v1;
+                                       const float *v2;
                                }
                                shortest[2];
+                               memset(shortest, 0, sizeof(shortest));
                                // a single autosprite surface can contain multiple sprites...
                                for (j = 0;j < surface->num_vertices - 3;j += 4)
                                {
@@ -3827,43 +3894,74 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta
                                        for (i = 0;i < 4;i++)
                                                VectorAdd(center, (rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
                                        VectorScale(center, 0.25f, center);
-                                       shortest[0].quadedge = shortest[1].quadedge = 0;
-                                       shortest[0].length2 = shortest[1].length2 = 0;
                                        // find the two shortest edges, then use them to define the
                                        // axis vectors for rotating around the central axis
                                        for (i = 0;i < 6;i++)
                                        {
                                                v1 = rsurface.vertex3f + 3 * (surface->num_firstvertex + quadedges[i][0]);
                                                v2 = rsurface.vertex3f + 3 * (surface->num_firstvertex + quadedges[i][1]);
+#if 0
+                                               Debug_PolygonBegin(NULL, 0, false, 0);
+                                               Debug_PolygonVertex(v1[0], v1[1], v1[2], 0, 0, 1, 0, 0, 1);
+                                               Debug_PolygonVertex((v1[0] + v2[0]) * 0.5f + rsurface.normal3f[3 * (surface->num_firstvertex + j)+0] * 4, (v1[1] + v2[1]) * 0.5f + rsurface.normal3f[3 * (surface->num_firstvertex + j)+1], (v1[2] + v2[2]) * 0.5f + rsurface.normal3f[3 * (surface->num_firstvertex + j)+2], 0, 0, 1, 1, 0, 1);
+                                               Debug_PolygonVertex(v2[0], v2[1], v2[2], 0, 0, 1, 0, 0, 1);
+                                               Debug_PolygonEnd();
+#endif
                                                l = VectorDistance2(v1, v2);
+                                               // this length bias tries to make sense of square polygons, assuming they are meant to be upright
+                                               if (v1[2] != v2[2])
+                                                       l += (1.0f / 1024.0f);
                                                if (shortest[0].length2 > l || i == 0)
                                                {
                                                        shortest[1] = shortest[0];
                                                        shortest[0].length2 = l;
-                                                       shortest[0].quadedge = i;
+                                                       shortest[0].v1 = v1;
+                                                       shortest[0].v2 = v2;
                                                }
                                                else if (shortest[1].length2 > l || i == 1)
                                                {
                                                        shortest[1].length2 = l;
-                                                       shortest[1].quadedge = i;
+                                                       shortest[1].v1 = v1;
+                                                       shortest[1].v2 = v2;
                                                }
                                        }
-                                       // this calculates the midpoints *2 (not bothering to average) of the two shortest edges, and subtracts one from the other to get the up vector
-                                       for (i = 0;i < 3;i++)
-                                       {
-                                               right[i] = rsurface.vertex3f[3 * (surface->num_firstvertex + quadedges[shortest[1].quadedge][1]) + i]
-                                                                + rsurface.vertex3f[3 * (surface->num_firstvertex + quadedges[shortest[1].quadedge][0]) + i];
-                                               up[i] = rsurface.vertex3f[3 * (surface->num_firstvertex + quadedges[shortest[1].quadedge][0]) + i]
-                                                         + rsurface.vertex3f[3 * (surface->num_firstvertex + quadedges[shortest[1].quadedge][1]) + i]
-                                                         - rsurface.vertex3f[3 * (surface->num_firstvertex + quadedges[shortest[0].quadedge][0]) + i]
-                                                         - rsurface.vertex3f[3 * (surface->num_firstvertex + quadedges[shortest[0].quadedge][1]) + i];
-                                       }
+                                       VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
+                                       VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
+#if 0
+                                       Debug_PolygonBegin(NULL, 0, false, 0);
+                                       Debug_PolygonVertex(start[0], start[1], start[2], 0, 0, 1, 1, 0, 1);
+                                       Debug_PolygonVertex(center[0] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+0] * 4, center[1] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+1] * 4, center[2] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+2] * 4, 0, 0, 0, 1, 0, 1);
+                                       Debug_PolygonVertex(end[0], end[1], end[2], 0, 0, 0, 1, 1, 1);
+                                       Debug_PolygonEnd();
+#endif
+                                       // this calculates the right vector from the shortest edge
+                                       // and the up vector from the edge midpoints
+                                       VectorSubtract(shortest[0].v1, shortest[0].v2, right);
+                                       VectorNormalize(right);
+                                       VectorSubtract(end, start, up);
+                                       VectorNormalize(up);
                                        // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
-                                       VectorSubtract(rsurface.modelorg, center, forward);
+                                       //VectorSubtract(rsurface.modelorg, center, forward);
+                                       Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.forward, forward);
+                                       VectorNegate(forward, forward);
+                                       VectorReflect(forward, 0, up, forward);
+                                       VectorNormalize(forward);
                                        CrossProduct(up, forward, newright);
-                                       // normalize the vectors involved
-                                       VectorNormalize(right);
                                        VectorNormalize(newright);
+#if 0
+                                       Debug_PolygonBegin(NULL, 0, false, 0);
+                                       Debug_PolygonVertex(center[0] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+0] * 8, center[1] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+1] * 8, center[2] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+2] * 8, 0, 0, 1, 0, 0, 1);
+                                       Debug_PolygonVertex(center[0] + right[0] * 8, center[1] + right[1] * 8, center[2] + right[2] * 8, 0, 0, 0, 1, 0, 1);
+                                       Debug_PolygonVertex(center[0] + up   [0] * 8, center[1] + up   [1] * 8, center[2] + up   [2] * 8, 0, 0, 0, 0, 1, 1);
+                                       Debug_PolygonEnd();
+#endif
+#if 0
+                                       Debug_PolygonBegin(NULL, 0, false, 0);
+                                       Debug_PolygonVertex(center[0] + forward [0] * 8, center[1] + forward [1] * 8, center[2] + forward [2] * 8, 0, 0, 1, 0, 0, 1);
+                                       Debug_PolygonVertex(center[0] + newright[0] * 8, center[1] + newright[1] * 8, center[2] + newright[2] * 8, 0, 0, 0, 1, 0, 1);
+                                       Debug_PolygonVertex(center[0] + up      [0] * 8, center[1] + up      [1] * 8, center[2] + up      [2] * 8, 0, 0, 0, 0, 1, 1);
+                                       Debug_PolygonEnd();
+#endif
                                        // rotate the quad around the up axis vector, this is made
                                        // especially easy by the fact we know the quad is flat,
                                        // so we only have to subtract the center position and
@@ -3874,12 +3972,12 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta
                                        // displacement from the center, which we do with a
                                        // DotProduct, the subtraction/addition of center is also
                                        // optimized into DotProducts here
-                                       l = DotProduct(newright, center) - DotProduct(right, center);
+                                       l = DotProduct(right, center);
                                        for (i = 0;i < 4;i++)
                                        {
                                                v1 = rsurface.vertex3f + 3 * (surface->num_firstvertex + j + i);
-                                               f = DotProduct(right, v1) - DotProduct(newright, v1) + l;
-                                               VectorMA(v1, f, newright, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
+                                               f = DotProduct(right, v1) - l;
+                                               VectorMAMAM(1, v1, -f, right, f, newright, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
                                        }
                                }
                                Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer);
@@ -4590,7 +4688,7 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **t
        GL_Color(rsurface.texture->currentlayers[0].color[0], rsurface.texture->currentlayers[0].color[1], rsurface.texture->currentlayers[0].color[2], rsurface.texture->currentlayers[0].color[3]);
        if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
        {
-               R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
+               R_Mesh_TexBind(7, R_GetTexture(r_texture_grey128));
                if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
                        R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
                R_Mesh_ColorPointer(NULL, 0, 0);
@@ -4940,6 +5038,8 @@ static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **textur
                GL_DepthMask(writedepth);
                GL_Color(1,1,1,1);
                GL_AlphaTest(false);
+               // use lightmode 0 (fullbright or lightmap) or 2 (model lighting)
+               rsurface.lightmode = ((rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || rsurface.modeltexcoordlightmap2f != NULL) ? 0 : 2;
                R_Mesh_ColorPointer(NULL, 0, 0);
                memset(&m, 0, sizeof(m));
                m.tex[0] = R_GetTexture(r_texture_white);
@@ -4964,7 +5064,7 @@ static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **textur
        else if (rsurface.texture->currentnumlayers)
        {
                // write depth for anything we skipped on the depth-only pass earlier
-               if (!writedepth && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
+               if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
                        writedepth = true;
                GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
                GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);