cls.qw_downloadtype = dl_none;
+ // parse the Q3 shader files
+ Mod_LoadQ3Shaders();
+
// touch all of the precached models that are still loaded so we can free
// anything that isn't needed
if (!sv.active)
{
// loading models
+ // parse the Q3 shader files
+ if (cl.loadmodel_current < 2)
+ Mod_LoadQ3Shaders();
+
for (;cl.loadmodel_current < cl.loadmodel_total;cl.loadmodel_current++)
{
if (cl.model_precache[cl.loadmodel_current] && cl.model_precache[cl.loadmodel_current]->Draw)
// hack
if (!skinframe)
skinframe = R_SkinFrame_LoadMissing();
+ memset(texture, 0, sizeof(*texture));
texture->currentframe = texture;
+ //texture->animated = false;
texture->numskinframes = 1;
texture->skinframerate = 1;
texture->skinframes[0] = skinframe;
texture->currentskinframe = skinframe;
+ //texture->backgroundnumskinframes = 0;
+ //texture->customblendfunc[0] = 0;
+ //texture->customblendfunc[1] = 0;
+ //texture->surfaceflags = 0;
+ //texture->supercontents = 0;
+ //texture->surfaceparms = 0;
+ //texture->textureflags = 0;
texture->basematerialflags = MATERIALFLAG_WALL;
if (texture->currentskinframe->fog)
for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
{
memset(skin, 0, sizeof(*skin));
- Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
- // don't render unmentioned meshes
- skin->basematerialflags = skin->currentmaterialflags = 0;
// see if a mesh
for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
{
// leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
if (!strcmp(skinfileitem->name, meshname) && strcmp(skinfileitem->replacement, "common/nodraw") && strcmp(skinfileitem->replacement, "textures/common/nodraw"))
{
- tempskinframe = R_SkinFrame_LoadExternal(skinfileitem->replacement, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false);
- if (!tempskinframe)
- if (cls.state != ca_dedicated)
- Con_DPrintf("mesh \"%s\": failed to load skin #%i \"%s\"\n", meshname, i, skinfileitem->replacement);
- Mod_BuildAliasSkinFromSkinFrame(skin, tempskinframe);
+ if (!Mod_LoadTextureFromQ3Shader(skin, skinfileitem->replacement, false, false, true))
+ {
+ tempskinframe = R_SkinFrame_LoadExternal(skinfileitem->replacement, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false);
+ if (!tempskinframe)
+ if (cls.state != ca_dedicated)
+ Con_DPrintf("mesh \"%s\": failed to load skin #%i \"%s\"\n", meshname, i, skinfileitem->replacement);
+ Mod_BuildAliasSkinFromSkinFrame(skin, tempskinframe);
+ }
break;
}
}
+ if (!skinfileitem)
+ {
+ // don't render unmentioned meshes
+ Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
+ skin->basematerialflags = skin->currentmaterialflags = 0;
+ }
}
}
else
{
- tempskinframe = R_SkinFrame_LoadExternal(shadername, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false);
- if (!tempskinframe)
- if (cls.state != ca_dedicated)
- Con_Printf("Can't find texture \"%s\" for mesh \"%s\", using grey checkerboard\n", shadername, meshname);
- Mod_BuildAliasSkinFromSkinFrame(skin, tempskinframe);
+ if (!Mod_LoadTextureFromQ3Shader(skin, shadername, false, false, true))
+ {
+ tempskinframe = R_SkinFrame_LoadExternal(shadername, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false);
+ if (!tempskinframe)
+ if (cls.state != ca_dedicated)
+ Con_Printf("Can't find texture \"%s\" for mesh \"%s\", using grey checkerboard\n", shadername, meshname);
+ Mod_BuildAliasSkinFromSkinFrame(skin, tempskinframe);
+ }
}
}
sprintf (name, "%s_%i_%i", loadmodel->name, i, j);
else
sprintf (name, "%s_%i", loadmodel->name, i);
- tempskinframe = R_SkinFrame_LoadExternal(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP, false);
- if (!tempskinframe)
- tempskinframe = R_SkinFrame_LoadInternal(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight, 8, NULL, NULL);
- Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, tempskinframe);
+ if (!Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, false, true))
+ {
+ tempskinframe = R_SkinFrame_LoadExternal(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP, false);
+ if (!tempskinframe)
+ tempskinframe = R_SkinFrame_LoadInternal(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight, 8, NULL, NULL);
+ Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, tempskinframe);
+ }
datapointer += skinwidth * skinheight;
totalskins++;
}
}
// check for skins that don't exist in the model, but do exist as external images
// (this was added because yummyluv kept pestering me about support for it)
+ // TODO: support shaders here?
while ((tempskinframe = R_SkinFrame_LoadExternal(va("%s_%i", loadmodel->name, loadmodel->numskins), (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP, false)))
{
// expand the arrays to make room
loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
{
- tempskinframe = R_SkinFrame_LoadExternal(inskin, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false);
- if (!tempskinframe)
- Con_Printf("%s is missing skin \"%s\"\n", loadmodel->name, inskin);
- Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + i * loadmodel->num_surfaces, tempskinframe);
+ if (!Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, false, false, true))
+ {
+ tempskinframe = R_SkinFrame_LoadExternal(inskin, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false);
+ if (!tempskinframe)
+ Con_Printf("%s is missing skin \"%s\"\n", loadmodel->name, inskin);
+ Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + i * loadmodel->num_surfaces, tempskinframe);
+ }
}
}
else
continue;
dmiptex = (miptex_t *)((unsigned char *)m + dofs[i]);
- // make sure name is no more than 15 characters
- for (j = 0;dmiptex->name[j] && j < 15;j++)
+ // copy name, but only up to 16 characters
+ // (the output buffer can hold more than this, but the input buffer is
+ // only 16)
+ for (j = 0;dmiptex->name[j] && j < 16;j++)
name[j] = dmiptex->name[j];
name[j] = 0;
if (name[j] >= 'A' && name[j] <= 'Z')
name[j] += 'a' - 'A';
+ if (Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i, name, true, false, false))
+ continue;
+
tx = loadmodel->data_textures + i;
strlcpy(tx->name, name, sizeof(tx->name));
tx->width = mtwidth;
}
}
-// 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_QuakeC(&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_QuakeC(&text, false) || strcasecmp(com_token, "{"))
- {
- Con_Printf("%s parsing error - expected \"{\", found \"%s\"\n", search->filenames[fileindex], com_token);
- break;
- }
- while (COM_ParseToken_QuakeC(&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_QuakeC(&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_QuakeC(&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_QuakeC(&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 if (!strcasecmp(parameter[1], "antiportal"))
- shader->surfaceparms |= Q3SURFACEPARM_ANTIPORTAL;
- else
- Con_DPrintf("%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->backgroundlayer = NULL;
- shader->primarylayer = shader->layers + 0;
- if ((shader->layers[0].blendfunc[0] == GL_ONE && shader->layers[0].blendfunc[1] == GL_ZERO && !shader->layers[0].alphatest)
- && ((shader->layers[1].blendfunc[0] == GL_SRC_ALPHA && shader->layers[1].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA && !shader->layers[0].alphatest)
- || (shader->layers[1].blendfunc[0] == GL_ONE && shader->layers[1].blendfunc[1] == GL_ZERO && 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->backgroundlayer = NULL;
- 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;
if (cls.state == ca_dedicated)
return;
- // parse the Q3 shader files
- Mod_Q3BSP_LoadShaders();
-
c = 0;
for (i = 0;i < count;i++, in++, out++)
- {
- q3shaderinfo_t *shader;
- 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 | MATERIALFLAG_NOSHADOW;
- 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 ((out->surfaceflags & Q3SURFACEFLAG_NODRAW) || shader->numlayers == 0)
- out->basematerialflags |= MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
- else if (shader->surfaceparms & Q3SURFACEPARM_LAVA)
- out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOSHADOW;
- else if (shader->surfaceparms & Q3SURFACEPARM_SLIME)
- out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_WATERALPHA | MATERIALFLAG_NOSHADOW;
- else if (shader->surfaceparms & Q3SURFACEPARM_WATER)
- out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_WATERALPHA | MATERIALFLAG_NOSHADOW;
- else
- out->basematerialflags |= MATERIALFLAG_WALL;
- if (shader->layers[0].alphatest)
- out->basematerialflags |= MATERIALFLAG_ALPHATEST | MATERIALFLAG_NOSHADOW;
- if (shader->textureflags & Q3TEXTUREFLAG_TWOSIDED)
- out->basematerialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
- if (shader->textureflags & (Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2))
- out->basematerialflags |= MATERIALFLAG_NOSHADOW;
- 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_NOSHADOW;
- else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE)
- out->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
- 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_NOSHADOW;
- else
- out->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
- }
- }
- if (!shader->lighting)
- out->basematerialflags |= MATERIALFLAG_FULLBRIGHT;
- if (shader->primarylayer)
- {
- int j;
- out->numskinframes = shader->primarylayer->numframes;
- out->skinframerate = shader->primarylayer->framerate;
- for (j = 0;j < shader->primarylayer->numframes;j++)
- if (!(out->skinframes[j] = R_SkinFrame_LoadExternal(shader->primarylayer->texturename[j], ((shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | ((!r_picmipworld.integer || (shader->textureflags & Q3TEXTUREFLAG_NOPICMIP)) ? 0 : TEXF_PICMIP) | (shader->primarylayer->clampmap ? TEXF_CLAMP : 0), false)))
- {
- Con_DPrintf("%s: could not load texture \"%s\" (frame %i) for shader \"%s\"\n", loadmodel->name, shader->primarylayer->texturename[j], j, out->name);
- out->skinframes[j] = R_SkinFrame_LoadMissing();
- }
- }
- if (shader->backgroundlayer)
- {
- int j;
- out->backgroundnumskinframes = shader->backgroundlayer->numframes;
- out->backgroundskinframerate = shader->backgroundlayer->framerate;
- for (j = 0;j < shader->backgroundlayer->numframes;j++)
- {
- if (!(out->backgroundskinframes[j] = R_SkinFrame_LoadExternal(shader->backgroundlayer->texturename[j], ((shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | ((!r_picmipworld.integer || (shader->textureflags & Q3TEXTUREFLAG_NOPICMIP)) ? 0 : TEXF_PICMIP) | (shader->backgroundlayer->clampmap ? TEXF_CLAMP : 0), false)))
- {
- Con_DPrintf("%s: could not load texture \"%s\" (frame %i) for shader \"%s\"\n", loadmodel->name, shader->backgroundlayer->texturename[j], j, out->name);
- out->backgroundskinframes[j] = R_SkinFrame_LoadMissing();
- }
- }
- }
- }
- else if (!strcmp(out->name, "noshader"))
- out->surfaceparms = 0;
- else
- {
+ if (Mod_LoadTextureFromQ3Shader(out, out->name, false, true, false))
c++;
- Con_DPrintf("%s: No shader found for texture \"%s\"\n", loadmodel->name, out->name);
- out->surfaceparms = 0;
- if (out->surfaceflags & Q3SURFACEFLAG_NODRAW)
- out->basematerialflags |= MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
- else if (out->surfaceflags & Q3SURFACEFLAG_SKY)
- out->basematerialflags |= MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW;
- else
- out->basematerialflags |= MATERIALFLAG_WALL;
- // these are defaults
- //if (!strncmp(out->name, "textures/skies/", 15))
- // out->surfaceparms |= Q3SURFACEPARM_SKY;
- //if (!strcmp(out->name, "caulk") || !strcmp(out->name, "common/caulk") || !strcmp(out->name, "textures/common/caulk")
- // || !strcmp(out->name, "nodraw") || !strcmp(out->name, "common/nodraw") || !strcmp(out->name, "textures/common/nodraw"))
- // out->surfaceparms |= Q3SURFACEPARM_NODRAW;
- //if (R_TextureHasAlpha(out->skinframes[0].base))
- // out->surfaceparms |= Q3SURFACEPARM_TRANS;
- out->numskinframes = 1;
- if (!(out->skinframes[0] = R_SkinFrame_LoadExternal(out->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | (r_picmipworld.integer ? TEXF_PICMIP : 0), false)))
- Con_DPrintf("%s: could not load texture for missing shader \"%s\"\n", loadmodel->name, out->name);
- }
- // init the animation variables
- out->currentframe = out;
- if (out->numskinframes < 1)
- out->numskinframes = 1;
- if (!out->skinframes[0])
- out->skinframes[0] = R_SkinFrame_LoadMissing();
- out->currentskinframe = out->skinframes[0];
- out->backgroundcurrentskinframe = out->backgroundskinframes[0];
- }
if (c)
Con_DPrintf("%s: %i textures missing shaders\n", loadmodel->name, c);
}
static mempool_t *mod_mempool;
static memexpandablearray_t models;
+// FIXME: make this a memexpandablearray_t
+#define Q3SHADER_MAXSHADERS 4096
+static int q3shaders_numshaders = 0;
+static q3shaderinfo_t q3shaders_shaders[Q3SHADER_MAXSHADERS];
+
static void mod_start(void)
{
int i;
int nummodels = Mem_ExpandableArray_IndexRange(&models);
model_t *mod;
+ // parse the Q3 shader files
+ Mod_LoadQ3Shaders();
+
for (i = 0;i < nummodels;i++)
if ((mod = Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*')
if (mod->used)
Mod_GetTerrainVertexFromRGBA(imagepixels, imagewidth, imageheight, ix, iy, vertex3f, texcoord2f, svector3f, tvector3f, normal3f, pixelstepmatrix, pixeltexturestepmatrix);
}
+void Mod_LoadQ3Shaders(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];
+ q3shaders_numshaders = 0;
+ search = FS_Search("scripts/*.shader", true, false);
+ if (!search)
+ return;
+ for (fileindex = 0;fileindex < search->numfilenames;fileindex++)
+ {
+ text = f = (char *)FS_LoadFile(search->filenames[fileindex], tempmempool, false, NULL);
+ if (!f)
+ continue;
+ while (COM_ParseToken_QuakeC(&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_QuakeC(&text, false) || strcasecmp(com_token, "{"))
+ {
+ Con_Printf("%s parsing error - expected \"{\", found \"%s\"\n", search->filenames[fileindex], com_token);
+ break;
+ }
+ while (COM_ParseToken_QuakeC(&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_QuakeC(&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_QuakeC(&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_QuakeC(&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 if (!strcasecmp(parameter[1], "antiportal"))
+ shader->surfaceparms |= Q3SURFACEPARM_ANTIPORTAL;
+ else
+ Con_DPrintf("%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->backgroundlayer = NULL;
+ shader->primarylayer = shader->layers + 0;
+ if ((shader->layers[0].blendfunc[0] == GL_ONE && shader->layers[0].blendfunc[1] == GL_ZERO && !shader->layers[0].alphatest)
+ && ((shader->layers[1].blendfunc[0] == GL_SRC_ALPHA && shader->layers[1].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA && !shader->layers[0].alphatest)
+ || (shader->layers[1].blendfunc[0] == GL_ONE && shader->layers[1].blendfunc[1] == GL_ZERO && 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->backgroundlayer = NULL;
+ shader->primarylayer = shader->layers + 1;
+ }
+ }
+ }
+ Mem_Free(f);
+ }
+}
+
+q3shaderinfo_t *Mod_LookupQ3Shader(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;
+}
+
+extern cvar_t r_picmipworld;
+qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qboolean q1bsp, qboolean q3bsp, qboolean md3)
+{
+ int j;
+ int texflags;
+ qboolean success = true;
+ q3shaderinfo_t *shader;
+ strlcpy(texture->name, name, sizeof(texture->name));
+ shader = Mod_LookupQ3Shader(name);
+ if (shader)
+ {
+ texture->surfaceparms = shader->surfaceparms;
+ texture->textureflags = shader->textureflags;
+ texture->basematerialflags = 0;
+ if (shader->surfaceparms & Q3SURFACEPARM_SKY)
+ {
+ texture->basematerialflags |= MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW;
+ 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 ((texture->surfaceflags & Q3SURFACEFLAG_NODRAW) || shader->numlayers == 0)
+ texture->basematerialflags |= MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
+ else if (shader->surfaceparms & Q3SURFACEPARM_LAVA)
+ texture->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOSHADOW;
+ else if (shader->surfaceparms & Q3SURFACEPARM_SLIME)
+ texture->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_WATERALPHA | MATERIALFLAG_NOSHADOW;
+ else if (shader->surfaceparms & Q3SURFACEPARM_WATER)
+ texture->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_WATERALPHA | MATERIALFLAG_NOSHADOW;
+ else
+ texture->basematerialflags |= MATERIALFLAG_WALL;
+ if (shader->layers[0].alphatest)
+ texture->basematerialflags |= MATERIALFLAG_ALPHATEST | MATERIALFLAG_NOSHADOW;
+ if (shader->textureflags & Q3TEXTUREFLAG_TWOSIDED)
+ texture->basematerialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
+ if (shader->textureflags & (Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2))
+ texture->basematerialflags |= MATERIALFLAG_NOSHADOW;
+ texture->customblendfunc[0] = GL_ONE;
+ texture->customblendfunc[1] = GL_ZERO;
+ if (shader->numlayers > 0)
+ {
+ texture->customblendfunc[0] = shader->layers[0].blendfunc[0];
+ texture->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)
+ texture->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
+ else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE)
+ texture->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
+ else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA)
+ texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
+ else
+ texture->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
+ }
+ }
+ if (!shader->lighting)
+ texture->basematerialflags |= MATERIALFLAG_FULLBRIGHT;
+ if (shader->primarylayer)
+ {
+ texture->numskinframes = shader->primarylayer->numframes;
+ texture->skinframerate = shader->primarylayer->framerate;
+ for (j = 0;j < shader->primarylayer->numframes;j++)
+ {
+ texflags = TEXF_ALPHA | TEXF_PRECACHE;
+ if (!(shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS))
+ texflags |= TEXF_MIPMAP;
+ if (!(shader->textureflags & Q3TEXTUREFLAG_NOPICMIP) && ((!q1bsp && !q3bsp) || r_picmipworld.integer))
+ texflags |= TEXF_PICMIP;
+ if (shader->primarylayer->clampmap)
+ texflags |= TEXF_CLAMP;
+ if (!(texture->skinframes[j] = R_SkinFrame_LoadExternal(shader->primarylayer->texturename[j], texflags, false)))
+ {
+ Con_DPrintf("%s: could not load texture \"%s\" (frame %i) for shader \"%s\"\n", loadmodel->name, shader->primarylayer->texturename[j], j, texture->name);
+ texture->skinframes[j] = R_SkinFrame_LoadMissing();
+ }
+ }
+ }
+ if (shader->backgroundlayer)
+ {
+ texture->backgroundnumskinframes = shader->backgroundlayer->numframes;
+ texture->backgroundskinframerate = shader->backgroundlayer->framerate;
+ for (j = 0;j < shader->backgroundlayer->numframes;j++)
+ {
+ if (!(texture->backgroundskinframes[j] = R_SkinFrame_LoadExternal(shader->backgroundlayer->texturename[j], ((shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | ((!r_picmipworld.integer || (shader->textureflags & Q3TEXTUREFLAG_NOPICMIP)) ? 0 : TEXF_PICMIP) | (shader->backgroundlayer->clampmap ? TEXF_CLAMP : 0), false)))
+ {
+ Con_DPrintf("%s: could not load texture \"%s\" (frame %i) for shader \"%s\"\n", loadmodel->name, shader->backgroundlayer->texturename[j], j, texture->name);
+ texture->backgroundskinframes[j] = R_SkinFrame_LoadMissing();
+ }
+ }
+ }
+ }
+ else if (!strcmp(texture->name, "noshader"))
+ texture->surfaceparms = 0;
+ else
+ {
+ success = false;
+ Con_DPrintf("%s: No shader found for texture \"%s\"\n", loadmodel->name, texture->name);
+ texture->surfaceparms = 0;
+ if (texture->surfaceflags & Q3SURFACEFLAG_NODRAW)
+ texture->basematerialflags |= MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
+ else if (texture->surfaceflags & Q3SURFACEFLAG_SKY)
+ texture->basematerialflags |= MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW;
+ else
+ texture->basematerialflags |= MATERIALFLAG_WALL;
+ texture->numskinframes = 1;
+ if (!(texture->skinframes[0] = R_SkinFrame_LoadExternal(texture->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | (r_picmipworld.integer ? TEXF_PICMIP : 0), false)))
+ Con_DPrintf("%s: could not load texture for missing shader \"%s\"\n", loadmodel->name, texture->name);
+ }
+ // init the animation variables
+ texture->currentframe = texture;
+ if (texture->numskinframes < 1)
+ texture->numskinframes = 1;
+ if (!texture->skinframes[0])
+ texture->skinframes[0] = R_SkinFrame_LoadMissing();
+ texture->currentskinframe = texture->skinframes[0];
+ texture->backgroundcurrentskinframe = texture->backgroundskinframes[0];
+ return success;
+}
+
skinfile_t *Mod_LoadSkinFiles(void)
{
int i, words, numtags, line, tagsetsused = false, wordsoverflow;
void Mod_ShadowMesh_CalcBBox(shadowmesh_t *firstmesh, vec3_t mins, vec3_t maxs, vec3_t center, float *radius);
void Mod_ShadowMesh_Free(shadowmesh_t *mesh);
+#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;
+
+void Mod_LoadQ3Shaders(void);
+q3shaderinfo_t *Mod_LookupQ3Shader(const char *name);
+qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qboolean q1bsp, qboolean q3bsp, qboolean md3);
+
extern cvar_t r_mipskins;
typedef struct skinfileitem_s