From: havoc Date: Wed, 14 Sep 2016 04:53:02 +0000 (+0000) Subject: Overhauled quake3 shader loading such that it now produces shader passes that could... X-Git-Tag: xonotic-v0.8.5~88^2~37 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=commitdiff_plain;h=f5e4d031fd609e6a6ab36559e599211aa9ac51c3 Overhauled quake3 shader loading such that it now produces shader passes that could render the material mostly correctly (rendering not yet implemented for the pre/post passes the logic identifies). Main visible effect of this is that quake3 maps look more correct, but don't have any fancy effects yet. This changed the loaders for all other formats that produce texture_t as texture->materialshaderpass-> is the new source of truth for several things. git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@12285 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/gl_rmain.c b/gl_rmain.c index 2800ebcf..349b78e5 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -8208,13 +8208,13 @@ texture_t *R_GetCurrentTexture(texture_t *t) 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; @@ -8249,7 +8249,7 @@ texture_t *R_GetCurrentTexture(texture_t *t) 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) { @@ -8278,10 +8278,9 @@ texture_t *R_GetCurrentTexture(texture_t *t) 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) @@ -8298,8 +8297,10 @@ texture_t *R_GetCurrentTexture(texture_t *t) 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; @@ -9242,60 +9243,63 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const 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))) @@ -10138,10 +10142,10 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const } } - 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: @@ -10159,8 +10163,8 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const // 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: @@ -10200,10 +10204,10 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const // 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; diff --git a/gl_rsurf.c b/gl_rsurf.c index 93dd027f..72c5a472 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -1618,7 +1618,7 @@ static void R_ListWorldTextures (void) Con_Print("Worldmodel textures :\n"); for(i=0,t=m->data_textures;inum_textures;i++,t++) - if (t->numskinframes) + if (t->name[0] && strcasecmp(t->name, "NO TEXTURE FOUND")) Con_Printf("%s\n", t->name); } diff --git a/model_alias.c b/model_alias.c index aeb512e9..68f19b8d 100644 --- a/model_alias.c +++ b/model_alias.c @@ -909,9 +909,7 @@ static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *ski 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; diff --git a/model_brush.c b/model_brush.c index 0c49508f..21838fb0 100644 --- a/model_brush.c +++ b/model_brush.c @@ -1622,7 +1622,7 @@ static void R_Q1BSP_LoadSplitSky (unsigned char *src, int width, int height, int 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; @@ -1653,9 +1653,9 @@ static void Mod_Q1BSP_LoadTextures(sizebuf_t *sb) // 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)); @@ -1664,10 +1664,8 @@ static void Mod_Q1BSP_LoadTextures(sizebuf_t *sb) 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) @@ -1827,7 +1825,7 @@ static void Mod_Q1BSP_LoadTextures(sizebuf_t *sb) } 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) @@ -1856,15 +1854,15 @@ static void Mod_Q1BSP_LoadTextures(sizebuf_t *sb) 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; @@ -1879,7 +1877,7 @@ static void Mod_Q1BSP_LoadTextures(sizebuf_t *sb) 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 @@ -1895,12 +1893,12 @@ static void Mod_Q1BSP_LoadTextures(sizebuf_t *sb) 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; } @@ -4413,12 +4411,12 @@ static void Mod_Q2BSP_LoadTexinfo(sizebuf_t *sb) } 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) { @@ -4443,7 +4441,7 @@ static void Mod_Q2BSP_LoadTexinfo(sizebuf_t *sb) 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; diff --git a/model_shared.c b/model_shared.c index 67471410..2061c03e 100644 --- a/model_shared.c +++ b/model_shared.c @@ -100,7 +100,7 @@ static void mod_shutdown(void) 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; @@ -110,10 +110,11 @@ static void mod_newmap(void) { 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); @@ -348,7 +349,9 @@ static void Mod_FindPotentialDeforms(dp_model_t *mod) 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++) { @@ -1727,8 +1730,6 @@ void Mod_LoadQ3Shaders(void) 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; @@ -2380,30 +2381,6 @@ void Mod_LoadQ3Shaders(void) // 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); @@ -2435,9 +2412,52 @@ q3shaderinfo_t *Mod_LookupQ3Shader(const char *name) 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; @@ -2549,51 +2569,99 @@ nothing GL_ZERO GL_ONE } 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) @@ -2734,19 +2802,19 @@ nothing GL_ZERO GL_ONE 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); @@ -2762,12 +2830,12 @@ nothing GL_ZERO GL_ONE } // 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; } diff --git a/model_shared.h b/model_shared.h index b687b1f0..834ac4d2 100644 --- a/model_shared.h +++ b/model_shared.h @@ -263,7 +263,7 @@ shadowmesh_t; #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 @@ -451,7 +451,6 @@ typedef struct q3shaderinfo_s qboolean lighting; qboolean vertexalpha; qboolean textureblendalpha; - int primarylayer, backgroundlayer; q3shaderinfo_layer_t layers[Q3SHADER_MAXLAYERS]; char skyboxname[Q3PATHLENGTH]; q3shaderinfo_deform_t deforms[Q3MAXDEFORMS]; @@ -503,6 +502,20 @@ typedef struct q3shaderinfo_s } 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, @@ -546,16 +559,10 @@ typedef struct texture_s 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]; @@ -578,12 +585,14 @@ typedef struct texture_s 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 @@ -1146,6 +1155,8 @@ void Mod_FreeQ3Shaders(void); 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; diff --git a/model_sprite.c b/model_sprite.c index 9b8bab23..2dd74695 100644 --- a/model_sprite.c +++ b/model_sprite.c @@ -75,8 +75,8 @@ static void Mod_SpriteSetupTexture(texture_t *texture, skinframe_t *skinframe, q 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))