]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_brush.c
cleaned up and fixed collisions with brush models (example: you can now ramp jump...
[xonotic/darkplaces.git] / model_brush.c
index 6788f8a15a17203f6a7376e1799161002e1683e6..3301a7b44deeb2097d4420c4064ee9b66ac4249a 100644 (file)
@@ -20,14 +20,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 
-byte mod_novis[(MAX_MAP_LEAFS + 7)/ 8];
+qbyte mod_novis[(MAX_MAP_LEAFS + 7)/ 8];
 
 cvar_t r_subdivide_size = {CVAR_SAVE, "r_subdivide_size", "128"};
 cvar_t halflifebsp = {0, "halflifebsp", "0"};
 cvar_t r_novis = {0, "r_novis", "0"};
 cvar_t r_miplightmaps = {CVAR_SAVE, "r_miplightmaps", "0"};
 cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1"};
-cvar_t r_vertexsurfacesthreshold = {CVAR_SAVE, "r_vertexsurfacesthreshold", "48"};
+cvar_t r_vertexsurfacesthreshold = {CVAR_SAVE, "r_vertexsurfacesthreshold", "0"};
 
 /*
 ===============
@@ -118,12 +118,12 @@ mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
 Mod_DecompressVis
 ===================
 */
-static byte *Mod_DecompressVis (byte *in, model_t *model)
+static qbyte *Mod_DecompressVis (qbyte *in, model_t *model)
 {
-       static byte     decompressed[MAX_MAP_LEAFS/8];
-       int             c;
-       byte    *out;
-       int             row;
+       static qbyte decompressed[MAX_MAP_LEAFS/8];
+       int c;
+       qbyte *out;
+       int row;
 
        row = (model->numleafs+7)>>3;
        out = decompressed;
@@ -160,7 +160,7 @@ static byte *Mod_DecompressVis (byte *in, model_t *model)
        return decompressed;
 }
 
-byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
+qbyte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
 {
        if (r_novis.integer || leaf == model->leafs || leaf->compressed_vis == NULL)
                return mod_novis;
@@ -169,8 +169,8 @@ byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
 
 void Mod_SetupNoTexture(void)
 {
-       int             x, y;
-       byte    pix[16][16][4];
+       int x, y;
+       qbyte pix[16][16][4];
 
        for (y = 0;y < 16;y++)
        {
@@ -212,7 +212,7 @@ static void Mod_LoadTextures (lump_t *l)
        miptex_t                *dmiptex;
        texture_t               *tx, *tx2, *anims[10], *altanims[10];
        dmiptexlump_t   *m;
-       byte                    *data, *mtdata, *data2;
+       qbyte                   *data, *mtdata, *data2;
        char                    name[256];
 
        Mod_SetupNoTexture();
@@ -237,7 +237,7 @@ static void Mod_LoadTextures (lump_t *l)
                dofs[i] = LittleLong(dofs[i]);
                if (dofs[i] == -1)
                        continue;
-               dmiptex = (miptex_t *)((byte *)m + dofs[i]);
+               dmiptex = (miptex_t *)((qbyte *)m + dofs[i]);
                mtwidth = LittleLong (dmiptex->width);
                mtheight = LittleLong (dmiptex->height);
                mtdata = NULL;
@@ -247,7 +247,7 @@ static void Mod_LoadTextures (lump_t *l)
                        // texture included
                        if (j < 40 || j + mtwidth * mtheight > l->filelen)
                                Host_Error ("Texture %s is corrupt or incomplete\n", dmiptex->name);
-                       mtdata = (byte *)dmiptex + j;
+                       mtdata = (qbyte *)dmiptex + j;
                }
 
                if ((mtwidth & 15) || (mtheight & 15))
@@ -486,8 +486,7 @@ Mod_LoadLighting
 static void Mod_LoadLighting (lump_t *l)
 {
        int i;
-       byte *in, *out, *data;
-       byte d;
+       qbyte *in, *out, *data, d;
        char litfilename[1024];
        loadmodel->lightdata = NULL;
        if (loadmodel->ishlbsp) // LordHavoc: load the colored lighting data straight
@@ -501,7 +500,7 @@ static void Mod_LoadLighting (lump_t *l)
                strcpy(litfilename, loadmodel->name);
                COM_StripExtension(litfilename, litfilename);
                strcat(litfilename, ".lit");
-               data = (byte*) COM_LoadFile (litfilename, false);
+               data = (qbyte*) COM_LoadFile (litfilename, false);
                if (data)
                {
                        if (loadsize > 8 && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
@@ -976,7 +975,7 @@ void Mod_GenerateWarpMesh (msurface_t *surf)
        if (mesh->numtriangles < 1)
                Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
        mesh->index = Mem_Alloc(loadmodel->mempool, mesh->numtriangles * sizeof(int[3]) + mesh->numverts * sizeof(surfvertex_t));
-       mesh->vertex = (surfvertex_t *)((long) mesh->index + mesh->numtriangles * sizeof(int[3]));
+       mesh->vertex = (surfvertex_t *)((qbyte *) mesh->index + mesh->numtriangles * sizeof(int[3]));
        memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
 
        for (i = 0;i < mesh->numtriangles;i++)
@@ -1014,7 +1013,7 @@ void Mod_GenerateVertexLitMesh (msurface_t *surf)
        mesh->numverts = surf->poly_numverts;
        mesh->numtriangles = surf->poly_numverts - 2;
        mesh->index = Mem_Alloc(loadmodel->mempool, mesh->numtriangles * sizeof(int[3]) + mesh->numverts * sizeof(surfvertex_t));
-       mesh->vertex = (surfvertex_t *)((long) mesh->index + mesh->numtriangles * sizeof(int[3]));
+       mesh->vertex = (surfvertex_t *)((qbyte *) mesh->index + mesh->numtriangles * sizeof(int[3]));
        memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
 
        index = mesh->index;
@@ -1064,16 +1063,16 @@ void Mod_GenerateLightmappedMesh (msurface_t *surf)
        if (r_miplightmaps.integer)
        {
                surf->lightmaptexturestride = (surf->extents[0]>>4)+1;
-               surf->lightmaptexture = R_ProceduralTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP/* | TEXF_PRECACHE*/, NULL, NULL, 0);
+               surf->lightmaptexture = R_ProceduralTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP | TEXF_PRECACHE, NULL, NULL, 0);
        }
        else
        {
                surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
-               surf->lightmaptexture = R_ProceduralTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT/* | TEXF_PRECACHE*/, NULL, NULL, 0);
+               surf->lightmaptexture = R_ProceduralTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_PRECACHE, NULL, NULL, 0);
        }
 //     surf->lightmaptexture = R_LoadTexture(loadmodel->texturepool, va("lightmap%08x", lightmapnum), surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_PRECACHE);
 //     surf->lightmaptexture = R_LoadTexture(loadmodel->texturepool, va("lightmap%08x", lightmapnum), surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_PRECACHE);
-       R_GetFragmentLocation(surf->lightmaptexture, NULL, NULL, &xbase, &ybase, &xscale, &yscale);
+       R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &xbase, &ybase, &xscale, &yscale);
        xscale = (xscale - xbase) * 16.0 / ((surf->extents[0] & ~15) + 16);
        yscale = (yscale - ybase) * 16.0 / ((surf->extents[1] & ~15) + 16);
 
@@ -1081,7 +1080,7 @@ void Mod_GenerateLightmappedMesh (msurface_t *surf)
        mesh->numverts = surf->poly_numverts;
        mesh->numtriangles = surf->poly_numverts - 2;
        mesh->index = Mem_Alloc(loadmodel->mempool, mesh->numtriangles * sizeof(int[3]) + mesh->numverts * sizeof(surfvertex_t));
-       mesh->vertex = (surfvertex_t *)((long) mesh->index + mesh->numtriangles * sizeof(int[3]));
+       mesh->vertex = (surfvertex_t *)((qbyte *) mesh->index + mesh->numtriangles * sizeof(int[3]));
        memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
 
        index = mesh->index;
@@ -1132,7 +1131,7 @@ void Mod_GenerateVertexMesh (msurface_t *surf)
        mesh->numverts = surf->poly_numverts;
        mesh->numtriangles = surf->poly_numverts - 2;
        mesh->index = Mem_Alloc(loadmodel->mempool, mesh->numtriangles * sizeof(int[3]) + mesh->numverts * sizeof(surfvertex_t));
-       mesh->vertex = (surfvertex_t *)((long) mesh->index + mesh->numtriangles * sizeof(int[3]));
+       mesh->vertex = (surfvertex_t *)((qbyte *) mesh->index + mesh->numtriangles * sizeof(int[3]));
        memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
 
        index = mesh->index;
@@ -1182,8 +1181,7 @@ static void Mod_LoadFaces (lump_t *l)
 {
        dface_t         *in;
        msurface_t      *out;
-       int                     i, count, surfnum;
-       int                     planenum, side;
+       int                     i, count, surfnum, planenum, side, ssize, tsize;
 
        in = (void *)(mod_base + l->fileofs);
        if (l->filelen % sizeof(*in))
@@ -1217,13 +1215,12 @@ static void Mod_LoadFaces (lump_t *l)
                out->cached_dlight = true;
                out->cached_ambient = -1000;
                out->cached_lightscalebit = -1000;
-               out->cached_light[0] = -1000;
-               out->cached_light[1] = -1000;
-               out->cached_light[2] = -1000;
-               out->cached_light[3] = -1000;
 
                CalcSurfaceExtents (out);
 
+               ssize = (out->extents[0] >> 4) + 1;
+               tsize = (out->extents[1] >> 4) + 1;
+
                // lighting info
                for (i = 0;i < MAXLIGHTMAPS;i++)
                        out->styles[i] = in->styles[i];
@@ -1266,6 +1263,7 @@ static void Mod_LoadFaces (lump_t *l)
                {
                        // qbsp couldn't find the texture for this surface, but it was either turb or sky...  assume turb
                        out->shader = &Cshader_water;
+                       out->shader = &Cshader_water;
                        out->samples = NULL;
                        Mod_GenerateWarpMesh (out);
                }
@@ -1276,15 +1274,22 @@ static void Mod_LoadFaces (lump_t *l)
                        out->samples = NULL;
                        Mod_GenerateVertexMesh(out);
                }
-               else if (out->extents[0] < r_vertexsurfacesthreshold.integer && out->extents[1] < r_vertexsurfacesthreshold.integer)
-               {
-                       out->shader = &Cshader_wall_vertex;
-                       Mod_GenerateVertexLitMesh(out);
-               }
                else
                {
-                       out->shader = &Cshader_wall_lightmap;
-                       Mod_GenerateLightmappedMesh(out);
+                       // stainmap for permanent marks on walls
+                       out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
+                       // clear to white
+                       memset(out->stainsamples, 255, ssize * tsize * 3);
+                       if (out->extents[0] < r_vertexsurfacesthreshold.integer && out->extents[1] < r_vertexsurfacesthreshold.integer)
+                       {
+                               out->shader = &Cshader_wall_vertex;
+                               Mod_GenerateVertexLitMesh(out);
+                       }
+                       else
+                       {
+                               out->shader = &Cshader_wall_lightmap;
+                               Mod_GenerateLightmappedMesh(out);
+                       }
                }
        }
 }
@@ -1297,7 +1302,7 @@ static int Mod_SurfaceQSortCompare(const void *voida, const void *voidb)
        a = *((const msurface_t **)voida);
        b = *((const msurface_t **)voidb);
        if (a->shader != b->shader)
-               return (long) a->shader - (long) b->shader;
+               return (qbyte *) a->shader - (qbyte *) b->shader;
        if (a->texinfo->texture != b->texinfo->texture);
                return a->texinfo->texture - b->texinfo->texture;
        return 0;
@@ -1465,6 +1470,7 @@ static void Mod_LoadClipnodes (lump_t *l)
                hull->clip_maxs[0] = 16;
                hull->clip_maxs[1] = 16;
                hull->clip_maxs[2] = 36;
+               VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
 
                hull = &loadmodel->hulls[2];
                hull->clipnodes = out;
@@ -1477,6 +1483,7 @@ static void Mod_LoadClipnodes (lump_t *l)
                hull->clip_maxs[0] = 32;
                hull->clip_maxs[1] = 32;
                hull->clip_maxs[2] = 32;
+               VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
 
                hull = &loadmodel->hulls[3];
                hull->clipnodes = out;
@@ -1489,6 +1496,7 @@ static void Mod_LoadClipnodes (lump_t *l)
                hull->clip_maxs[0] = 16;
                hull->clip_maxs[1] = 16;
                hull->clip_maxs[2] = 18;
+               VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
        }
        else
        {
@@ -1503,6 +1511,7 @@ static void Mod_LoadClipnodes (lump_t *l)
                hull->clip_maxs[0] = 16;
                hull->clip_maxs[1] = 16;
                hull->clip_maxs[2] = 32;
+               VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
 
                hull = &loadmodel->hulls[2];
                hull->clipnodes = out;
@@ -1515,6 +1524,7 @@ static void Mod_LoadClipnodes (lump_t *l)
                hull->clip_maxs[0] = 32;
                hull->clip_maxs[1] = 32;
                hull->clip_maxs[2] = 64;
+               VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
        }
 
        for (i=0 ; i<count ; i++, out++, in++)
@@ -1641,6 +1651,7 @@ static void Mod_LoadPlanes (lump_t *l)
 typedef struct
 {
        int numpoints;
+       int padding;
        double points[8][3]; // variable sized
 }
 winding_t;
@@ -1656,7 +1667,7 @@ static winding_t *NewWinding (int points)
        int size;
 
        if (points > MAX_POINTS_ON_WINDING)
-               Host_Error("NewWinding: too many points\n");
+               Sys_Error("NewWinding: too many points\n");
 
        size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
        w = Mem_Alloc(loadmodel->mempool, size);
@@ -1730,9 +1741,6 @@ static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
        winding_t       *neww;
        int             maxpts;
 
-       // debugging
-       Mem_CheckSentinels(in);
-
        counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
 
        // determine sides for each point
@@ -1762,12 +1770,15 @@ static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
                return in;
 
        maxpts = in->numpoints+4;       // can't use counts[0]+2 because of fp grouping errors
+       if (maxpts > MAX_POINTS_ON_WINDING)
+               Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
+
        neww = NewWinding (maxpts);
 
        for (i = 0;i < in->numpoints;i++)
        {
                if (neww->numpoints >= maxpts)
-                       Host_Error ("ClipWinding: points exceeded estimate");
+                       Sys_Error ("ClipWinding: points exceeded estimate");
 
                p1 = in->points[i];
 
@@ -1809,7 +1820,7 @@ static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
        FreeWinding (in);
 
        // debugging
-       Mem_CheckSentinels(neww);
+       //Mem_CheckSentinels(neww);
 
        return neww;
 }
@@ -1837,9 +1848,6 @@ static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, wi
        winding_t       *f, *b;
        int             maxpts;
 
-       // debugging
-       Mem_CheckSentinels(in);
-
        counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
 
        // determine sides for each point
@@ -1871,13 +1879,16 @@ static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, wi
 
        maxpts = in->numpoints+4;       // can't use counts[0]+2 because of fp grouping errors
 
+       if (maxpts > MAX_POINTS_ON_WINDING)
+               Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
+
        *front = f = NewWinding (maxpts);
        *back = b = NewWinding (maxpts);
 
        for (i = 0;i < in->numpoints;i++)
        {
                if (f->numpoints >= maxpts || b->numpoints >= maxpts)
-                       Host_Error ("DivideWinding: points exceeded estimate");
+                       Sys_Error ("DivideWinding: points exceeded estimate");
 
                p1 = in->points[i];
 
@@ -1925,8 +1936,8 @@ static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, wi
        }
 
        // debugging
-       Mem_CheckSentinels(front);
-       Mem_CheckSentinels(back);
+       //Mem_CheckSentinels(f);
+       //Mem_CheckSentinels(b);
 }
 
 typedef struct portal_s
@@ -1987,13 +1998,15 @@ static void Mod_FinalizePortals(void)
        mleaf_t *leaf, *endleaf;
        winding_t *w;
 
+       //Mem_CheckSentinelsGlobal();
+
        // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
        leaf = loadmodel->leafs;
        endleaf = leaf + loadmodel->numleafs;
        for (;leaf < endleaf;leaf++)
        {
-               VectorSet( 2000000000,  2000000000,  2000000000, leaf->mins);
-               VectorSet(-2000000000, -2000000000, -2000000000, leaf->maxs);
+               VectorSet(leaf->mins,  2000000000,  2000000000,  2000000000);
+               VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
        }
        p = portalchain;
        while(p)
@@ -2020,6 +2033,8 @@ static void Mod_FinalizePortals(void)
 
        Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
 
+       //Mem_CheckSentinelsGlobal();
+
        // tally up portal and point counts
        p = portalchain;
        numportals = 0;
@@ -2039,7 +2054,7 @@ static void Mod_FinalizePortals(void)
        }
        loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
        loadmodel->numportals = numportals;
-       loadmodel->portalpoints = (void *) ((long) loadmodel->portals + numportals * sizeof(mportal_t));
+       loadmodel->portalpoints = (void *) ((qbyte *) loadmodel->portals + numportals * sizeof(mportal_t));
        loadmodel->numportalpoints = numpoints;
        // clear all leaf portal chains
        for (i = 0;i < loadmodel->numleafs;i++)
@@ -2110,6 +2125,8 @@ static void Mod_FinalizePortals(void)
                FreePortal(p);
                p = pnext;
        }
+
+       //Mem_CheckSentinelsGlobal();
 }
 
 /*
@@ -2212,7 +2229,7 @@ static void Mod_RecursiveNodePortals (mnode_t *node)
        nodeportal->plane = *node->plane;
 
        nodeportalwinding = BaseWindingForPlane (node->plane);
-       Mem_CheckSentinels(nodeportalwinding);
+       //Mem_CheckSentinels(nodeportalwinding);
        side = 0;       // shut up compiler warning
        for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
        {
@@ -2368,6 +2385,7 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer)
        dheader_t       *header;
        dmodel_t        *bm;
        mempool_t       *mainmempool;
+       char            *loadname;
 
        mod->type = mod_brush;
 
@@ -2381,7 +2399,7 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer)
                Cvar_SetValue("halflifebsp", mod->ishlbsp);
 
 // swap all the lumps
-       mod_base = (byte *)header;
+       mod_base = (qbyte *)header;
 
        for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
                ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
@@ -2433,6 +2451,7 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer)
        mod->numframes = 2;             // regular and alternate animation
 
        mainmempool = mod->mempool;
+       loadname = mod->name;
 
 //
 // set up the submodels (FIXME: this is confusing)
@@ -2496,6 +2515,18 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer)
                mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
                mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
 //             mod->modelradius = modelradius;
+               // LordHavoc: check for empty submodels (lacrima.bsp has such a glitch)
+               if (mod->normalmins[0] > mod->normalmaxs[0] || mod->normalmins[1] > mod->normalmaxs[1] || mod->normalmins[2] > mod->normalmaxs[2])
+               {
+                       Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
+                       VectorClear(mod->normalmins);
+                       VectorClear(mod->normalmaxs);
+                       VectorClear(mod->yawmins);
+                       VectorClear(mod->yawmaxs);
+                       VectorClear(mod->rotatedmins);
+                       VectorClear(mod->rotatedmaxs);
+                       //mod->modelradius = 0;
+               }
 
 //             VectorCopy (bm->maxs, mod->maxs);
 //             VectorCopy (bm->mins, mod->mins);