]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_brush.c
- fix specular stuff on Q1BSP
[xonotic/darkplaces.git] / model_brush.c
index d8fe5ae41d87763160ae2cb8cb246b24e1fe9a6a..7af9d0e7b4a225a7fc75eb93601d21ff65122082 100644 (file)
@@ -853,7 +853,7 @@ static int Mod_Q1BSP_RecursiveHullCheckPoint(RecursiveHullCheckTraceInfo_t *t, i
 }
 //#endif
 
-static void Mod_Q1BSP_TracePoint(struct model_s *model, int frame, trace_t *trace, const vec3_t start, int hitsupercontentsmask)
+static void Mod_Q1BSP_TracePoint(struct model_s *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, int hitsupercontentsmask)
 {
        RecursiveHullCheckTraceInfo_t rhc;
 
@@ -869,13 +869,13 @@ static void Mod_Q1BSP_TracePoint(struct model_s *model, int frame, trace_t *trac
        Mod_Q1BSP_RecursiveHullCheckPoint(&rhc, rhc.hull->firstclipnode);
 }
 
-static void Mod_Q1BSP_TraceLine(struct model_s *model, int frame, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask)
+static void Mod_Q1BSP_TraceLine(struct model_s *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask)
 {
        RecursiveHullCheckTraceInfo_t rhc;
 
        if (VectorCompare(start, end))
        {
-               Mod_Q1BSP_TracePoint(model, frame, trace, start, hitsupercontentsmask);
+               Mod_Q1BSP_TracePoint(model, frameblend, skeleton, trace, start, hitsupercontentsmask);
                return;
        }
 
@@ -921,7 +921,7 @@ static void Mod_Q1BSP_TraceLine(struct model_s *model, int frame, trace_t *trace
 #endif
 }
 
-static void Mod_Q1BSP_TraceBox(struct model_s *model, int frame, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask)
+static void Mod_Q1BSP_TraceBox(struct model_s *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask)
 {
        // this function currently only supports same size start and end
        double boxsize[3];
@@ -930,9 +930,9 @@ static void Mod_Q1BSP_TraceBox(struct model_s *model, int frame, trace_t *trace,
        if (VectorCompare(boxmins, boxmaxs))
        {
                if (VectorCompare(start, end))
-                       Mod_Q1BSP_TracePoint(model, frame, trace, start, hitsupercontentsmask);
+                       Mod_Q1BSP_TracePoint(model, frameblend, skeleton, trace, start, hitsupercontentsmask);
                else
-                       Mod_Q1BSP_TraceLine(model, frame, trace, start, end, hitsupercontentsmask);
+                       Mod_Q1BSP_TraceLine(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask);
                return;
        }
 
@@ -1142,7 +1142,7 @@ void Collision_ClipTrace_Point(trace_t *trace, const vec3_t cmins, const vec3_t
 static qboolean Mod_Q1BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end)
 {
        trace_t trace;
-       model->TraceLine(model, 0, &trace, start, end, SUPERCONTENTS_VISBLOCKERMASK);
+       model->TraceLine(model, NULL, NULL, &trace, start, end, SUPERCONTENTS_VISBLOCKERMASK);
        return trace.fraction == 1;
 }
 
@@ -1459,6 +1459,8 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l)
                tx->reflectfactor = 1;
                Vector4Set(tx->reflectcolor4f, 1, 1, 1, 1);
                tx->r_water_wateralpha = 1;
+               tx->specularscalemod = 1;
+               tx->specularpowermod = 1;
        }
 
        if (!m)
@@ -1601,7 +1603,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l)
                                                        Mem_Free(freepixels);
                                        }
                                        else if (mtdata) // texture included
-                                               skinframe = R_SkinFrame_LoadInternalQuake(tx->name, TEXF_ALPHA | TEXF_MIPMAP | TEXF_PRECACHE | (r_picmipworld.integer ? TEXF_PICMIP : 0), false, r_fullbrights.integer, mtdata, tx->width, tx->height);
+                                               skinframe = R_SkinFrame_LoadInternalQuake(tx->name, TEXF_PRECACHE | TEXF_MIPMAP | (r_picmipworld.integer ? TEXF_PICMIP : 0), false, r_fullbrights.integer, mtdata, tx->width, tx->height);
                                }
                                // if skinframe is still NULL the "missing" texture will be used
                                if (skinframe)
@@ -1625,7 +1627,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l)
                                        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]->fog)
+                               if (tx->skinframes[0] && tx->skinframes[0]->hasalpha)
                                        tx->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
                        }
                        else if (!strncmp(tx->name, "mirror", 6)) // Tenebrae
@@ -1638,12 +1640,14 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l)
                                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]->fog)
+                       else if (tx->skinframes[0] && tx->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->specularscalemod = 1; // not supported here
+                       tx->specularpowermod = 1; // not supported here
                }
        }
 
@@ -2228,71 +2232,7 @@ static void Mod_Q1BSP_GenerateWarpMesh(msurface_t *surface)
 }
 #endif
 
-/* Maximum size of a single LM */
-#define MAX_SINGLE_LM_SIZE    256
-
-struct alloc_lm_row
-{
-       int rowY;
-       int currentX;
-};
-
-struct alloc_lm_state
-{
-       int currentY;
-       struct alloc_lm_row rows[MAX_SINGLE_LM_SIZE];
-};
-
-static void init_alloc_lm_state (struct alloc_lm_state* state)
-{
-       int r;
-
-       state->currentY = 0;
-       for (r = 0; r < MAX_SINGLE_LM_SIZE; r++)
-       {
-         state->rows[r].currentX = 0;
-         state->rows[r].rowY = -1;
-       }
-}
-
-static qboolean Mod_Q1BSP_AllocLightmapBlock(struct alloc_lm_state* state, int totalwidth, int totalheight, int blockwidth, int blockheight, int *outx, int *outy)
-{
-       struct alloc_lm_row* row;
-       int r;
-
-       row = &(state->rows[blockheight]);
-       if ((row->rowY < 0) || (row->currentX + blockwidth > totalwidth))
-       {
-               if (state->currentY + blockheight <= totalheight)
-               {
-                       row->rowY = state->currentY;
-                       row->currentX = 0;
-                       state->currentY += blockheight;
-               }
-               else
-               {
-                       /* See if we can stuff the block into a higher row */
-                       row = NULL;
-                       for (r = blockheight; r < MAX_SINGLE_LM_SIZE; r++)
-                       {
-                               if ((state->rows[r].rowY >= 0)
-                                 && (state->rows[r].currentX + blockwidth <= totalwidth))
-                               {
-                                       row = &(state->rows[r]);
-                                       break;
-                               }
-                       }
-                       if (row == NULL) return false;
-               }
-       }
-       *outy = row->rowY;
-       *outx = row->currentX;
-       row->currentX += blockwidth;
-
-       return true;
-}
-
-extern cvar_t gl_max_size;
+extern cvar_t gl_max_lightmapsize;
 static void Mod_Q1BSP_LoadFaces(lump_t *l)
 {
        dface_t *in;
@@ -2326,7 +2266,7 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
        lightmaptexture = NULL;
        deluxemaptexture = r_texture_blanknormalmap;
        lightmapnumber = 1;
-       lightmapsize = max(256, gl_max_size.integer);
+       lightmapsize = bound(256, gl_max_lightmapsize.integer, (int)vid.maxtexturesize_2d);
        totallightmapsamples = 0;
 
        totalverts = 0;
@@ -2469,20 +2409,20 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
        // small maps (such as ammo boxes especially) don't need big lightmap
        // textures, so this code tries to guess a good size based on
        // totallightmapsamples (size of the lightmaps lump basically), as well as
-       // trying to max out the gl_max_size if there is a lot of lightmap data to
-       // store
+       // trying to max out the size if there is a lot of lightmap data to store
        // additionally, never choose a lightmapsize that is smaller than the
        // largest surface encountered (as it would fail)
        i = lightmapsize;
-       for (lightmapsize = 64; (lightmapsize < i) && (lightmapsize < gl_max_size.integer) && (totallightmapsamples > lightmapsize*lightmapsize); lightmapsize*=2)
+       for (lightmapsize = 64; (lightmapsize < i) && (lightmapsize < bound(128, gl_max_lightmapsize.integer, (int)vid.maxtexturesize_2d)) && (totallightmapsamples > lightmapsize*lightmapsize); lightmapsize*=2)
                ;
 
        // now that we've decided the lightmap texture size, we can do the rest
        if (cls.state != ca_dedicated)
        {
                int stainmapsize = 0;
-               struct alloc_lm_state allocState;
+               mod_alloclightmap_state_t allocState;
 
+               Mod_AllocLightmap_Init(&allocState, lightmapsize, lightmapsize);
                for (surfacenum = 0, surface = loadmodel->data_surfaces;surfacenum < count;surfacenum++, surface++)
                {
                        int i, iu, iv, lightmapx = 0, lightmapy = 0;
@@ -2497,7 +2437,7 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
                        tsize = (surface->lightmapinfo->extents[1] >> 4) + 1;
                        stainmapsize += ssize * tsize * 3;
 
-                       if (!lightmaptexture || !Mod_Q1BSP_AllocLightmapBlock(&allocState, lightmapsize, lightmapsize, ssize, tsize, &lightmapx, &lightmapy))
+                       if (!lightmaptexture || !Mod_AllocLightmap_Block(&allocState, ssize, tsize, &lightmapx, &lightmapy))
                        {
                                // allocate a texture pool if we need it
                                if (loadmodel->texturepool == NULL)
@@ -2507,8 +2447,8 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
                                if (loadmodel->brushq1.nmaplightdata)
                                        deluxemaptexture = R_LoadTexture2D(loadmodel->texturepool, va("deluxemap%i", lightmapnumber), lightmapsize, lightmapsize, NULL, TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
                                lightmapnumber++;
-                               init_alloc_lm_state (&allocState);
-                               Mod_Q1BSP_AllocLightmapBlock(&allocState, lightmapsize, lightmapsize, ssize, tsize, &lightmapx, &lightmapy);
+                               Mod_AllocLightmap_Reset(&allocState);
+                               Mod_AllocLightmap_Block(&allocState, ssize, tsize, &lightmapx, &lightmapy);
                        }
                        surface->lightmaptexture = lightmaptexture;
                        surface->deluxemaptexture = deluxemaptexture;
@@ -2988,26 +2928,7 @@ typedef struct portal_s
 }
 portal_t;
 
-static portal_t *portalchain;
-
-/*
-===========
-AllocPortal
-===========
-*/
-static portal_t *AllocPortal(void)
-{
-       portal_t *p;
-       p = (portal_t *)Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
-       p->chain = portalchain;
-       portalchain = p;
-       return p;
-}
-
-static void FreePortal(portal_t *p)
-{
-       Mem_Free(p);
-}
+static memexpandablearray_t portalarray;
 
 static void Mod_Q1BSP_RecursiveRecalcNodeBBox(mnode_t *node)
 {
@@ -3030,8 +2951,8 @@ static void Mod_Q1BSP_RecursiveRecalcNodeBBox(mnode_t *node)
 
 static void Mod_Q1BSP_FinalizePortals(void)
 {
-       int i, j, numportals, numpoints;
-       portal_t *p, *pnext;
+       int i, j, numportals, numpoints, portalindex, portalrange = Mem_ExpandableArray_IndexRange(&portalarray);
+       portal_t *p;
        mportal_t *portal;
        mvertex_t *point;
        mleaf_t *leaf, *endleaf;
@@ -3045,11 +2966,13 @@ static void Mod_Q1BSP_FinalizePortals(void)
                VectorSet(leaf->mins,  2000000000,  2000000000,  2000000000);
                VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
        }
-       p = portalchain;
        numportals = 0;
        numpoints = 0;
-       while (p)
+       for (portalindex = 0;portalindex < portalrange;portalindex++)
        {
+               p = (portal_t*)Mem_ExpandableArray_RecordAtIndex(&portalarray, portalindex);
+               if (!p)
+                       continue;
                // note: this check must match the one below or it will usually corrupt memory
                // the nodes[0] != nodes[1] check is because leaf 0 is the shared solid leaf, it can have many portals inside with leaf 0 on both sides
                if (p->numpoints >= 3 && p->nodes[0] != p->nodes[1] && ((mleaf_t *)p->nodes[0])->clusterindex >= 0 && ((mleaf_t *)p->nodes[1])->clusterindex >= 0)
@@ -3057,7 +2980,6 @@ static void Mod_Q1BSP_FinalizePortals(void)
                        numportals += 2;
                        numpoints += p->numpoints * 2;
                }
-               p = p->chain;
        }
        loadmodel->brush.data_portals = (mportal_t *)Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
        loadmodel->brush.num_portals = numportals;
@@ -3069,12 +2991,11 @@ static void Mod_Q1BSP_FinalizePortals(void)
        // process all portals in the global portal chain, while freeing them
        portal = loadmodel->brush.data_portals;
        point = loadmodel->brush.data_portalpoints;
-       p = portalchain;
-       portalchain = NULL;
-       while (p)
+       for (portalindex = 0;portalindex < portalrange;portalindex++)
        {
-               pnext = p->chain;
-
+               p = (portal_t*)Mem_ExpandableArray_RecordAtIndex(&portalarray, portalindex);
+               if (!p)
+                       continue;
                if (p->numpoints >= 3 && p->nodes[0] != p->nodes[1])
                {
                        // note: this check must match the one above or it will usually corrupt memory
@@ -3142,8 +3063,6 @@ static void Mod_Q1BSP_FinalizePortals(void)
                                }
                        }
                }
-               FreePortal(p);
-               p = pnext;
        }
        // now recalculate the node bounding boxes from the leafs
        Mod_Q1BSP_RecursiveRecalcNodeBBox(loadmodel->brush.data_nodes + loadmodel->brushq1.hulls[0].firstclipnode);
@@ -3245,7 +3164,7 @@ static void Mod_Q1BSP_RecursiveNodePortals(mnode_t *node)
 
        // create the new portal by generating a polygon for the node plane,
        // and clipping it by all of the other portals(which came from nodes above this one)
-       nodeportal = AllocPortal();
+       nodeportal = (portal_t *)Mem_ExpandableArray_AllocRecord(&portalarray);
        nodeportal->plane = *plane;
 
        // TODO: calculate node bounding boxes during recursion and calculate a maximum plane size accordingly to improve precision (as most maps do not need 1 billion unit plane polygons)
@@ -3328,7 +3247,7 @@ static void Mod_Q1BSP_RecursiveNodePortals(mnode_t *node)
                }
 
                // the portal is split
-               splitportal = AllocPortal();
+               splitportal = (portal_t *)Mem_ExpandableArray_AllocRecord(&portalarray);
                temp = splitportal->chain;
                *splitportal = *portal;
                splitportal->chain = temp;
@@ -3357,9 +3276,10 @@ static void Mod_Q1BSP_RecursiveNodePortals(mnode_t *node)
 
 static void Mod_Q1BSP_MakePortals(void)
 {
-       portalchain = NULL;
+       Mem_ExpandableArray_NewArray(&portalarray, loadmodel->mempool, sizeof(portal_t), 1020*1024/sizeof(portal_t));
        Mod_Q1BSP_RecursiveNodePortals(loadmodel->brush.data_nodes + loadmodel->brushq1.hulls[0].firstclipnode);
        Mod_Q1BSP_FinalizePortals();
+       Mem_ExpandableArray_FreeArray(&portalarray);
 }
 
 //Returns PVS data for a given point
@@ -3531,6 +3451,7 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
        mod->Draw = R_Q1BSP_Draw;
        mod->DrawDepth = R_Q1BSP_DrawDepth;
        mod->DrawDebug = R_Q1BSP_DrawDebug;
+       mod->DrawPrepass = R_Q1BSP_DrawPrepass;
        mod->GetLightInfo = R_Q1BSP_GetLightInfo;
        mod->CompileShadowMap = R_Q1BSP_CompileShadowMap;
        mod->DrawShadowMap = R_Q1BSP_DrawShadowMap;
@@ -4252,13 +4173,21 @@ static void Mod_Q3BSP_LoadEntities(lump_t *l)
                        if (!COM_ParseToken_Simple(&data, false, false))
                                break; // error
                        strlcpy(value, com_token, sizeof(value));
-                       if (!strcmp("gridsize", key))
+                       if (!strcasecmp("gridsize", key)) // this one is case insensitive to 100% match q3map2
                        {
 #if _MSC_VER >= 1400
 #define sscanf sscanf_s
 #endif
+#if 0
                                if (sscanf(value, "%f %f %f", &v[0], &v[1], &v[2]) == 3 && v[0] != 0 && v[1] != 0 && v[2] != 0)
                                        VectorCopy(v, loadmodel->brushq3.num_lightgrid_cellsize);
+#else
+                               VectorSet(v, 64, 64, 128);
+                               if(sscanf(value, "%f %f %f", &v[0], &v[1], &v[2]) != 3)
+                                       Con_Printf("Mod_Q3BSP_LoadEntities: funny gridsize \"%s\" in %s, interpreting as \"%f %f %f\" to match q3map2's parsing\n", value, loadmodel->name, v[0], v[1], v[2]);
+                               if (v[0] != 0 && v[1] != 0 && v[2] != 0)
+                                       VectorCopy(v, loadmodel->brushq3.num_lightgrid_cellsize);
+#endif
                        }
                        else if (!strcmp("deluxeMaps", key))
                        {
@@ -4694,7 +4623,7 @@ static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump)
                ;
        // i is now 0 for 128, 1 for 256, etc
 
-       for (power = 1;power + i <= mod_q3bsp_lightmapmergepower.integer && (size << power) <= gl_max_texture_size && (1 << (power * 2)) < 4 * (count >> (loadmodel->brushq3.deluxemapping ? 1 : 0)); power++)
+       for (power = 1;power + i <= mod_q3bsp_lightmapmergepower.integer && (size << power) <= (int)vid.maxtexturesize_2d && (1 << (power * 2)) < 4 * (count >> (loadmodel->brushq3.deluxemapping ? 1 : 0)); power++)
                loadmodel->brushq3.num_lightmapmergepower = power;
 
        loadmodel->brushq3.num_lightmapmerge = 1 << loadmodel->brushq3.num_lightmapmergepower;
@@ -5476,7 +5405,10 @@ static void Mod_Q3BSP_LoadLightGrid(lump_t *l)
        if (l->filelen)
        {
                if (l->filelen < count * (int)sizeof(*in))
-                       Host_Error("Mod_Q3BSP_LoadLightGrid: invalid lightgrid lump size %i bytes, should be %i bytes (%ix%ix%i)", l->filelen, (int)(count * sizeof(*in)), loadmodel->brushq3.num_lightgrid_isize[0], loadmodel->brushq3.num_lightgrid_isize[1], loadmodel->brushq3.num_lightgrid_isize[2]);
+               {
+                       Con_Printf("Mod_Q3BSP_LoadLightGrid: invalid lightgrid lump size %i bytes, should be %i bytes (%ix%ix%i)", l->filelen, (int)(count * sizeof(*in)), loadmodel->brushq3.num_lightgrid_isize[0], loadmodel->brushq3.num_lightgrid_isize[1], loadmodel->brushq3.num_lightgrid_isize[2]);
+                       return; // ignore the grid if we cannot understand it
+               }
                if (l->filelen != count * (int)sizeof(*in))
                        Con_Printf("Mod_Q3BSP_LoadLightGrid: Warning: calculated lightgrid size %i bytes does not match lump size %i\n", (int)(count * sizeof(*in)), l->filelen);
                out = (q3dlightgrid_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
@@ -5656,7 +5588,7 @@ static qboolean Mod_Q3BSP_TraceLineOfSight(struct model_s *model, const vec3_t s
        if (model->brush.submodel || mod_q3bsp_tracelineofsight_brushes.integer)
        {
                trace_t trace;
-               model->TraceLine(model, 0, &trace, start, end, SUPERCONTENTS_VISBLOCKERMASK);
+               model->TraceLine(model, NULL, NULL, &trace, start, end, SUPERCONTENTS_VISBLOCKERMASK);
                return trace.fraction == 1;
        }
        else
@@ -5860,7 +5792,7 @@ static void Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace_t *trace, dp_model_t *mo
 
 static int markframe = 0;
 
-static void Mod_Q3BSP_TracePoint(dp_model_t *model, int frame, trace_t *trace, const vec3_t start, int hitsupercontentsmask)
+static void Mod_Q3BSP_TracePoint(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, int hitsupercontentsmask)
 {
        int i;
        q3mbrush_t *brush;
@@ -5878,7 +5810,7 @@ static void Mod_Q3BSP_TracePoint(dp_model_t *model, int frame, trace_t *trace, c
                Mod_Q3BSP_TracePoint_RecursiveBSPNode(trace, model, model->brush.data_nodes, start, ++markframe);
 }
 
-static void Mod_Q3BSP_TraceLine(dp_model_t *model, int frame, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask)
+static void Mod_Q3BSP_TraceLine(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask)
 {
        int i;
        float segmentmins[3], segmentmaxs[3];
@@ -5887,7 +5819,7 @@ static void Mod_Q3BSP_TraceLine(dp_model_t *model, int frame, trace_t *trace, co
 
        if (VectorCompare(start, end))
        {
-               Mod_Q3BSP_TracePoint(model, frame, trace, start, hitsupercontentsmask);
+               Mod_Q3BSP_TracePoint(model, frameblend, skeleton, trace, start, hitsupercontentsmask);
                return;
        }
 
@@ -5915,7 +5847,7 @@ static void Mod_Q3BSP_TraceLine(dp_model_t *model, int frame, trace_t *trace, co
                Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, model, model->brush.data_nodes, start, end, 0, 1, start, end, ++markframe, segmentmins, segmentmaxs);
 }
 
-static void Mod_Q3BSP_TraceBox(dp_model_t *model, int frame, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask)
+static void Mod_Q3BSP_TraceBox(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask)
 {
        int i;
        float segmentmins[3], segmentmaxs[3];
@@ -5930,10 +5862,10 @@ static void Mod_Q3BSP_TraceBox(dp_model_t *model, int frame, trace_t *trace, con
                VectorAdd(start, boxmins, shiftstart);
                VectorAdd(end, boxmins, shiftend);
                if (VectorCompare(start, end))
-                       Mod_Q3BSP_TracePoint(model, frame, trace, shiftstart, hitsupercontentsmask);
+                       Mod_Q3BSP_TracePoint(model, frameblend, skeleton, trace, shiftstart, hitsupercontentsmask);
                else
                {
-                       Mod_Q3BSP_TraceLine(model, frame, trace, shiftstart, shiftend, hitsupercontentsmask);
+                       Mod_Q3BSP_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask);
                        VectorSubtract(trace->endpos, boxmins, trace->endpos);
                }
                return;
@@ -6118,6 +6050,7 @@ void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
        mod->Draw = R_Q1BSP_Draw;
        mod->DrawDepth = R_Q1BSP_DrawDepth;
        mod->DrawDebug = R_Q1BSP_DrawDebug;
+       mod->DrawPrepass = R_Q1BSP_DrawPrepass;
        mod->GetLightInfo = R_Q1BSP_GetLightInfo;
        mod->CompileShadowMap = R_Q1BSP_CompileShadowMap;
        mod->DrawShadowMap = R_Q1BSP_DrawShadowMap;
@@ -6216,6 +6149,9 @@ void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->brush.num_leafs = 0;
        Mod_Q3BSP_RecursiveFindNumLeafs(loadmodel->brush.data_nodes);
 
+       if (loadmodel->brush.numsubmodels)
+               loadmodel->brush.submodels = (dp_model_t **)Mem_Alloc(loadmodel->mempool, loadmodel->brush.numsubmodels * sizeof(dp_model_t *));
+
        mod = loadmodel;
        for (i = 0;i < loadmodel->brush.numsubmodels;i++)
        {
@@ -6243,6 +6179,8 @@ void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
                        mod->brush.AmbientSoundLevelsForPoint = NULL;
                }
                mod->brush.submodel = i;
+               if (loadmodel->brush.submodels)
+                       loadmodel->brush.submodels[i] = mod;
 
                // make the model surface list (used by shadowing/lighting)
                mod->firstmodelsurface = mod->brushq3.data_models[i].firstface;
@@ -6803,6 +6741,7 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->Draw = R_Q1BSP_Draw;
        loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
        loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+       loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
        loadmodel->GetLightInfo = R_Q1BSP_GetLightInfo;
        loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
        loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;