if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
t->currentskinframe = r_qwskincache[i].skinframe;
- if (t->currentskinframe == NULL)
- t->currentskinframe = t->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->skinframerate, t->numskinframes)];
+ if (t->materialshaderpass && t->currentskinframe == NULL)
+ t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
}
- else if (t->numskinframes >= 2)
- t->currentskinframe = t->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->skinframerate, t->numskinframes)];
- if (t->backgroundnumskinframes >= 2)
- t->backgroundcurrentskinframe = t->backgroundskinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundskinframerate, t->backgroundnumskinframes)];
+ else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
+ t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
+ if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
+ t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
t->currentmaterialflags = t->basematerialflags;
t->currentalpha = rsurface.colormod[3] * t->basealpha;
t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
- if (t->backgroundnumskinframes)
+ if (t->backgroundshaderpass)
t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
{
Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
}
- for (i = 0, tcmod = t->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
- R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
- for (i = 0, tcmod = t->backgroundtcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
- R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
+ if (t->materialshaderpass)
+ for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
+ R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
t->colormapping = VectorLength2(rsurface.colormap_pantscolor) + VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
if (t->currentskinframe->qpixels)
t->glowtexture = t->currentskinframe->glow;
t->fogtexture = t->currentskinframe->fog;
t->reflectmasktexture = t->currentskinframe->reflect;
- if (t->backgroundnumskinframes)
+ if (t->backgroundshaderpass)
{
+ for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
+ R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
t->backgroundglosstexture = r_texture_black;
break;
}
}
- switch(rsurface.texture->tcgen.tcgen)
+ if (rsurface.texture->materialshaderpass)
{
- default:
- case Q3TCGEN_TEXTURE:
- break;
- case Q3TCGEN_LIGHTMAP:
- if (!dynamicvertex)
- {
- r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
- r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
- r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
- r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
- }
- dynamicvertex = true;
- batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
- needsupdate |= BATCHNEED_VERTEXMESH_LIGHTMAP;
- break;
- case Q3TCGEN_VECTOR:
- if (!dynamicvertex)
+ switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
{
- r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
- r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
- r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
- r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
- }
- dynamicvertex = true;
- batchneed |= BATCHNEED_ARRAY_VERTEX;
- needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
- break;
- case Q3TCGEN_ENVIRONMENT:
- if (!dynamicvertex)
- {
- r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
- r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
- r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
- r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
+ default:
+ case Q3TCGEN_TEXTURE:
+ break;
+ case Q3TCGEN_LIGHTMAP:
+ if (!dynamicvertex)
+ {
+ r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
+ }
+ dynamicvertex = true;
+ batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
+ needsupdate |= BATCHNEED_VERTEXMESH_LIGHTMAP;
+ break;
+ case Q3TCGEN_VECTOR:
+ if (!dynamicvertex)
+ {
+ r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
+ }
+ dynamicvertex = true;
+ batchneed |= BATCHNEED_ARRAY_VERTEX;
+ needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
+ break;
+ case Q3TCGEN_ENVIRONMENT:
+ if (!dynamicvertex)
+ {
+ r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
+ }
+ dynamicvertex = true;
+ batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
+ needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
+ break;
}
- dynamicvertex = true;
- batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
- needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
- break;
- }
- if (rsurface.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
- {
- if (!dynamicvertex)
+ if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
{
- r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
- r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
- r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
- r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
+ if (!dynamicvertex)
+ {
+ r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
+ }
+ dynamicvertex = true;
+ batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
+ needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
}
- dynamicvertex = true;
- batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
- needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
}
if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
}
}
- if (rsurface.batchtexcoordtexture2f)
+ if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
{
// generate texcoords based on the chosen texcoord source
- switch(rsurface.texture->tcgen.tcgen)
+ switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
{
default:
case Q3TCGEN_TEXTURE:
// rsurface.batchtexcoordtexture2f_bufferoffset = 0;
for (j = 0;j < batchnumvertices;j++)
{
- rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->tcgen.parms);
- rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->tcgen.parms + 3);
+ rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
+ rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
}
break;
case Q3TCGEN_ENVIRONMENT:
// and we only support that as the first one
// (handling a mixture of turbulent and other tcmods would be problematic
// without punting it entirely to a software path)
- if (rsurface.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
+ if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
{
- amplitude = rsurface.texture->tcmods[0].parms[1];
- animpos = rsurface.texture->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->tcmods[0].parms[3];
+ amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
+ animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
// rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
// rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
// rsurface.batchtexcoordtexture2f_bufferoffset = 0;
Con_Print("Worldmodel textures :\n");
for(i=0,t=m->data_textures;i<m->num_textures;i++,t++)
- if (t->numskinframes)
+ if (t->name[0] && strcasecmp(t->name, "NO TEXTURE FOUND"))
Con_Printf("%s\n", t->name);
}
memset(texture, 0, sizeof(*texture));
texture->currentframe = texture;
//texture->animated = false;
- texture->numskinframes = 1;
- texture->skinframerate = 1;
- texture->skinframes[0] = skinframe;
+ texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(skinframe);
texture->currentskinframe = skinframe;
//texture->backgroundnumskinframes = 0;
//texture->customblendfunc[0] = 0;
static void Mod_Q1BSP_LoadTextures(sizebuf_t *sb)
{
int i, j, k, num, max, altmax, mtwidth, mtheight, doffset, incomplete, nummiptex = 0;
- skinframe_t *skinframe;
+ skinframe_t *skinframemissing;
texture_t *tx, *tx2, *anims[10], *altanims[10];
texture_t backuptex;
unsigned char *data, *mtdata;
// fill out all slots with notexture
if (cls.state != ca_dedicated)
- skinframe = R_SkinFrame_LoadMissing();
+ skinframemissing = R_SkinFrame_LoadMissing();
else
- skinframe = NULL;
+ skinframemissing = NULL;
for (i = 0, tx = loadmodel->data_textures;i < loadmodel->num_textures;i++, tx++)
{
strlcpy(tx->name, "NO TEXTURE FOUND", sizeof(tx->name));
tx->basealpha = 1.0f;
if (cls.state != ca_dedicated)
{
- tx->numskinframes = 1;
- tx->skinframerate = 1;
- tx->skinframes[0] = skinframe;
- tx->currentskinframe = tx->skinframes[0];
+ tx->materialshaderpass = tx->shaderpasses[0] = Mod_CreateShaderPass(skinframemissing);
+ tx->currentskinframe = skinframemissing;
}
tx->basematerialflags = MATERIALFLAG_WALL;
if (i == loadmodel->num_textures - 1)
}
else
{
- skinframe = R_SkinFrame_LoadExternal(gamemode == GAME_TENEBRAE ? tx->name : va(vabuf, sizeof(vabuf), "textures/%s/%s", mapname, tx->name), TEXF_ALPHA | TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP | TEXF_COMPRESS, false);
+ skinframe_t *skinframe = R_SkinFrame_LoadExternal(gamemode == GAME_TENEBRAE ? tx->name : va(vabuf, sizeof(vabuf), "textures/%s/%s", mapname, tx->name), TEXF_ALPHA | TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP | TEXF_COMPRESS, false);
if (!skinframe)
skinframe = R_SkinFrame_LoadExternal(gamemode == GAME_TENEBRAE ? tx->name : va(vabuf, sizeof(vabuf), "textures/%s", tx->name), TEXF_ALPHA | TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP | TEXF_COMPRESS, false);
if (skinframe)
else if (mtdata) // texture included
skinframe = R_SkinFrame_LoadInternalQuake(tx->name, TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP, false, r_fullbrights.integer, mtdata, tx->width, tx->height);
}
- // if skinframe is still NULL the "missing" texture will be used
+ // if skinframe is still NULL the "missing" texture has already been assigned to this
if (skinframe)
- tx->skinframes[0] = skinframe;
+ tx->materialshaderpass->skinframes[0] = skinframe;
}
// LordHavoc: some Tenebrae textures get replaced by black
if (!strncmp(tx->name, "*glassmirror", 12)) // Tenebrae
- tx->skinframes[0] = R_SkinFrame_LoadInternalBGRA(tx->name, TEXF_MIPMAP | TEXF_ALPHA, zerotrans, 1, 1, false);
+ tx->materialshaderpass->skinframes[0] = R_SkinFrame_LoadInternalBGRA(tx->name, TEXF_MIPMAP | TEXF_ALPHA, zerotrans, 1, 1, false);
else if (!strncmp(tx->name, "mirror", 6)) // Tenebrae
- tx->skinframes[0] = R_SkinFrame_LoadInternalBGRA(tx->name, 0, zeroopaque, 1, 1, false);
+ tx->materialshaderpass->skinframes[0] = R_SkinFrame_LoadInternalBGRA(tx->name, 0, zeroopaque, 1, 1, false);
}
tx->basematerialflags = MATERIALFLAG_WALL;
tx->basematerialflags |= MATERIALFLAG_WATERSCROLL | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_NOSHADOW;
else
tx->basematerialflags |= MATERIALFLAG_WATERSCROLL | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_NOSHADOW | MATERIALFLAG_WATERALPHA | MATERIALFLAG_WATERSHADER;
- if (tx->skinframes[0] && tx->skinframes[0]->hasalpha)
+ if (tx->materialshaderpass->skinframes[0]->hasalpha)
tx->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
}
else if (tx->name[0] == '{') // fence textures
tx->basematerialflags = MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW;
else if (!strcmp(tx->name, "caulk"))
tx->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
- else if (tx->skinframes[0] && tx->skinframes[0]->hasalpha)
+ else if (tx->materialshaderpass->skinframes[0]->hasalpha)
tx->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
// start out with no animation
tx->currentframe = tx;
- tx->currentskinframe = tx->skinframes[0];
+ tx->currentskinframe = tx->materialshaderpass->skinframes[0];
tx->currentmaterialflags = tx->basematerialflags;
}
}
if (q2flags & Q2SURF_FLOWING)
{
- tx->tcmods[0].tcmod = Q3TCMOD_SCROLL;
+ tx->materialshaderpass->tcmods[0].tcmod = Q3TCMOD_SCROLL;
if (q2flags & Q2SURF_WARP)
- tx->tcmods[0].parms[0] = -0.5f;
+ tx->materialshaderpass->tcmods[0].parms[0] = -0.5f;
else
- tx->tcmods[0].parms[0] = -1.6f;
- tx->tcmods[0].parms[1] = 0.0f;
+ tx->materialshaderpass->tcmods[0].parms[0] = -1.6f;
+ tx->materialshaderpass->tcmods[0].parms[1] = 0.0f;
}
if (q2flags & Q2SURF_ALPHATEST)
{
tx->supercontents = Mod_Q2BSP_SuperContentsFromNativeContents(loadmodel, tx->q2contents);
// set the current values to the base values
tx->currentframe = tx;
- tx->currentskinframe = tx->skinframes[0];
+ tx->currentskinframe = tx->materialshaderpass->skinframes[0];
tx->currentmaterialflags = tx->basematerialflags;
loadmodel->num_texturesperskin++;
loadmodel->num_textures = loadmodel->num_texturesperskin;
static void mod_newmap(void)
{
msurface_t *surface;
- int i, j, k, surfacenum, ssize, tsize;
+ int i, j, k, l, surfacenum, ssize, tsize;
int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
dp_model_t *mod;
{
for (j = 0;j < mod->num_textures && mod->data_textures;j++)
{
- for (k = 0;k < mod->data_textures[j].numskinframes;k++)
- R_SkinFrame_MarkUsed(mod->data_textures[j].skinframes[k]);
- for (k = 0;k < mod->data_textures[j].backgroundnumskinframes;k++)
- R_SkinFrame_MarkUsed(mod->data_textures[j].backgroundskinframes[k]);
+ // note that materialshaderpass and backgroundshaderpass point to shaderpasses[] and so do the pre/post shader ranges, so this catches all of them...
+ for (l = 0; l < Q3SHADER_MAXLAYERS; l++)
+ if (mod->data_textures[j].shaderpasses[l])
+ for (k = 0; k < mod->data_textures[j].shaderpasses[l]->numframes; k++)
+ R_SkinFrame_MarkUsed(mod->data_textures[j].shaderpasses[l]->skinframes[k]);
}
if (mod->brush.solidskyskinframe)
R_SkinFrame_MarkUsed(mod->brush.solidskyskinframe);
for (i = 0;i < mod->num_textures;i++)
{
texture = mod->data_textures + i;
- if (texture->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
+ if (texture->materialshaderpass && texture->materialshaderpass->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
+ mod->wantnormals = true;
+ if (texture->materialshaderpass && texture->materialshaderpass->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
mod->wantnormals = true;
for (j = 0;j < Q3MAXDEFORMS;j++)
{
shader.lighting = false;
shader.vertexalpha = false;
shader.textureblendalpha = false;
- shader.primarylayer = 0;
- shader.backgroundlayer = 0;
shader.skyboxname[0] = 0;
shader.deforms[0].deform = Q3DEFORM_NONE;
shader.dpnortlight = false;
// hide this shader if a cvar said it should be killed
if (shader.dpshaderkill)
shader.numlayers = 0;
- // pick the primary layer to render with
- if (shader.numlayers)
- {
- shader.backgroundlayer = -1;
- shader.primarylayer = 0;
- // if lightmap comes first this is definitely an ordinary texture
- // if the first two layers have the correct blendfuncs and use vertex alpha, it is a blended terrain shader
- if ((shader.layers[shader.primarylayer].texturename != NULL)
- && !strcasecmp(shader.layers[shader.primarylayer].texturename[0], "$lightmap"))
- {
- shader.backgroundlayer = -1;
- shader.primarylayer = 1;
- }
- else if (shader.numlayers >= 2
- && shader.layers[1].alphagen.alphagen == Q3ALPHAGEN_VERTEX
- && (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[1].blendfunc[0] == GL_ONE && shader.layers[1].blendfunc[1] == GL_ZERO && shader.layers[1].alphatest)))
- {
- // terrain blending or other effects
- shader.backgroundlayer = 0;
- shader.primarylayer = 1;
- }
- }
// fix up multiple reflection types
if(shader.textureflags & Q3TEXTUREFLAG_WATERSHADER)
shader.textureflags &= ~(Q3TEXTUREFLAG_REFRACTION | Q3TEXTUREFLAG_REFLECTION | Q3TEXTUREFLAG_CAMERA);
return NULL;
}
-qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags)
+texture_shaderpass_t *Mod_CreateShaderPass(skinframe_t *skinframe)
+{
+ texture_shaderpass_t *shaderpass = (texture_shaderpass_t *)Mem_Alloc(loadmodel->mempool, sizeof(*shaderpass));
+ shaderpass->framerate = 0.0f;
+ shaderpass->numframes = 1;
+ shaderpass->blendfunc[0] = GL_ONE;
+ shaderpass->blendfunc[1] = GL_ZERO;
+ shaderpass->rgbgen.rgbgen = Q3RGBGEN_IDENTITY;
+ shaderpass->alphagen.alphagen = Q3ALPHAGEN_IDENTITY;
+ shaderpass->alphatest = false;
+ shaderpass->tcgen.tcgen = Q3TCGEN_TEXTURE;
+ shaderpass->skinframes[0] = skinframe;
+ return shaderpass;
+}
+
+texture_shaderpass_t *Mod_CreateShaderPassFromQ3ShaderLayer(q3shaderinfo_layer_t *layer, int layerindex, int texflags, const char *texturename)
{
int j;
+ texture_shaderpass_t *shaderpass = (texture_shaderpass_t *)Mem_Alloc(loadmodel->mempool, sizeof(*shaderpass));
+ shaderpass->alphatest = layer->alphatest != 0;
+ shaderpass->framerate = layer->framerate;
+ shaderpass->numframes = layer->numframes;
+ shaderpass->blendfunc[0] = layer->blendfunc[0];
+ shaderpass->blendfunc[1] = layer->blendfunc[1];
+ shaderpass->rgbgen = layer->rgbgen;
+ shaderpass->alphagen = layer->alphagen;
+ shaderpass->tcgen = layer->tcgen;
+ for (j = 0; j < Q3MAXTCMODS && layer->tcmods[j].tcmod != Q3TCMOD_NONE; j++)
+ shaderpass->tcmods[j] = layer->tcmods[j];
+ for (j = 0; j < layer->numframes; j++)
+ {
+ if (cls.state == ca_dedicated)
+ {
+ shaderpass->skinframes[j] = NULL;
+ }
+ else if (!(shaderpass->skinframes[j] = R_SkinFrame_LoadExternal(layer->texturename[j], texflags, false)))
+ {
+ Con_Printf("^1%s:^7 could not load texture ^3\"%s\"^7 (frame %i) for layer %i of shader ^2\"%s\"\n", loadmodel->name, layer->texturename[j], j, layerindex, texturename);
+ shaderpass->skinframes[j] = R_SkinFrame_LoadMissing();
+ }
+ }
+ return shaderpass;
+}
+
+qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags)
+{
int texflagsmask, texflagsor;
qboolean success = true;
q3shaderinfo_t *shader;
}
if (!shader->lighting)
texture->basematerialflags |= MATERIALFLAG_FULLBRIGHT;
- if (shader->primarylayer >= 0)
+
+ // here be dragons: convert quake3 shaders to material
+ if (shader->numlayers > 0)
{
- q3shaderinfo_layer_t* primarylayer = shader->layers + shader->primarylayer;
- // copy over many primarylayer parameters
- texture->rgbgen = primarylayer->rgbgen;
- texture->alphagen = primarylayer->alphagen;
- texture->tcgen = primarylayer->tcgen;
- memcpy(texture->tcmods, primarylayer->tcmods, sizeof(texture->tcmods));
- // load the textures
- texture->numskinframes = primarylayer->numframes;
- texture->skinframerate = primarylayer->framerate;
- for (j = 0;j < primarylayer->numframes;j++)
+ int i;
+ int terrainbackgroundlayer = -1;
+ int lightmaplayer = -1;
+ int alphagenspecularlayer = -1;
+ int rgbgenvertexlayer = -1;
+ int rgbgendiffuselayer = -1;
+ int materiallayer = -1;
+ int endofprelayers = 0;
+ int firstpostlayer = 0;
+ int shaderpassindex = 0;
+ for (i = 0; i < shader->numlayers; i++)
{
- if(cls.state == ca_dedicated)
- {
- texture->skinframes[j] = NULL;
- }
- else if (!(texture->skinframes[j] = R_SkinFrame_LoadExternal(primarylayer->texturename[j], (primarylayer->texflags & texflagsmask) | texflagsor, false)))
- {
- Con_Printf("^1%s:^7 could not load texture ^3\"%s\"^7 (frame %i) for shader ^2\"%s\"\n", loadmodel->name, primarylayer->texturename[j], j, texture->name);
- texture->skinframes[j] = R_SkinFrame_LoadMissing();
- }
+ if (shader->layers[i].texturename != NULL && !strcasecmp(shader->layers[i].texturename[0], "$lightmap"))
+ lightmaplayer = i;
+ if (shader->layers[i].rgbgen.rgbgen == Q3RGBGEN_VERTEX)
+ rgbgenvertexlayer = i;
+ if (shader->layers[i].rgbgen.rgbgen == Q3RGBGEN_LIGHTINGDIFFUSE)
+ rgbgendiffuselayer = i;
+ if (shader->layers[i].alphagen.alphagen == Q3ALPHAGEN_LIGHTINGSPECULAR)
+ alphagenspecularlayer = i;
}
- }
- if (shader->backgroundlayer >= 0)
- {
- q3shaderinfo_layer_t* backgroundlayer = shader->layers + shader->backgroundlayer;
- // copy over one secondarylayer parameter
- memcpy(texture->backgroundtcmods, backgroundlayer->tcmods, sizeof(texture->backgroundtcmods));
- // load the textures
- texture->backgroundnumskinframes = backgroundlayer->numframes;
- texture->backgroundskinframerate = backgroundlayer->framerate;
- for (j = 0;j < backgroundlayer->numframes;j++)
+ if (shader->numlayers >= 2
+ && shader->layers[1].alphagen.alphagen == Q3ALPHAGEN_VERTEX
+ && (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[1].blendfunc[0] == GL_ONE && shader->layers[1].blendfunc[1] == GL_ZERO && shader->layers[1].alphatest)))
{
- if(cls.state == ca_dedicated)
- {
- texture->skinframes[j] = NULL;
- }
- else if (!(texture->backgroundskinframes[j] = R_SkinFrame_LoadExternal(backgroundlayer->texturename[j], (backgroundlayer->texflags & texflagsmask) | texflagsor, false)))
- {
- Con_Printf("^1%s:^7 could not load texture ^3\"%s\"^7 (background frame %i) for shader ^2\"%s\"\n", loadmodel->name, backgroundlayer->texturename[j], j, texture->name);
- texture->backgroundskinframes[j] = R_SkinFrame_LoadMissing();
- }
+ // terrain blend or certain other effects involving alphatest over a regular layer
+ terrainbackgroundlayer = 0;
+ materiallayer = 1;
+ // terrain may be vertex lit (in which case both layers are rgbGen vertex) or lightmapped (in which ase the third layer is lightmap)
+ firstpostlayer = lightmaplayer >= 0 ? lightmaplayer + 1 : materiallayer + 1;
+ }
+ else if (lightmaplayer == 0)
+ {
+ // ordinary texture but with $lightmap before diffuse
+ materiallayer = 1;
+ firstpostlayer = lightmaplayer + 2;
+ }
+ else if (lightmaplayer >= 1)
+ {
+ // ordinary texture - we don't properly apply lighting to the prelayers, but oh well...
+ endofprelayers = lightmaplayer - 1;
+ materiallayer = lightmaplayer - 1;
+ firstpostlayer = lightmaplayer + 1;
}
+ else if (rgbgenvertexlayer >= 0)
+ {
+ // map models with baked lighting
+ materiallayer = rgbgenvertexlayer;
+ endofprelayers = rgbgenvertexlayer;
+ firstpostlayer = rgbgenvertexlayer + 1;
+ }
+ else if (rgbgendiffuselayer >= 0)
+ {
+ // entity models with dynamic lighting
+ materiallayer = rgbgendiffuselayer;
+ endofprelayers = rgbgendiffuselayer;
+ firstpostlayer = rgbgendiffuselayer + 1;
+ // player models often have specular as a pass after diffuse - we don't currently make use of that specular texture (would need to meld it into the skinframe)...
+ if (alphagenspecularlayer >= 0)
+ firstpostlayer = alphagenspecularlayer + 1;
+ }
+ else
+ {
+ // special effects shaders - treat first as primary layer and do everything else as post
+ endofprelayers = 0;
+ materiallayer = 0;
+ firstpostlayer = 1;
+ }
+ // convert the main material layer
+ // FIXME: if alphagenspecularlayer is used, we should pass a specular texture name to R_SkinFrame_LoadExternal and have it load that texture instead of the assumed name for _gloss texture
+ if (materiallayer >= 0)
+ texture->materialshaderpass = texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(&shader->layers[materiallayer], materiallayer, (shader->layers[materiallayer].texflags & texflagsmask) | texflagsor, texture->name);
+ // convert the terrain background blend layer (if any)
+ if (terrainbackgroundlayer >= 0)
+ texture->backgroundshaderpass = texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(&shader->layers[terrainbackgroundlayer], terrainbackgroundlayer, (shader->layers[terrainbackgroundlayer].texflags & texflagsmask) | texflagsor, texture->name);
+ // convert the prepass layers (if any)
+ texture->startpreshaderpass = shaderpassindex;
+ for (i = 0; i < endofprelayers; i++)
+ texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(&shader->layers[i], i, (shader->layers[i].texflags & texflagsmask) | texflagsor, texture->name);
+ texture->endpreshaderpass = shaderpassindex;
+ texture->startpostshaderpass = shaderpassindex;
+ // convert the postpass layers (if any)
+ for (i = firstpostlayer; i < shader->numlayers; i++)
+ texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(&shader->layers[i], i, (shader->layers[i].texflags & texflagsmask) | texflagsor, texture->name);
+ texture->startpostshaderpass = shaderpassindex;
}
+
if (shader->dpshadow)
texture->basematerialflags &= ~MATERIALFLAG_NOSHADOW;
if (shader->dpnoshadow)
texture->basematerialflags |= MATERIALFLAG_WALL;
texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
}
- texture->numskinframes = 1;
if(cls.state == ca_dedicated)
{
- texture->skinframes[0] = NULL;
+ texture->materialshaderpass = NULL;
success = false;
}
else
{
if (fallback)
{
- if ((texture->skinframes[0] = R_SkinFrame_LoadExternal(texture->name, defaulttexflags, false)))
+ texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(R_SkinFrame_LoadExternal(texture->name, defaulttexflags, false));
+ if (texture->materialshaderpass->skinframes[0])
{
- if(texture->skinframes[0]->hasalpha)
+ if (texture->materialshaderpass->skinframes[0]->hasalpha)
texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
if (texture->q2contents)
texture->supercontents = Mod_Q2BSP_SuperContentsFromNativeContents(loadmodel, texture->q2contents);
}
// 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];
+ if (!texture->materialshaderpass)
+ texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(R_SkinFrame_LoadMissing());
+ if (!texture->materialshaderpass->skinframes[0])
+ texture->materialshaderpass->skinframes[0] = R_SkinFrame_LoadMissing();
+ texture->currentskinframe = texture->materialshaderpass ? texture->materialshaderpass->skinframes[0] : NULL;
+ texture->backgroundcurrentskinframe = texture->backgroundshaderpass ? texture->backgroundshaderpass->skinframes[0] : NULL;
return success;
}
#define TEXTURE_MAXFRAMES 64
#define Q3WAVEPARMS 4
#define Q3DEFORM_MAXPARMS 3
-#define Q3SHADER_MAXLAYERS 2 // FIXME support more than that (currently only two are used, so why keep more in RAM?)
+#define Q3SHADER_MAXLAYERS 8
#define Q3RGBGEN_MAXPARMS 3
#define Q3ALPHAGEN_MAXPARMS 1
#define Q3TCGEN_MAXPARMS 6
qboolean lighting;
qboolean vertexalpha;
qboolean textureblendalpha;
- int primarylayer, backgroundlayer;
q3shaderinfo_layer_t layers[Q3SHADER_MAXLAYERS];
char skyboxname[Q3PATHLENGTH];
q3shaderinfo_deform_t deforms[Q3MAXDEFORMS];
}
q3shaderinfo_t;
+typedef struct texture_shaderpass_s
+{
+ qboolean alphatest; // FIXME: handle alphafunc properly
+ float framerate;
+ int numframes;
+ skinframe_t *skinframes[TEXTURE_MAXFRAMES];
+ int blendfunc[2];
+ q3shaderinfo_layer_rgbgen_t rgbgen;
+ q3shaderinfo_layer_alphagen_t alphagen;
+ q3shaderinfo_layer_tcgen_t tcgen;
+ q3shaderinfo_layer_tcmod_t tcmods[Q3MAXTCMODS];
+}
+texture_shaderpass_t;
+
typedef enum texturelayertype_e
{
TEXTURELAYERTYPE_INVALID,
float biaspolygonfactor;
float biaspolygonoffset;
- // textures to use when rendering this material
+ // textures to use when rendering this material (derived from materialshaderpass)
skinframe_t *currentskinframe;
- int numskinframes;
- float skinframerate;
- skinframe_t *skinframes[TEXTURE_MAXFRAMES];
- // background layer (for terrain texture blending)
+ // textures to use for terrain texture blending (derived from backgroundshaderpass)
skinframe_t *backgroundcurrentskinframe;
- int backgroundnumskinframes;
- float backgroundskinframerate;
- skinframe_t *backgroundskinframes[TEXTURE_MAXFRAMES];
// total frames in sequence and alternate sequence
int anim_total[2];
matrix4x4_t currentbackgroundtexmatrix;
// various q3 shader features
- q3shaderinfo_layer_rgbgen_t rgbgen;
- q3shaderinfo_layer_alphagen_t alphagen;
- q3shaderinfo_layer_tcgen_t tcgen;
- q3shaderinfo_layer_tcmod_t tcmods[Q3MAXTCMODS];
- q3shaderinfo_layer_tcmod_t backgroundtcmods[Q3MAXTCMODS];
q3shaderinfo_deform_t deforms[Q3MAXDEFORMS];
+ texture_shaderpass_t *shaderpasses[Q3SHADER_MAXLAYERS]; // all shader passes in one array
+ texture_shaderpass_t *materialshaderpass; // equal to one of shaderpasses[] or NULL
+ texture_shaderpass_t *backgroundshaderpass; // equal to one of shaderpasses[] or NULL
+ unsigned char startpreshaderpass; // range within shaderpasses[]
+ unsigned char endpreshaderpass; // number of preshaderpasses
+ unsigned char startpostshaderpass; // range within shaderpasses[]
+ unsigned char endpostshaderpass; // number of postshaderpasses
qboolean colormapping;
rtexture_t *basetexture; // original texture without pants/shirt/glow
void Mod_LoadQ3Shaders(void);
q3shaderinfo_t *Mod_LookupQ3Shader(const char *name);
qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags);
+texture_shaderpass_t *Mod_CreateShaderPass(skinframe_t *skinframe);
+texture_shaderpass_t *Mod_CreateShaderPassFromQ3ShaderLayer(q3shaderinfo_layer_t *layer, int layerindex, int texflags, const char *texturename);
extern cvar_t r_mipskins;
extern cvar_t r_mipnormalmaps;
else if (skinframe->hasalpha)
texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
texture->currentmaterialflags = texture->basematerialflags;
- texture->numskinframes = 1;
- texture->currentskinframe = texture->skinframes[0] = skinframe;
+ texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(skinframe);
+ texture->currentskinframe = skinframe;
texture->surfaceflags = 0;
texture->supercontents = SUPERCONTENTS_SOLID;
if (!(texture->basematerialflags & MATERIALFLAG_BLENDED))