reworked most of q3bsp q3 shader loading, now supports more shader effects (the first...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 18 Apr 2006 10:44:11 +0000 (10:44 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 18 Apr 2006 10:44:11 +0000 (10:44 +0000)
q3 fog shaders are usually invisible now (looks better than blinding white surfaces)
added support for more hacky q3 shaders (like sky shaders that don't have surfaceparm sky, and transparent shaders that don't have surfaceparm trans)
added support for alpha test in q3 shaders (improves some shaders)

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

gl_rmain.c
gl_rsurf.c
model_alias.c
model_brush.c
model_brush.h
model_shared.h
r_shadow.c

index 4b68e50..6fdd91f 100644 (file)
@@ -2278,9 +2278,9 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
        if (!(ent->flags & RENDER_LIGHT))
                t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT;
        if (ent->effects & EF_ADDITIVE)
-               t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_TRANSPARENT;
+               t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT;
        else if (t->currentalpha < 1)
-               t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT;
+               t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT;
        if (ent->effects & EF_NODEPTHTEST)
                t->currentmaterialflags |= MATERIALFLAG_NODEPTHTEST;
        if (t->currentmaterialflags & MATERIALFLAG_WATER && r_waterscroll.value != 0)
@@ -2319,25 +2319,28 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
                        {
                                blendfunc1 = GL_SRC_ALPHA;
                                blendfunc2 = GL_ONE;
-                               depthmask = false;
                        }
                        else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
                        {
                                blendfunc1 = GL_SRC_ALPHA;
                                blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
-                               depthmask = false;
+                       }
+                       else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
+                       {
+                               blendfunc1 = t->customblendfunc[0];
+                               blendfunc2 = t->customblendfunc[1];
                        }
                        else
                        {
                                blendfunc1 = GL_ONE;
                                blendfunc2 = GL_ZERO;
-                               depthmask = true;
                        }
+                       depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
                        if (t->currentmaterialflags & (MATERIALFLAG_WATER | MATERIALFLAG_WALL))
                        {
                                rtexture_t *currentbasetexture;
                                int layerflags = 0;
-                               if (fogenabled && (t->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
+                               if (fogenabled && (t->currentmaterialflags & MATERIALFLAG_BLENDED))
                                        layerflags |= TEXTURELAYERFLAG_FOGDARKEN;
                                currentbasetexture = (VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) < (1.0f / 1048576.0f) && t->skin.merged) ? t->skin.merged : t->skin.base;
                                if (t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
@@ -2361,7 +2364,7 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
                                        colorscale *= r_lightmapintensity;
                                        if (r_textureunits.integer >= 2 && gl_combine.integer)
                                                R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE_COMBINE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * colorscale, ent->colormod[1] * colorscale, ent->colormod[2] * colorscale, t->currentalpha);
-                                       else if ((t->currentmaterialflags & MATERIALFLAG_TRANSPARENT) == 0)
+                                       else if ((t->currentmaterialflags & MATERIALFLAG_BLENDED) == 0)
                                                R_Texture_AddLayer(t, true, GL_ONE, GL_ZERO, TEXTURELAYERTYPE_LITTEXTURE_MULTIPASS, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * colorscale * 0.5f, ent->colormod[1] * colorscale * 0.5f, ent->colormod[2] * colorscale * 0.5f, t->currentalpha);
                                        else
                                                R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE_VERTEX, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * colorscale, ent->colormod[1] * colorscale, ent->colormod[2] * colorscale, t->currentalpha);
@@ -2395,7 +2398,7 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
                                        // were darkened by fog already, and we should not add fog color
                                        // (because the background was not darkened, there is no fog color
                                        // that was lost behind it).
-                                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, (t->currentmaterialflags & MATERIALFLAG_TRANSPARENT) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA, TEXTURELAYERTYPE_FOG, t->skin.fog, &identitymatrix, fogcolor[0], fogcolor[1], fogcolor[2], t->currentalpha);
+                                       R_Texture_AddLayer(t, false, GL_SRC_ALPHA, (t->currentmaterialflags & MATERIALFLAG_BLENDED) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA, TEXTURELAYERTYPE_FOG, t->skin.fog, &identitymatrix, fogcolor[0], fogcolor[1], fogcolor[2], t->currentalpha);
                                }
                        }
                }
@@ -2748,23 +2751,10 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                        }
                }
        }
-       else if (r_glsl.integer && gl_support_fragment_shader)
+       else if (texture->currentnumlayers && r_glsl.integer && gl_support_fragment_shader)
        {
-               if (texture->currentmaterialflags & MATERIALFLAG_ADD)
-               {
-                       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
-                       GL_DepthMask(false);
-               }
-               else if (texture->currentmaterialflags & MATERIALFLAG_ALPHA)
-               {
-                       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-                       GL_DepthMask(false);
-               }
-               else
-               {
-                       GL_BlendFunc(GL_ONE, GL_ZERO);
-                       GL_DepthMask(true);
-               }
+               GL_BlendFunc(texture->currentlayers[0].blendfunc1, texture->currentlayers[0].blendfunc2);
+               GL_DepthMask(!(texture->currentmaterialflags & MATERIALFLAG_BLENDED));
 
                R_Mesh_ColorPointer(NULL);
                R_Mesh_ResetTextureState();
@@ -2795,11 +2785,15 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                                R_Mesh_ColorPointer(model->surfmesh.data_lightmapcolor4f);
                        }
                }
+               if (texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
+                       qglEnable(GL_ALPHA_TEST);
                for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
                {
                        const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
                        RSurf_Draw(surface);
                }
+               if (texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
+                       qglDisable(GL_ALPHA_TEST);
                qglUseProgramObjectARB(0);
        }
        else if (texture->currentnumlayers)
@@ -2811,6 +2805,16 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                {
                        vec4_t layercolor;
                        int layertexrgbscale;
+                       if (texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
+                       {
+                               if (layerindex == 0)
+                                       qglEnable(GL_ALPHA_TEST);
+                               else
+                               {
+                                       qglDisable(GL_ALPHA_TEST);
+                                       qglDepthFunc(GL_EQUAL);
+                               }
+                       }
                        GL_DepthMask(layer->depthmask);
                        GL_BlendFunc(layer->blendfunc1, layer->blendfunc2);
                        if ((layer->color[0] > 2 || layer->color[1] > 2 || layer->color[2] > 2) && (gl_combine.integer || layer->depthmask))
@@ -3006,6 +3010,11 @@ static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *text
                                GL_LockArrays(0, 0);
                        }
                }
+               if (texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
+               {
+                       qglDepthFunc(GL_LEQUAL);
+                       qglDisable(GL_ALPHA_TEST);
+               }
        }
        GL_LockArrays(0, 0);
        if ((texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (ent->flags & RENDER_NOCULLFACE))
@@ -3032,7 +3041,7 @@ void R_QueueTextureSurfaceList(entity_render_t *ent, texture_t *texture, rtextur
 {
        int texturesurfaceindex;
        vec3_t tempcenter, center;
-       if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)
+       if (texture->currentmaterialflags & MATERIALFLAG_BLENDED)
        {
                // drawing sky transparently would be too difficult
                if (!(texture->currentmaterialflags & MATERIALFLAG_SKY))
index e21fcc1..1cb6808 100644 (file)
@@ -835,7 +835,7 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surface
                {
                        if (batchnumsurfaces > 0)
                        {
-                               if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)
+                               if (texture->currentmaterialflags & MATERIALFLAG_BLENDED)
                                        R_Q1BSP_DrawLight_TransparentBatch(ent, texture, batchnumsurfaces, batchsurfacelist);
                                else
                                        R_Shadow_RenderSurfacesLighting(ent, texture, batchnumsurfaces, batchsurfacelist);
@@ -851,7 +851,7 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surface
                {
                        if (batchnumsurfaces == RSURF_MAX_BATCHSURFACES)
                        {
-                               if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)
+                               if (texture->currentmaterialflags & MATERIALFLAG_BLENDED)
                                        R_Q1BSP_DrawLight_TransparentBatch(ent, texture, batchnumsurfaces, batchsurfacelist);
                                else
                                        R_Shadow_RenderSurfacesLighting(ent, texture, batchnumsurfaces, batchsurfacelist);
@@ -862,7 +862,7 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surface
        }
        if (batchnumsurfaces > 0)
        {
-               if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)
+               if (texture->currentmaterialflags & MATERIALFLAG_BLENDED)
                        R_Q1BSP_DrawLight_TransparentBatch(ent, texture, batchnumsurfaces, batchsurfacelist);
                else
                        R_Shadow_RenderSurfacesLighting(ent, texture, batchnumsurfaces, batchsurfacelist);
index beb9b00..4a9cf05 100644 (file)
@@ -399,7 +399,7 @@ static void Mod_BuildAliasSkinFromSkinFrame(texture_t *skin, skinframe_t *skinfr
        skin->currentframe = skin;
        skin->basematerialflags = MATERIALFLAG_WALL;
        if (skin->skin.fog)
-               skin->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT;
+               skin->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT;
        skin->currentmaterialflags = skin->basematerialflags;
 }
 
index d8e5bdf..816e3b1 100644 (file)
@@ -1418,7 +1418,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l)
                        tx->basematerialflags |= MATERIALFLAG_WALL;
                }
                if (tx->skin.fog)
-                       tx->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT;
+                       tx->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT;
 
                // start out with no animation
                tx->currentframe = tx;
@@ -3927,274 +3927,436 @@ static void Mod_Q3BSP_LoadEntities(lump_t *l)
        }
 }
 
-static void Mod_Q3BSP_LoadTextures(lump_t *l)
+// FIXME: make MAXSHADERS dynamic
+#define Q3SHADER_MAXSHADERS 4096
+#define Q3SHADER_MAXLAYERS 8
+
+typedef struct q3shaderinfo_layer_s
 {
-       q3dtexture_t *in;
-       texture_t *out;
-       int i, count;
-       int j, c;
+       char texturename[Q3PATHLENGTH];
+       int blendfunc[2];
+       qboolean rgbgenvertex;
+       qboolean alphagenvertex;
+}
+q3shaderinfo_layer_t;
+
+typedef struct q3shaderinfo_s
+{
+       char name[Q3PATHLENGTH];
+       int surfaceparms;
+       int textureflags;
+       int numlayers;
+       qboolean lighting;
+       qboolean vertexalpha;
+       qboolean textureblendalpha;
+       q3shaderinfo_layer_t *primarylayer, *backgroundlayer;
+       q3shaderinfo_layer_t layers[Q3SHADER_MAXLAYERS];
+       char skyboxname[Q3PATHLENGTH];
+}
+q3shaderinfo_t;
+
+int q3shaders_numshaders;
+q3shaderinfo_t q3shaders_shaders[Q3SHADER_MAXSHADERS];
+
+static void Mod_Q3BSP_LoadShaders(void)
+{
+       int j;
+       int fileindex;
        fssearch_t *search;
        char *f;
        const char *text;
-       int flags, flags2, numparameters, passnumber;
-       char shadername[Q3PATHLENGTH];
-       char sky[Q3PATHLENGTH];
-       char firstpasstexturename[Q3PATHLENGTH];
+       q3shaderinfo_t *shader;
+       q3shaderinfo_layer_t *layer;
+       int numparameters;
        char parameter[4][Q3PATHLENGTH];
-
-       in = (q3dtexture_t *)(mod_base + l->fileofs);
-       if (l->filelen % sizeof(*in))
-               Host_Error("Mod_Q3BSP_LoadTextures: funny lump size in %s",loadmodel->name);
-       count = l->filelen / sizeof(*in);
-       out = (texture_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
-
-       loadmodel->data_textures = out;
-       loadmodel->num_textures = count;
-
-       for (i = 0;i < count;i++, in++, out++)
-       {
-               strlcpy (out->name, in->name, sizeof (out->name));
-               out->surfaceflags = LittleLong(in->surfaceflags);
-               out->supercontents = Mod_Q3BSP_SuperContentsFromNativeContents(loadmodel, LittleLong(in->contents));
-               out->surfaceparms = -1;
-       }
-
-       // do a quick parse of shader files to get surfaceparms
-       if ((search = FS_Search("scripts/*.shader", true, false)))
+       search = FS_Search("scripts/*.shader", true, false);
+       if (!search)
+               return;
+       q3shaders_numshaders = 0;
+       for (fileindex = 0;fileindex < search->numfilenames;fileindex++)
        {
-               for (i = 0;i < search->numfilenames;i++)
+               text = f = (char *)FS_LoadFile(search->filenames[fileindex], tempmempool, false, NULL);
+               if (!f)
+                       continue;
+               while (COM_ParseToken(&text, false))
                {
-                       if ((f = (char *)FS_LoadFile(search->filenames[i], tempmempool, false, NULL)))
+                       if (q3shaders_numshaders >= Q3SHADER_MAXSHADERS)
+                       {
+                               Con_Printf("Mod_Q3BSP_LoadShaders: too many shaders!\n");
+                               break;
+                       }
+                       shader = q3shaders_shaders + q3shaders_numshaders++;
+                       memset(shader, 0, sizeof(*shader));
+                       strlcpy(shader->name, com_token, sizeof(shader->name));
+                       if (!COM_ParseToken(&text, false) || strcasecmp(com_token, "{"))
                        {
-                               text = f;
-                               while (COM_ParseToken(&text, false))
+                               Con_Printf("%s parsing error - expected \"{\", found \"%s\"\n", search->filenames[fileindex], com_token);
+                               break;
+                       }
+                       while (COM_ParseToken(&text, false))
+                       {
+                               if (!strcasecmp(com_token, "}"))
+                                       break;
+                               if (!strcasecmp(com_token, "{"))
                                {
-                                       strlcpy (shadername, com_token, sizeof (shadername));
-                                       flags = 0;
-                                       flags2 = 0;
-                                       sky[0] = 0;
-                                       passnumber = 0;
-                                       firstpasstexturename[0] = 0;
-                                       if (COM_ParseToken(&text, false) && !strcasecmp(com_token, "{"))
+                                       if (shader->numlayers < Q3SHADER_MAXLAYERS)
                                        {
-                                               while (COM_ParseToken(&text, false))
+                                               layer = shader->layers + shader->numlayers++;
+                                               layer->rgbgenvertex = false;
+                                               layer->alphagenvertex = false;
+                                               layer->blendfunc[0] = GL_ONE;
+                                               layer->blendfunc[1] = GL_ZERO;
+                                       }
+                                       else
+                                               layer = NULL;
+                                       while (COM_ParseToken(&text, false))
+                                       {
+                                               if (!strcasecmp(com_token, "}"))
+                                                       break;
+                                               if (!strcasecmp(com_token, "\n"))
+                                                       continue;
+                                               if (layer == NULL)
+                                                       continue;
+                                               numparameters = 0;
+                                               for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
                                                {
-                                                       if (!strcasecmp(com_token, "}"))
-                                                               break;
-                                                       else if (!strcasecmp(com_token, "{"))
+                                                       if (j < 4)
                                                        {
-                                                               while (COM_ParseToken(&text, false))
-                                                               {
-                                                                       if (!strcasecmp(com_token, "}"))
-                                                                               break;
-                                                                       if (!strcasecmp(com_token, "\n"))
-                                                                               continue;
-                                                                       numparameters = 0;
-                                                                       for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
-                                                                       {
-                                                                               if (j < 4)
-                                                                               {
-                                                                                       strlcpy(parameter[j], com_token, sizeof(parameter[j]));
-                                                                                       numparameters = j + 1;
-                                                                               }
-                                                                               if (!COM_ParseToken(&text, true))
-                                                                                       break;
-                                                                       }
-                                                                       if (developer.integer >= 100)
-                                                                       {
-                                                                               Con_Printf("%s %i: ", shadername, passnumber);
-                                                                               for (j = 0;j < numparameters;j++)
-                                                                                       Con_Printf(" %s", parameter[j]);
-                                                                               Con_Print("\n");
-                                                                       }
-                                                                       if (passnumber == 0 && numparameters >= 1)
-                                                                       {
-                                                                               if (!strcasecmp(parameter[0], "blendfunc") && (flags & Q3SURFACEPARM_TRANS))
-                                                                               {
-                                                                                       if (numparameters == 2 && !strcasecmp(parameter[1], "add"))
-                                                                                               flags2 |= Q3TEXTUREFLAG_ADDITIVE;
-                                                                                       else if (numparameters == 3 && !strcasecmp(parameter[1], "gl_one") && !strcasecmp(parameter[2], "gl_one"))
-                                                                                               flags2 |= Q3TEXTUREFLAG_ADDITIVE;
-                                                                                       else if (numparameters == 3 && !strcasecmp(parameter[1], "gl_src_alpha") && !strcasecmp(parameter[2], "gl_one"))
-                                                                                               flags2 |= Q3TEXTUREFLAG_ADDITIVE;
-                                                                               }
-                                                                               else if (numparameters >= 2 && (!strcasecmp(parameter[0], "map") || !strcasecmp(parameter[0], "clampmap")))
-                                                                                       strlcpy(firstpasstexturename, parameter[1], sizeof(firstpasstexturename));
-                                                                               else if (numparameters >= 3 && !strcasecmp(parameter[0], "animmap"))
-                                                                                       strlcpy(firstpasstexturename, parameter[2], sizeof(firstpasstexturename));
-                                                                               else if (numparameters >= 2 && !strcasecmp(parameter[0], "alphafunc"))
-                                                                                       flags2 |= Q3TEXTUREFLAG_ALPHATEST;
-                                                                       }
-                                                                       // break out a level if it was }
-                                                                       if (!strcasecmp(com_token, "}"))
-                                                                               break;
-                                                               }
-                                                               passnumber++;
-                                                               continue;
+                                                               strlcpy(parameter[j], com_token, sizeof(parameter[j]));
+                                                               numparameters = j + 1;
                                                        }
-                                                       numparameters = 0;
-                                                       for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
-                                                       {
-                                                               if (j < 4)
-                                                               {
-                                                                       strlcpy(parameter[j], com_token, sizeof(parameter[j]));
-                                                                       numparameters = j + 1;
-                                                               }
-                                                               if (!COM_ParseToken(&text, true))
-                                                                       break;
-                                                       }
-                                                       if (i == 0 && !strcasecmp(com_token, "}"))
+                                                       if (!COM_ParseToken(&text, true))
                                                                break;
-                                                       if (developer.integer >= 100)
-                                                       {
-                                                               Con_Printf("%s: ", shadername);
-                                                               for (j = 0;j < numparameters;j++)
-                                                                       Con_Printf(" %s", parameter[j]);
-                                                               Con_Print("\n");
-                                                       }
-                                                       if (numparameters < 1)
-                                                               continue;
-                                                       if (!strcasecmp(parameter[0], "surfaceparm") && numparameters >= 2)
-                                                       {
-                                                               if (!strcasecmp(parameter[1], "alphashadow"))
-                                                                       flags |= Q3SURFACEPARM_ALPHASHADOW;
-                                                               else if (!strcasecmp(parameter[1], "areaportal"))
-                                                                       flags |= Q3SURFACEPARM_AREAPORTAL;
-                                                               else if (!strcasecmp(parameter[1], "clusterportal"))
-                                                                       flags |= Q3SURFACEPARM_CLUSTERPORTAL;
-                                                               else if (!strcasecmp(parameter[1], "detail"))
-                                                                       flags |= Q3SURFACEPARM_DETAIL;
-                                                               else if (!strcasecmp(parameter[1], "donotenter"))
-                                                                       flags |= Q3SURFACEPARM_DONOTENTER;
-                                                               else if (!strcasecmp(parameter[1], "fog"))
-                                                                       flags |= Q3SURFACEPARM_FOG;
-                                                               else if (!strcasecmp(parameter[1], "lava"))
-                                                                       flags |= Q3SURFACEPARM_LAVA;
-                                                               else if (!strcasecmp(parameter[1], "lightfilter"))
-                                                                       flags |= Q3SURFACEPARM_LIGHTFILTER;
-                                                               else if (!strcasecmp(parameter[1], "metalsteps"))
-                                                                       flags |= Q3SURFACEPARM_METALSTEPS;
-                                                               else if (!strcasecmp(parameter[1], "nodamage"))
-                                                                       flags |= Q3SURFACEPARM_NODAMAGE;
-                                                               else if (!strcasecmp(parameter[1], "nodlight"))
-                                                                       flags |= Q3SURFACEPARM_NODLIGHT;
-                                                               else if (!strcasecmp(parameter[1], "nodraw"))
-                                                                       flags |= Q3SURFACEPARM_NODRAW;
-                                                               else if (!strcasecmp(parameter[1], "nodrop"))
-                                                                       flags |= Q3SURFACEPARM_NODROP;
-                                                               else if (!strcasecmp(parameter[1], "noimpact"))
-                                                                       flags |= Q3SURFACEPARM_NOIMPACT;
-                                                               else if (!strcasecmp(parameter[1], "nolightmap"))
-                                                                       flags |= Q3SURFACEPARM_NOLIGHTMAP;
-                                                               else if (!strcasecmp(parameter[1], "nomarks"))
-                                                                       flags |= Q3SURFACEPARM_NOMARKS;
-                                                               else if (!strcasecmp(parameter[1], "nomipmaps"))
-                                                                       flags |= Q3SURFACEPARM_NOMIPMAPS;
-                                                               else if (!strcasecmp(parameter[1], "nonsolid"))
-                                                                       flags |= Q3SURFACEPARM_NONSOLID;
-                                                               else if (!strcasecmp(parameter[1], "origin"))
-                                                                       flags |= Q3SURFACEPARM_ORIGIN;
-                                                               else if (!strcasecmp(parameter[1], "playerclip"))
-                                                                       flags |= Q3SURFACEPARM_PLAYERCLIP;
-                                                               else if (!strcasecmp(parameter[1], "sky"))
-                                                                       flags |= Q3SURFACEPARM_SKY;
-                                                               else if (!strcasecmp(parameter[1], "slick"))
-                                                                       flags |= Q3SURFACEPARM_SLICK;
-                                                               else if (!strcasecmp(parameter[1], "slime"))
-                                                                       flags |= Q3SURFACEPARM_SLIME;
-                                                               else if (!strcasecmp(parameter[1], "structural"))
-                                                                       flags |= Q3SURFACEPARM_STRUCTURAL;
-                                                               else if (!strcasecmp(parameter[1], "trans"))
-                                                                       flags |= Q3SURFACEPARM_TRANS;
-                                                               else if (!strcasecmp(parameter[1], "water"))
-                                                                       flags |= Q3SURFACEPARM_WATER;
-                                                               else if (!strcasecmp(parameter[1], "pointlight"))
-                                                                       flags |= Q3SURFACEPARM_POINTLIGHT;
-                                                               else
-                                                                       Con_Printf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[i], parameter[1]);
-                                                       }
-                                                       else if (!strcasecmp(parameter[0], "sky") && numparameters >= 2)
-                                                               strlcpy(sky, parameter[1], sizeof(sky));
-                                                       else if (!strcasecmp(parameter[0], "skyparms") && numparameters >= 2)
-                                                       {
-                                                               if (!atoi(parameter[1]) && strcasecmp(parameter[1], "-"))
-                                                                       strlcpy(sky, parameter[1], sizeof(sky));
-                                                       }
-                                                       else if (!strcasecmp(parameter[0], "cull") && numparameters >= 2)
-                                                       {
-                                                               if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "twosided"))
-                                                                       flags2 |= Q3TEXTUREFLAG_TWOSIDED;
-                                                       }
-                                                       else if (!strcasecmp(parameter[0], "nomipmaps"))
-                                                               flags2 |= Q3TEXTUREFLAG_NOMIPMAPS;
-                                                       else if (!strcasecmp(parameter[0], "nopicmip"))
-                                                               flags2 |= Q3TEXTUREFLAG_NOPICMIP;
-                                                       else if (!strcasecmp(parameter[0], "deformvertexes") && numparameters >= 2)
-                                                       {
-                                                               if (!strcasecmp(parameter[1], "autosprite") && numparameters == 2)
-                                                                       flags2 |= Q3TEXTUREFLAG_AUTOSPRITE;
-                                                               if (!strcasecmp(parameter[1], "autosprite2") && numparameters == 2)
-                                                                       flags2 |= Q3TEXTUREFLAG_AUTOSPRITE2;
-                                                       }
                                                }
-                                               // add shader to list (shadername and flags)
-                                               // actually here we just poke into the texture settings
-                                               for (j = 0, out = loadmodel->data_textures;j < loadmodel->num_textures;j++, out++)
+                                               if (developer.integer >= 100)
+                                               {
+                                                       Con_Printf("%s %i: ", shader->name, shader->numlayers - 1);
+                                                       for (j = 0;j < numparameters;j++)
+                                                               Con_Printf(" %s", parameter[j]);
+                                                       Con_Print("\n");
+                                               }
+                                               if (numparameters >= 2 && !strcasecmp(parameter[0], "blendfunc"))
                                                {
-                                                       if (!strcasecmp(out->name, shadername))
+                                                       if (numparameters == 2)
                                                        {
-                                                               out->surfaceparms = flags;
-                                                               out->textureflags = flags2;
-                                                               out->basematerialflags = 0;
-                                                               if (out->surfaceparms & Q3SURFACEPARM_NODRAW)
-                                                                       out->basematerialflags |= MATERIALFLAG_NODRAW;
-                                                               else if (out->surfaceparms & Q3SURFACEPARM_SKY)
-                                                                       out->basematerialflags |= MATERIALFLAG_SKY;
-                                                               else if (out->surfaceparms & Q3SURFACEPARM_LAVA)
-                                                                       out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_FULLBRIGHT;
-                                                               else if (out->surfaceparms & Q3SURFACEPARM_SLIME)
-                                                                       out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_WATERALPHA;
-                                                               else if (out->surfaceparms & Q3SURFACEPARM_WATER)
-                                                                       out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_WATERALPHA;
-                                                               else
-                                                                       out->basematerialflags |= MATERIALFLAG_WALL;
-                                                               if (out->textureflags & Q3TEXTUREFLAG_ALPHATEST)
+                                                               if (!strcasecmp(parameter[1], "add"))
                                                                {
-                                                                       // FIXME: support alpha test?
-                                                                       out->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT;
+                                                                       layer->blendfunc[0] = GL_ONE;
+                                                                       layer->blendfunc[1] = GL_ONE;
                                                                }
-                                                               else if (out->surfaceparms & Q3SURFACEPARM_TRANS)
+                                                               else if (!strcasecmp(parameter[1], "filter"))
                                                                {
-                                                                       if (out->textureflags & Q3TEXTUREFLAG_ADDITIVE)
-                                                                               out->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_TRANSPARENT;
-                                                                       else
-                                                                               out->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT;
+                                                                       layer->blendfunc[0] = GL_DST_COLOR;
+                                                                       layer->blendfunc[1] = GL_ZERO;
                                                                }
-                                                               strlcpy(out->firstpasstexturename, firstpasstexturename, sizeof(out->firstpasstexturename));
-                                                               if ((flags & Q3SURFACEPARM_SKY) && sky[0])
+                                                               else if (!strcasecmp(parameter[1], "blend"))
                                                                {
-                                                                       // quake3 seems to append a _ to the skybox name, so this must do so as well
-                                                                       dpsnprintf(loadmodel->brush.skybox, sizeof(loadmodel->brush.skybox), "%s_", sky);
+                                                                       layer->blendfunc[0] = GL_SRC_ALPHA;
+                                                                       layer->blendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
                                                                }
                                                        }
+                                                       else if (numparameters == 3)
+                                                       {
+                                                               int k;
+                                                               for (k = 0;k < 2;k++)
+                                                               {
+                                                                       if (!strcasecmp(parameter[k+1], "GL_ONE"))
+                                                                               layer->blendfunc[k] = GL_ONE;
+                                                                       else if (!strcasecmp(parameter[k+1], "GL_ZERO"))
+                                                                               layer->blendfunc[k] = GL_ZERO;
+                                                                       else if (!strcasecmp(parameter[k+1], "GL_SRC_COLOR"))
+                                                                               layer->blendfunc[k] = GL_SRC_COLOR;
+                                                                       else if (!strcasecmp(parameter[k+1], "GL_SRC_ALPHA"))
+                                                                               layer->blendfunc[k] = GL_SRC_ALPHA;
+                                                                       else if (!strcasecmp(parameter[k+1], "GL_DST_COLOR"))
+                                                                               layer->blendfunc[k] = GL_DST_COLOR;
+                                                                       else if (!strcasecmp(parameter[k+1], "GL_DST_ALPHA"))
+                                                                               layer->blendfunc[k] = GL_ONE_MINUS_DST_ALPHA;
+                                                                       else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_SRC_COLOR"))
+                                                                               layer->blendfunc[k] = GL_ONE_MINUS_SRC_COLOR;
+                                                                       else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_SRC_ALPHA"))
+                                                                               layer->blendfunc[k] = GL_ONE_MINUS_SRC_ALPHA;
+                                                                       else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_DST_COLOR"))
+                                                                               layer->blendfunc[k] = GL_ONE_MINUS_DST_COLOR;
+                                                                       else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_DST_ALPHA"))
+                                                                               layer->blendfunc[k] = GL_ONE_MINUS_DST_ALPHA;
+                                                                       else
+                                                                               layer->blendfunc[k] = GL_ONE; // default in case of parsing error
+                                                               }
+                                                       }
+                                               }
+                                               if (layer == shader->layers + 0)
+                                               {
+                                                       if (numparameters >= 2 && !strcasecmp(parameter[0], "alphafunc"))
+                                                               shader->textureflags |= Q3TEXTUREFLAG_ALPHATEST;
+                                               }
+                                               if (numparameters >= 2 && (!strcasecmp(parameter[0], "map") || !strcasecmp(parameter[0], "clampmap")))
+                                               {
+                                                       strlcpy(layer->texturename, parameter[1], sizeof(layer->texturename));
+                                                       if (!strcasecmp(parameter[1], "$lightmap"))
+                                                               shader->lighting = true;
                                                }
+                                               else if (numparameters >= 3 && !strcasecmp(parameter[0], "animmap"))
+                                                       strlcpy(layer->texturename, parameter[2], sizeof(layer->texturename));
+                                               else if (numparameters >= 2 && !strcasecmp(parameter[0], "rgbgen") && !strcasecmp(parameter[1], "vertex"))
+                                                       layer->rgbgenvertex = true;
+                                               else if (numparameters >= 2 && !strcasecmp(parameter[0], "alphagen") && !strcasecmp(parameter[1], "vertex"))
+                                                       layer->alphagenvertex = true;
+                                               // break out a level if it was }
+                                               if (!strcasecmp(com_token, "}"))
+                                                       break;
                                        }
-                                       else
+                                       if (layer->rgbgenvertex)
+                                               shader->lighting = true;
+                                       if (layer->alphagenvertex)
                                        {
-                                               Con_Printf("%s parsing error - expected \"{\", found \"%s\"\n", search->filenames[i], com_token);
-                                               goto parseerror;
+                                               if (layer == shader->layers + 0)
+                                               {
+                                                       // vertex controlled transparency
+                                                       shader->vertexalpha = true;
+                                               }
+                                               else
+                                               {
+                                                       // multilayer terrain shader or similar
+                                                       shader->textureblendalpha = true;
+                                               }
                                        }
+                                       continue;
+                               }
+                               numparameters = 0;
+                               for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
+                               {
+                                       if (j < 4)
+                                       {
+                                               strlcpy(parameter[j], com_token, sizeof(parameter[j]));
+                                               numparameters = j + 1;
+                                       }
+                                       if (!COM_ParseToken(&text, true))
+                                               break;
+                               }
+                               if (fileindex == 0 && !strcasecmp(com_token, "}"))
+                                       break;
+                               if (developer.integer >= 100)
+                               {
+                                       Con_Printf("%s: ", shader->name);
+                                       for (j = 0;j < numparameters;j++)
+                                               Con_Printf(" %s", parameter[j]);
+                                       Con_Print("\n");
+                               }
+                               if (numparameters < 1)
+                                       continue;
+                               if (!strcasecmp(parameter[0], "surfaceparm") && numparameters >= 2)
+                               {
+                                       if (!strcasecmp(parameter[1], "alphashadow"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_ALPHASHADOW;
+                                       else if (!strcasecmp(parameter[1], "areaportal"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_AREAPORTAL;
+                                       else if (!strcasecmp(parameter[1], "clusterportal"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_CLUSTERPORTAL;
+                                       else if (!strcasecmp(parameter[1], "detail"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_DETAIL;
+                                       else if (!strcasecmp(parameter[1], "donotenter"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_DONOTENTER;
+                                       else if (!strcasecmp(parameter[1], "fog"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_FOG;
+                                       else if (!strcasecmp(parameter[1], "lava"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_LAVA;
+                                       else if (!strcasecmp(parameter[1], "lightfilter"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_LIGHTFILTER;
+                                       else if (!strcasecmp(parameter[1], "metalsteps"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_METALSTEPS;
+                                       else if (!strcasecmp(parameter[1], "nodamage"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_NODAMAGE;
+                                       else if (!strcasecmp(parameter[1], "nodlight"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_NODLIGHT;
+                                       else if (!strcasecmp(parameter[1], "nodraw"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_NODRAW;
+                                       else if (!strcasecmp(parameter[1], "nodrop"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_NODROP;
+                                       else if (!strcasecmp(parameter[1], "noimpact"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_NOIMPACT;
+                                       else if (!strcasecmp(parameter[1], "nolightmap"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_NOLIGHTMAP;
+                                       else if (!strcasecmp(parameter[1], "nomarks"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_NOMARKS;
+                                       else if (!strcasecmp(parameter[1], "nomipmaps"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_NOMIPMAPS;
+                                       else if (!strcasecmp(parameter[1], "nonsolid"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_NONSOLID;
+                                       else if (!strcasecmp(parameter[1], "origin"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_ORIGIN;
+                                       else if (!strcasecmp(parameter[1], "playerclip"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_PLAYERCLIP;
+                                       else if (!strcasecmp(parameter[1], "sky"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_SKY;
+                                       else if (!strcasecmp(parameter[1], "slick"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_SLICK;
+                                       else if (!strcasecmp(parameter[1], "slime"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_SLIME;
+                                       else if (!strcasecmp(parameter[1], "structural"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_STRUCTURAL;
+                                       else if (!strcasecmp(parameter[1], "trans"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_TRANS;
+                                       else if (!strcasecmp(parameter[1], "water"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_WATER;
+                                       else if (!strcasecmp(parameter[1], "pointlight"))
+                                               shader->surfaceparms |= Q3SURFACEPARM_POINTLIGHT;
+                                       else
+                                               Con_Printf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[fileindex], parameter[1]);
+                               }
+                               else if (!strcasecmp(parameter[0], "sky") && numparameters >= 2)
+                               {
+                                       // some q3 skies don't have the sky parm set
+                                       shader->surfaceparms |= Q3SURFACEPARM_SKY;
+                                       strlcpy(shader->skyboxname, parameter[1], sizeof(shader->skyboxname));
                                }
-parseerror:
-                               Mem_Free(f);
+                               else if (!strcasecmp(parameter[0], "skyparms") && numparameters >= 2)
+                               {
+                                       // some q3 skies don't have the sky parm set
+                                       shader->surfaceparms |= Q3SURFACEPARM_SKY;
+                                       if (!atoi(parameter[1]) && strcasecmp(parameter[1], "-"))
+                                               strlcpy(shader->skyboxname, parameter[1], sizeof(shader->skyboxname));
+                               }
+                               else if (!strcasecmp(parameter[0], "cull") && numparameters >= 2)
+                               {
+                                       if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "twosided"))
+                                               shader->textureflags |= Q3TEXTUREFLAG_TWOSIDED;
+                               }
+                               else if (!strcasecmp(parameter[0], "nomipmaps"))
+                                       shader->surfaceparms |= Q3SURFACEPARM_NOMIPMAPS;
+                               else if (!strcasecmp(parameter[0], "nopicmip"))
+                                       shader->textureflags |= Q3TEXTUREFLAG_NOPICMIP;
+                               else if (!strcasecmp(parameter[0], "deformvertexes") && numparameters >= 2)
+                               {
+                                       if (!strcasecmp(parameter[1], "autosprite") && numparameters == 2)
+                                               shader->textureflags |= Q3TEXTUREFLAG_AUTOSPRITE;
+                                       if (!strcasecmp(parameter[1], "autosprite2") && numparameters == 2)
+                                               shader->textureflags |= Q3TEXTUREFLAG_AUTOSPRITE2;
+                               }
+                       }
+                       // identify if this is a blended terrain shader or similar
+                       shader->primarylayer = shader->layers + 0;
+                       if (shader->layers[1].blendfunc[0] == GL_SRC_ALPHA && shader->layers[1].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA)
+                       {
+                               // terrain blending or other effects
+                               shader->backgroundlayer = shader->layers + 0;
+                               shader->primarylayer = shader->layers + 1;
                        }
+                       // now see if the lightmap came first, and if so choose the second texture instead
+                       if (!strcasecmp(shader->primarylayer->texturename, "$lightmap"))
+                               shader->primarylayer = shader->layers + 1;
                }
+               Mem_Free(f);
        }
+}
+
+q3shaderinfo_t *Mod_Q3BSP_LookupShader(const char *name)
+{
+       int i;
+       for (i = 0;i < Q3SHADER_MAXSHADERS;i++)
+               if (!strcasecmp(q3shaders_shaders[i].name, name))
+                       return q3shaders_shaders + i;
+       return NULL;
+}
+
+static void Mod_Q3BSP_LoadTextures(lump_t *l)
+{
+       q3dtexture_t *in;
+       texture_t *out;
+       int i, count, c;
+
+       in = (q3dtexture_t *)(mod_base + l->fileofs);
+       if (l->filelen % sizeof(*in))
+               Host_Error("Mod_Q3BSP_LoadTextures: funny lump size in %s",loadmodel->name);
+       count = l->filelen / sizeof(*in);
+       out = (texture_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+       loadmodel->data_textures = out;
+       loadmodel->num_textures = count;
+
+       // parse the Q3 shader files
+       Mod_Q3BSP_LoadShaders();
 
        c = 0;
-       for (j = 0, out = loadmodel->data_textures;j < loadmodel->num_textures;j++, out++)
+       for (i = 0;i < count;i++, in++, out++)
        {
-               if (out->surfaceparms == -1)
+               q3shaderinfo_t *shader;
+               strlcpy (out->name, in->name, sizeof (out->name));
+               out->surfaceflags = LittleLong(in->surfaceflags);
+               out->supercontents = Mod_Q3BSP_SuperContentsFromNativeContents(loadmodel, LittleLong(in->contents));
+               shader = Mod_Q3BSP_LookupShader(out->name);
+               if (shader)
+               {
+                       out->surfaceparms = shader->surfaceparms;
+                       out->textureflags = shader->textureflags;
+                       out->basematerialflags = 0;
+                       if (shader->surfaceparms & Q3SURFACEPARM_SKY)
+                       {
+                               out->basematerialflags |= MATERIALFLAG_SKY;
+                               if (shader->skyboxname[0])
+                               {
+                                       // quake3 seems to append a _ to the skybox name, so this must do so as well
+                                       dpsnprintf(loadmodel->brush.skybox, sizeof(loadmodel->brush.skybox), "%s_", shader->skyboxname);
+                               }
+                       }
+                       else if ((shader->surfaceparms & Q3SURFACEPARM_NODRAW) || shader->numlayers == 0)
+                               out->basematerialflags |= MATERIALFLAG_NODRAW;
+                       else if (shader->surfaceparms & Q3SURFACEPARM_LAVA)
+                               out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_FULLBRIGHT;
+                       else if (shader->surfaceparms & Q3SURFACEPARM_SLIME)
+                               out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_WATERALPHA;
+                       else if (shader->surfaceparms & Q3SURFACEPARM_WATER)
+                               out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_WATERALPHA;
+                       else
+                               out->basematerialflags |= MATERIALFLAG_WALL;
+                       if (shader->textureflags & Q3TEXTUREFLAG_ALPHATEST)
+                               out->basematerialflags |= MATERIALFLAG_ALPHATEST | MATERIALFLAG_TRANSPARENT;
+                       out->customblendfunc[0] = GL_ONE;
+                       out->customblendfunc[1] = GL_ZERO;
+                       if (shader->numlayers > 0)
+                       {
+                               out->customblendfunc[0] = shader->layers[0].blendfunc[0];
+                               out->customblendfunc[1] = shader->layers[0].blendfunc[1];
+/*
+Q3 shader blendfuncs actually used in the game (* = supported by DP)
+* additive               GL_ONE GL_ONE
+  additive weird         GL_ONE GL_SRC_ALPHA
+  additive weird 2       GL_ONE GL_ONE_MINUS_SRC_ALPHA
+* alpha                  GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+  alpha inverse          GL_ONE_MINUS_SRC_ALPHA GL_SRC_ALPHA
+  brighten               GL_DST_COLOR GL_ONE
+  brighten               GL_ONE GL_SRC_COLOR
+  brighten weird         GL_DST_COLOR GL_ONE_MINUS_DST_ALPHA
+  brighten weird 2       GL_DST_COLOR GL_SRC_ALPHA
+* modulate               GL_DST_COLOR GL_ZERO
+* modulate               GL_ZERO GL_SRC_COLOR
+  modulate inverse       GL_ZERO GL_ONE_MINUS_SRC_COLOR
+  modulate inverse alpha GL_ZERO GL_SRC_ALPHA
+  modulate weird inverse GL_ONE_MINUS_DST_COLOR GL_ZERO
+* modulate x2            GL_DST_COLOR GL_SRC_COLOR
+* no blend               GL_ONE GL_ZERO
+  nothing                GL_ZERO GL_ONE
+*/
+                               // if not opaque, figure out what blendfunc to use
+                               if (shader->layers[0].blendfunc[0] != GL_ONE || shader->layers[0].blendfunc[1] != GL_ZERO)
+                               {
+                                       if (shader->layers[0].blendfunc[0] == GL_ONE && shader->layers[0].blendfunc[1] == GL_ONE)
+                                               out->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT;
+                                       else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE)
+                                               out->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT;
+                                       else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA)
+                                               out->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT;
+                                       else
+                                               out->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT;
+                               }
+                       }
+                       if (!shader->lighting)
+                               out->basematerialflags |= MATERIALFLAG_FULLBRIGHT;
+                       if (cls.state != ca_dedicated)
+                               if (shader->primarylayer && !Mod_LoadSkinFrame(&out->skin, shader->primarylayer->texturename, ((shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (shader->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP), false, true))
+                                       Con_Printf("%s: could not load texture \"%s\" for shader \"%s\"\n", loadmodel->name, shader->primarylayer->texturename, out->name);
+               }
+               else
                {
                        c++;
                        Con_DPrintf("%s: No shader found for texture \"%s\"\n", loadmodel->name, out->name);
@@ -4213,11 +4375,10 @@ parseerror:
                        //      out->surfaceparms |= Q3SURFACEPARM_NODRAW;
                        //if (R_TextureHasAlpha(out->skin.base))
                        //      out->surfaceparms |= Q3SURFACEPARM_TRANS;
+                       if (cls.state != ca_dedicated)
+                               if (!Mod_LoadSkinFrame(&out->skin, out->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, true))
+                                       Con_Printf("%s: could not load texture for missing shader \"%s\"\n", loadmodel->name, out->name);
                }
-               if (cls.state != ca_dedicated)
-                       if (!Mod_LoadSkinFrame(&out->skin, out->name, (((out->textureflags & Q3TEXTUREFLAG_NOMIPMAPS) || (out->surfaceparms & Q3SURFACEPARM_NOMIPMAPS)) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (out->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP), false, true))
-                               if (!Mod_LoadSkinFrame(&out->skin, out->firstpasstexturename, (((out->textureflags & Q3TEXTUREFLAG_NOMIPMAPS) || (out->surfaceparms & Q3SURFACEPARM_NOMIPMAPS)) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (out->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP), false, true))
-                                       Con_Printf("%s: texture loading for shader \"%s\" failed (first layer \"%s\" not found either)\n", loadmodel->name, out->name, out->firstpasstexturename);
                // no animation
                out->currentframe = out;
        }
index 080daf0..40b5e53 100644 (file)
@@ -86,6 +86,13 @@ mplane_t;
 #define MATERIALFLAG_NODRAW 512
 // probably used only on q1bsp water
 #define MATERIALFLAG_LIGHTBOTHSIDES 1024
+// use alpha test on this material
+#define MATERIALFLAG_ALPHATEST 2048
+// treat this material as a blended transparency (as opposed to an alpha test
+// transparency), this causes special fog behavior, and disables glDepthMask
+#define MATERIALFLAG_BLENDED 4096
+// render using a custom blendfunc
+#define MATERIALFLAG_CUSTOMBLEND 8192
 
 typedef struct medge_s
 {
@@ -624,14 +631,12 @@ q3dpvs_t;
 #define Q3SURFACEPARM_WATER 33554432
 #define Q3SURFACEPARM_POINTLIGHT 67108864
 
-// various flags from shaders
+// various flags from shaders, used for special effects not otherwise classified
 #define Q3TEXTUREFLAG_TWOSIDED 1
-#define Q3TEXTUREFLAG_ADDITIVE 2
-#define Q3TEXTUREFLAG_NOMIPMAPS 4
-#define Q3TEXTUREFLAG_NOPICMIP 8
-#define Q3TEXTUREFLAG_AUTOSPRITE 16
-#define Q3TEXTUREFLAG_AUTOSPRITE2 32
-#define Q3TEXTUREFLAG_ALPHATEST 64
+#define Q3TEXTUREFLAG_AUTOSPRITE 2
+#define Q3TEXTUREFLAG_AUTOSPRITE2 4
+#define Q3TEXTUREFLAG_ALPHATEST 8
+#define Q3TEXTUREFLAG_NOPICMIP 16
 
 typedef struct q3mbrush_s
 {
index bde7bf8..e8148fb 100644 (file)
@@ -215,12 +215,14 @@ typedef struct texture_s
        float specularscale;
        float specularpower;
 
+       // from q3 shaders
+       int customblendfunc[2];
+
        int currentnumlayers;
        texturelayer_t currentlayers[16];
 
        // q3bsp
        char name[64];
-       char firstpasstexturename[64]; // used only during loading
        int surfaceflags;
        int supercontents;
        int surfaceparms;
index 8428f99..3b12bbd 100644 (file)
@@ -1258,12 +1258,16 @@ static void R_Shadow_RenderSurfacesLighting_Light_GLSL(const entity_render_t *en
        R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
        R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
        R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
+       if (texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
+               qglDepthFunc(GL_EQUAL);
        for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
        {
                const msurface_t *surface = surfacelist[surfacelistindex];
                GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
                R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, model->surfmesh.data_element3i + surface->num_firsttriangle * 3);
        }
+       if (texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
+               qglDepthFunc(GL_LEQUAL);
        GL_LockArrays(0, 0);
 }