Overhauled quake3 shader loading such that it now produces shader passes that could...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Wed, 14 Sep 2016 04:53:02 +0000 (04:53 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Wed, 14 Sep 2016 04:53:02 +0000 (04:53 +0000)
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

gl_rmain.c
gl_rsurf.c
model_alias.c
model_brush.c
model_shared.c
model_shared.h
model_sprite.c

index 2800ebc..349b78e 100644 (file)
@@ -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;
index 93dd027..72c5a47 100644 (file)
@@ -1618,7 +1618,7 @@ static void R_ListWorldTextures (void)
 
        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);
 }
 
index aeb512e..68f19b8 100644 (file)
@@ -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;
index 0c49508..21838fb 100644 (file)
@@ -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;
index 6747141..2061c03 100644 (file)
@@ -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;
 }
 
index b687b1f..834ac4d 100644 (file)
@@ -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;
index 9b8bab2..2dd7469 100644 (file)
@@ -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))