+ 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 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;
+ 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;
+ loadmodel->num_texturesperskin = loadmodel->num_textures;
+
+ for (i = 0;i < count;i++)
+ {
+ strlcpy (out[i].name, in[i].name, sizeof (out[i].name));
+ out[i].surfaceflags = LittleLong(in[i].surfaceflags);
+ out[i].supercontents = Mod_Q3BSP_SuperContentsFromNativeContents(loadmodel, LittleLong(in[i].contents));
+ }
+
+ 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 | (shader->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP) | (shader->primarylayer->clampmap ? TEXF_CLAMP : 0))))
+ Con_DPrintf("%s: could not load texture \"%s\" (frame %i) for shader \"%s\"\n", loadmodel->name, shader->primarylayer->texturename[j], j, out->name);
+ }
+ 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 | (shader->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP) | (shader->backgroundlayer->clampmap ? TEXF_CLAMP : 0))))
+ {
+ 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
+ {
+ 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