-// FIXME: make MAXSHADERS dynamic
-#define Q3SHADER_MAXSHADERS 4096
-#define Q3SHADER_MAXLAYERS 8
-
-typedef struct q3shaderinfo_layer_s
-{
- int alphatest;
- int clampmap;
- float framerate;
- int numframes;
- char texturename[TEXTURE_MAXFRAMES][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;
- q3shaderinfo_t *shader;
- q3shaderinfo_layer_t *layer;
- int numparameters;
- char parameter[TEXTURE_MAXFRAMES + 4][Q3PATHLENGTH];
- search = FS_Search("scripts/*.shader", true, false);
- if (!search)
- return;
- q3shaders_numshaders = 0;
- for (fileindex = 0;fileindex < search->numfilenames;fileindex++)
- {
- text = f = (char *)FS_LoadFile(search->filenames[fileindex], tempmempool, false, NULL);
- if (!f)
- continue;
- while (COM_ParseToken(&text, false))
- {
- 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, "{"))
- {
- 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, "{"))
- {
- if (shader->numlayers < Q3SHADER_MAXLAYERS)
- {
- 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 (j < TEXTURE_MAXFRAMES + 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: ", 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 (numparameters == 2)
- {
- if (!strcasecmp(parameter[1], "add"))
- {
- layer->blendfunc[0] = GL_ONE;
- layer->blendfunc[1] = GL_ONE;
- }
- else if (!strcasecmp(parameter[1], "filter"))
- {
- layer->blendfunc[0] = GL_DST_COLOR;
- layer->blendfunc[1] = GL_ZERO;
- }
- else if (!strcasecmp(parameter[1], "blend"))
- {
- 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 (numparameters >= 2 && !strcasecmp(parameter[0], "alphafunc"))
- layer->alphatest = true;
- if (numparameters >= 2 && (!strcasecmp(parameter[0], "map") || !strcasecmp(parameter[0], "clampmap")))
- {
- if (!strcasecmp(parameter[0], "clampmap"))
- layer->clampmap = true;
- layer->numframes = 1;
- layer->framerate = 1;
- strlcpy(layer->texturename[0], parameter[1], sizeof(layer->texturename));
- if (!strcasecmp(parameter[1], "$lightmap"))
- shader->lighting = true;
- }
- else if (numparameters >= 3 && (!strcasecmp(parameter[0], "animmap") || !strcasecmp(parameter[0], "animclampmap")))
- {
- int i;
- layer->numframes = min(numparameters - 2, TEXTURE_MAXFRAMES);
- layer->framerate = atof(parameter[1]);
- for (i = 0;i < layer->numframes;i++)
- strlcpy(layer->texturename[i], parameter[i + 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;
- }
- if (layer->rgbgenvertex)
- shader->lighting = true;
- if (layer->alphagenvertex)
- {
- 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 < TEXTURE_MAXFRAMES + 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], "botclip"))
- shader->surfaceparms |= Q3SURFACEPARM_BOTCLIP;
- 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], "dust"))
- shader->surfaceparms |= Q3SURFACEPARM_DUST;
- else if (!strcasecmp(parameter[1], "hint"))
- shader->surfaceparms |= Q3SURFACEPARM_HINT;
- 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], "lightgrid"))
- shader->surfaceparms |= Q3SURFACEPARM_LIGHTGRID;
- 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));
- }
- 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
- if (shader->numlayers)
- {
- shader->primarylayer = shader->layers + 0;
- if ((shader->layers[1].blendfunc[0] == GL_SRC_ALPHA && shader->layers[1].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA) || shader->layers[1].alphatest)
- {
- // 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[0], "$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;
-}
-