]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_brush.c
made darkplaces able to compile as C++ again, and fixed all conversion warnings when...
[xonotic/darkplaces.git] / model_brush.c
index a4092e71acbf7cfc0a8891559ffa7c69ae2f1ccb..440c412922382a0b44b476e271b8fc6cd0a36db2 100644 (file)
@@ -430,10 +430,10 @@ static void Mod_Q1BSP_FindNonSolidLocation_r_Leaf(findnonsolidlocationinfo_t *in
                {
                        for (k = 0;k < surface->num_triangles;k++)
                        {
-                               tri = (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle) + k * 3;
-                               VectorCopy((surface->groupmesh->data_vertex3f + tri[0] * 3), vert[0]);
-                               VectorCopy((surface->groupmesh->data_vertex3f + tri[1] * 3), vert[1]);
-                               VectorCopy((surface->groupmesh->data_vertex3f + tri[2] * 3), vert[2]);
+                               tri = (info->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle) + k * 3;
+                               VectorCopy((info->model->surfmesh.data_vertex3f + tri[0] * 3), vert[0]);
+                               VectorCopy((info->model->surfmesh.data_vertex3f + tri[1] * 3), vert[1]);
+                               VectorCopy((info->model->surfmesh.data_vertex3f + tri[2] * 3), vert[2]);
                                VectorSubtract(vert[1], vert[0], edge[0]);
                                VectorSubtract(vert[2], vert[1], edge[1]);
                                CrossProduct(edge[1], edge[0], facenormal);
@@ -971,9 +971,9 @@ void Collision_ClipTrace_Box(trace_t *trace, const vec3_t cmins, const vec3_t cm
 
 static int Mod_Q1BSP_LightPoint_RecursiveBSPNode(model_t *model, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const mnode_t *node, float x, float y, float startz, float endz)
 {
-       int side, distz = endz - startz;
+       int side;
        float front, back;
-       float mid;
+       float mid, distz = endz - startz;
 
 loc0:
        if (!node->plane)
@@ -1517,9 +1517,9 @@ static void Mod_Q1BSP_LoadLighting(lump_t *l)
 {
        int i;
        unsigned char *in, *out, *data, d;
-       char litfilename[1024];
+       char litfilename[MAX_QPATH];
+       char dlitfilename[MAX_QPATH];
        fs_offset_t filesize;
-       loadmodel->brushq1.lightdata = NULL;
        if (loadmodel->brush.ishlbsp) // LordHavoc: load the colored lighting data straight
        {
                loadmodel->brushq1.lightdata = (unsigned char *)Mem_Alloc(loadmodel->mempool, l->filelen);
@@ -1536,7 +1536,9 @@ static void Mod_Q1BSP_LoadLighting(lump_t *l)
                // LordHavoc: hope is not lost yet, check for a .lit file to load
                strlcpy (litfilename, loadmodel->name, sizeof (litfilename));
                FS_StripExtension (litfilename, litfilename, sizeof (litfilename));
+               strlcpy (dlitfilename, litfilename, sizeof (dlitfilename));
                strlcat (litfilename, ".lit", sizeof (litfilename));
+               strlcat (dlitfilename, ".dlit", sizeof (dlitfilename));
                data = (unsigned char*) FS_LoadFile(litfilename, tempmempool, false, &filesize);
                if (data)
                {
@@ -1549,30 +1551,45 @@ static void Mod_Q1BSP_LoadLighting(lump_t *l)
                                        loadmodel->brushq1.lightdata = (unsigned char *)Mem_Alloc(loadmodel->mempool, filesize - 8);
                                        memcpy(loadmodel->brushq1.lightdata, data + 8, filesize - 8);
                                        Mem_Free(data);
+                                       data = (unsigned char*) FS_LoadFile(dlitfilename, tempmempool, false, &filesize);
+                                       if (data)
+                                       {
+                                               if (filesize == (fs_offset_t)(8 + l->filelen * 3) && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
+                                               {
+                                                       i = LittleLong(((int *)data)[1]);
+                                                       if (i == 1)
+                                                       {
+                                                               Con_DPrintf("loaded %s\n", dlitfilename);
+                                                               loadmodel->brushq1.nmaplightdata = (unsigned char *)Mem_Alloc(loadmodel->mempool, filesize - 8);
+                                                               memcpy(loadmodel->brushq1.nmaplightdata, data + 8, filesize - 8);
+                                                               loadmodel->brushq3.deluxemapping_modelspace = false;
+                                                               loadmodel->brushq3.deluxemapping = true;
+                                                       }
+                                               }
+                                               Mem_Free(data);
+                                               data = NULL;
+                                       }
                                        return;
                                }
                                else
-                               {
                                        Con_Printf("Unknown .lit file version (%d)\n", i);
-                                       Mem_Free(data);
-                               }
                        }
+                       else if (filesize == 8)
+                               Con_Print("Empty .lit file, ignoring\n");
                        else
+                               Con_Printf("Corrupt .lit file (file size %i bytes, should be %i bytes), ignoring\n", filesize, 8 + l->filelen * 3);
+                       if (data)
                        {
-                               if (filesize == 8)
-                                       Con_Print("Empty .lit file, ignoring\n");
-                               else
-                                       Con_Printf("Corrupt .lit file (file size %i bytes, should be %i bytes), ignoring\n", filesize, 8 + l->filelen * 3);
                                Mem_Free(data);
+                               data = NULL;
                        }
                }
                // LordHavoc: oh well, expand the white lighting data
                if (!l->filelen)
                        return;
                loadmodel->brushq1.lightdata = (unsigned char *)Mem_Alloc(loadmodel->mempool, l->filelen*3);
-               in = loadmodel->brushq1.lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
+               in = mod_base + l->fileofs;
                out = loadmodel->brushq1.lightdata;
-               memcpy(in, mod_base + l->fileofs, l->filelen);
                for (i = 0;i < l->filelen;i++)
                {
                        d = *in++;
@@ -1953,7 +1970,7 @@ static void Mod_Q1BSP_GenerateWarpMesh(msurface_t *surface)
 
        subdivpolytriangles = 0;
        subdivpolyverts = 0;
-       SubdividePolygon(surface->num_vertices, (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex));
+       SubdividePolygon(surface->num_vertices, (surface->mesh->data_vertex3f + 3 * surface->num_firstvertex));
        if (subdivpolytriangles < 1)
                Host_Error("Mod_Q1BSP_GenerateWarpMesh: no triangles?");
 
@@ -2015,7 +2032,7 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
        int i, j, count, surfacenum, planenum, smax, tmax, ssize, tsize, firstedge, numedges, totalverts, totaltris, lightmapnumber;
        float texmins[2], texmaxs[2], val, lightmaptexcoordscale;
 #define LIGHTMAPSIZE 256
-       rtexture_t *lightmaptexture;
+       rtexture_t *lightmaptexture, *deluxemaptexture;
        int lightmap_lineused[LIGHTMAPSIZE];
 
        in = (dface_t *)(mod_base + l->fileofs);
@@ -2036,13 +2053,10 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
                totaltris += numedges - 2;
        }
 
-       // TODO: split up into multiple meshes as needed to avoid exceeding 65536
-       // vertex limit
-       loadmodel->nummeshes = 1;
-       loadmodel->meshlist = (surfmesh_t **)Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t *));
-       loadmodel->meshlist[0] = Mod_AllocSurfMesh(loadmodel->mempool, totalverts, totaltris, true, false, false);
+       Mod_AllocSurfMesh(loadmodel->mempool, totalverts, totaltris, true, false, false);
 
        lightmaptexture = NULL;
+       deluxemaptexture = r_texture_blanknormalmap;
        lightmapnumber = 1;
        lightmaptexcoordscale = 1.0f / (float)LIGHTMAPSIZE;
 
@@ -2072,7 +2086,6 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
                //      surface->flags |= SURF_PLANEBACK;
                //surface->plane = loadmodel->brush.data_planes + planenum;
 
-               surface->groupmesh = loadmodel->meshlist[0];
                surface->num_firstvertex = totalverts;
                surface->num_vertices = numedges;
                surface->num_firsttriangle = totaltris;
@@ -2086,37 +2099,37 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
                        int lindex = loadmodel->brushq1.surfedges[firstedge + i];
                        float s, t;
                        if (lindex > 0)
-                               VectorCopy(loadmodel->brushq1.vertexes[loadmodel->brushq1.edges[lindex].v[0]].position, (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + i * 3);
+                               VectorCopy(loadmodel->brushq1.vertexes[loadmodel->brushq1.edges[lindex].v[0]].position, (loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3);
                        else
-                               VectorCopy(loadmodel->brushq1.vertexes[loadmodel->brushq1.edges[-lindex].v[1]].position, (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + i * 3);
-                       s = DotProduct(((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + i * 3), surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3];
-                       t = DotProduct(((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + i * 3), surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3];
-                       (surface->groupmesh->data_texcoordtexture2f + 2 * surface->num_firstvertex)[i * 2 + 0] = s / surface->texture->width;
-                       (surface->groupmesh->data_texcoordtexture2f + 2 * surface->num_firstvertex)[i * 2 + 1] = t / surface->texture->height;
-                       (surface->groupmesh->data_texcoordlightmap2f + 2 * surface->num_firstvertex)[i * 2 + 0] = 0;
-                       (surface->groupmesh->data_texcoordlightmap2f + 2 * surface->num_firstvertex)[i * 2 + 1] = 0;
-                       (surface->groupmesh->data_lightmapoffsets + surface->num_firstvertex)[i] = 0;
+                               VectorCopy(loadmodel->brushq1.vertexes[loadmodel->brushq1.edges[-lindex].v[1]].position, (loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3);
+                       s = DotProduct(((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3), surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3];
+                       t = DotProduct(((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3), surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3];
+                       (loadmodel->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[i * 2 + 0] = s / surface->texture->width;
+                       (loadmodel->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[i * 2 + 1] = t / surface->texture->height;
+                       (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[i * 2 + 0] = 0;
+                       (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[i * 2 + 1] = 0;
+                       (loadmodel->surfmesh.data_lightmapoffsets + surface->num_firstvertex)[i] = 0;
                }
 
                for (i = 0;i < surface->num_triangles;i++)
                {
-                       (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle)[i * 3 + 0] = 0 + surface->num_firstvertex;
-                       (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle)[i * 3 + 1] = i + 1 + surface->num_firstvertex;
-                       (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle)[i * 3 + 2] = i + 2 + surface->num_firstvertex;
+                       (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle)[i * 3 + 0] = 0 + surface->num_firstvertex;
+                       (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle)[i * 3 + 1] = i + 1 + surface->num_firstvertex;
+                       (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle)[i * 3 + 2] = i + 2 + surface->num_firstvertex;
                }
 
                // compile additional data about the surface geometry
-               Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, surface->groupmesh->data_vertex3f, surface->groupmesh->data_texcoordtexture2f, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle), surface->groupmesh->data_svector3f, surface->groupmesh->data_tvector3f, surface->groupmesh->data_normal3f, true);
-               BoxFromPoints(surface->mins, surface->maxs, surface->num_vertices, (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex));
+               Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle), loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, loadmodel->surfmesh.data_normal3f, true);
+               BoxFromPoints(surface->mins, surface->maxs, surface->num_vertices, (loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex));
 
                // generate surface extents information
-               texmins[0] = texmaxs[0] = DotProduct((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex), surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3];
-               texmins[1] = texmaxs[1] = DotProduct((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex), surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3];
+               texmins[0] = texmaxs[0] = DotProduct((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex), surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3];
+               texmins[1] = texmaxs[1] = DotProduct((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex), surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3];
                for (i = 1;i < surface->num_vertices;i++)
                {
                        for (j = 0;j < 2;j++)
                        {
-                               val = DotProduct((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + i * 3, surface->lightmapinfo->texinfo->vecs[j]) + surface->lightmapinfo->texinfo->vecs[j][3];
+                               val = DotProduct((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3, surface->lightmapinfo->texinfo->vecs[j]) + surface->lightmapinfo->texinfo->vecs[j][3];
                                texmins[j] = min(texmins[j], val);
                                texmaxs[j] = max(texmaxs[j], val);
                        }
@@ -2152,7 +2165,11 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
                else if (loadmodel->brush.ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
                        surface->lightmapinfo->samples = loadmodel->brushq1.lightdata + i;
                else // LordHavoc: white lighting (bsp version 29)
+               {
                        surface->lightmapinfo->samples = loadmodel->brushq1.lightdata + (i * 3);
+                       if (loadmodel->brushq1.nmaplightdata)
+                               surface->lightmapinfo->nmapsamples = loadmodel->brushq1.nmaplightdata + (i * 3);
+               }
 
                // check if we should apply a lightmap to this
                if (!(surface->lightmapinfo->texinfo->flags & TEX_SPECIAL) || surface->lightmapinfo->samples)
@@ -2173,13 +2190,16 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
                        if (!lightmaptexture || !Mod_Q1BSP_AllocLightmapBlock(lightmap_lineused, LIGHTMAPSIZE, LIGHTMAPSIZE, ssize, tsize, &lightmapx, &lightmapy))
                        {
                                // could not find room, make a new lightmap
-                               lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%i", lightmapnumber++), LIGHTMAPSIZE, LIGHTMAPSIZE, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+                               lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%i", lightmapnumber), LIGHTMAPSIZE, LIGHTMAPSIZE, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+                               if (loadmodel->brushq1.nmaplightdata)
+                                       deluxemaptexture = R_LoadTexture2D(loadmodel->texturepool, va("deluxemap%i", lightmapnumber), LIGHTMAPSIZE, LIGHTMAPSIZE, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+                               lightmapnumber++;
                                memset(lightmap_lineused, 0, sizeof(lightmap_lineused));
                                Mod_Q1BSP_AllocLightmapBlock(lightmap_lineused, LIGHTMAPSIZE, LIGHTMAPSIZE, ssize, tsize, &lightmapx, &lightmapy);
                        }
 
                        surface->lightmaptexture = lightmaptexture;
-                       surface->deluxemaptexture = r_texture_blanknormalmap;
+                       surface->deluxemaptexture = deluxemaptexture;
                        surface->lightmapinfo->lightmaporigin[0] = lightmapx;
                        surface->lightmapinfo->lightmaporigin[1] = lightmapy;
 
@@ -2190,14 +2210,14 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
 
                        for (i = 0;i < surface->num_vertices;i++)
                        {
-                               u = ((DotProduct(((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + i * 3), surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3]) + 8 - surface->lightmapinfo->texturemins[0]) * (1.0 / 16.0);
-                               v = ((DotProduct(((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + i * 3), surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3]) + 8 - surface->lightmapinfo->texturemins[1]) * (1.0 / 16.0);
-                               (surface->groupmesh->data_texcoordlightmap2f + 2 * surface->num_firstvertex)[i * 2 + 0] = u * uscale + ubase;
-                               (surface->groupmesh->data_texcoordlightmap2f + 2 * surface->num_firstvertex)[i * 2 + 1] = v * vscale + vbase;
+                               u = ((DotProduct(((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3), surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3]) + 8 - surface->lightmapinfo->texturemins[0]) * (1.0 / 16.0);
+                               v = ((DotProduct(((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3), surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3]) + 8 - surface->lightmapinfo->texturemins[1]) * (1.0 / 16.0);
+                               (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[i * 2 + 0] = u * uscale + ubase;
+                               (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[i * 2 + 1] = v * vscale + vbase;
                                // LordHavoc: calc lightmap data offset for vertex lighting to use
                                iu = (int) u;
                                iv = (int) v;
-                               (surface->groupmesh->data_lightmapoffsets + surface->num_firstvertex)[i] = (bound(0, iv, tmax) * ssize + bound(0, iu, smax)) * 3;
+                               (loadmodel->surfmesh.data_lightmapoffsets + surface->num_firstvertex)[i] = (bound(0, iv, tmax) * ssize + bound(0, iu, smax)) * 3;
                        }
                }
        }
@@ -3258,7 +3278,7 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer, void *bufferend)
        }
        loadmodel->brush.shadowmesh = Mod_ShadowMesh_Begin(loadmodel->mempool, numshadowmeshtriangles * 3, numshadowmeshtriangles, NULL, NULL, NULL, false, false, true);
        for (j = 0, surface = loadmodel->data_surfaces;j < loadmodel->num_surfaces;j++, surface++)
-               Mod_ShadowMesh_AddMesh(loadmodel->mempool, loadmodel->brush.shadowmesh, NULL, NULL, NULL, surface->groupmesh->data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+               Mod_ShadowMesh_AddMesh(loadmodel->mempool, loadmodel->brush.shadowmesh, NULL, NULL, NULL, loadmodel->surfmesh.data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
        loadmodel->brush.shadowmesh = Mod_ShadowMesh_Finish(loadmodel->mempool, loadmodel->brush.shadowmesh, false, true);
        Mod_BuildTriangleNeighbors(loadmodel->brush.shadowmesh->neighbor3i, loadmodel->brush.shadowmesh->element3i, loadmodel->brush.shadowmesh->numtriangles);
 
@@ -3366,7 +3386,7 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer, void *bufferend)
                                if (surface->texture->basematerialflags & MATERIALFLAG_SKY)
                                        mod->DrawSky = R_Q1BSP_DrawSky;
                                // calculate bounding shapes
-                               for (k = 0, vec = (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex);k < surface->num_vertices;k++, vec += 3)
+                               for (k = 0, vec = (loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex);k < surface->num_vertices;k++, vec += 3)
                                {
                                        if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
                                        if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
@@ -4430,7 +4450,7 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l)
 {
        q3dface_t *in, *oldin;
        msurface_t *out, *oldout;
-       int i, oldi, j, n, count, invalidelements, patchsize[2], finalwidth, finalheight, xtess, ytess, finalvertices, finaltriangles, firstvertex, firstelement, type, oldnumtriangles, oldnumtriangles2, meshnum, meshvertices, meshtriangles, numvertices, numtriangles;
+       int i, oldi, j, n, count, invalidelements, patchsize[2], finalwidth, finalheight, xtess, ytess, finalvertices, finaltriangles, firstvertex, firstelement, type, oldnumtriangles, oldnumtriangles2, meshvertices, meshtriangles, numvertices, numtriangles;
        //int *originalelement3i;
        //int *originalneighbor3i;
        float *originalvertex3f;
@@ -4441,7 +4461,6 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l)
        float *originaltexcoordtexture2f;
        float *originaltexcoordlightmap2f;
        float *v;
-       surfmesh_t *mesh, *tempmeshlist[1024];
 
        in = (q3dface_t *)(mod_base + l->fileofs);
        if (l->filelen % sizeof(*in))
@@ -4459,7 +4478,7 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l)
        // is also not a deluxemapped bsp if it has an odd number of lightmaps or
        // less than 2
        loadmodel->brushq3.deluxemapping = true;
-       if (count >= 2 && !(count & 1))
+       if (loadmodel->brushq3.num_lightmaps >= 2 && !(loadmodel->brushq3.num_lightmaps & 1))
        {
                for (i = 0;i < count;i++)
                {
@@ -4476,316 +4495,302 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l)
        Con_DPrintf("%s is %sdeluxemapped\n", loadmodel->name, loadmodel->brushq3.deluxemapping ? "" : "not ");
 
        i = 0;
-       for (meshnum = 0;i < count;meshnum++)
-       {
-               oldi = i;
-               oldin = in;
-               oldout = out;
-               meshvertices = 0;
-               meshtriangles = 0;
-               for (;i < count;i++, in++, out++)
-               {
-                       // check face type first
-                       type = LittleLong(in->type);
-                       if (type != Q3FACETYPE_POLYGON
-                        && type != Q3FACETYPE_PATCH
-                        && type != Q3FACETYPE_MESH
-                        && type != Q3FACETYPE_FLARE)
-                       {
-                               Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i: unknown face type %i\n", i, type);
-                               continue;
-                       }
+       oldi = i;
+       oldin = in;
+       oldout = out;
+       meshvertices = 0;
+       meshtriangles = 0;
+       for (;i < count;i++, in++, out++)
+       {
+               // check face type first
+               type = LittleLong(in->type);
+               if (type != Q3FACETYPE_POLYGON
+                && type != Q3FACETYPE_PATCH
+                && type != Q3FACETYPE_MESH
+                && type != Q3FACETYPE_FLARE)
+               {
+                       Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i: unknown face type %i\n", i, type);
+                       continue;
+               }
 
-                       n = LittleLong(in->textureindex);
-                       if (n < 0 || n >= loadmodel->num_textures)
-                       {
-                               Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i: invalid textureindex %i (%i textures)\n", i, n, loadmodel->num_textures);
-                               continue;
-                       }
-                       out->texture = loadmodel->data_textures + n;
-                       n = LittleLong(in->effectindex);
-                       if (n < -1 || n >= loadmodel->brushq3.num_effects)
-                       {
-                               if (developer.integer >= 100)
-                                       Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid effectindex %i (%i effects)\n", i, out->texture->name, n, loadmodel->brushq3.num_effects);
-                               n = -1;
-                       }
-                       if (n == -1)
-                               out->effect = NULL;
+               n = LittleLong(in->textureindex);
+               if (n < 0 || n >= loadmodel->num_textures)
+               {
+                       Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i: invalid textureindex %i (%i textures)\n", i, n, loadmodel->num_textures);
+                       continue;
+               }
+               out->texture = loadmodel->data_textures + n;
+               n = LittleLong(in->effectindex);
+               if (n < -1 || n >= loadmodel->brushq3.num_effects)
+               {
+                       if (developer.integer >= 100)
+                               Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid effectindex %i (%i effects)\n", i, out->texture->name, n, loadmodel->brushq3.num_effects);
+                       n = -1;
+               }
+               if (n == -1)
+                       out->effect = NULL;
+               else
+                       out->effect = loadmodel->brushq3.data_effects + n;
+               n = LittleLong(in->lightmapindex);
+               if (n >= loadmodel->brushq3.num_lightmaps)
+               {
+                       Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid lightmapindex %i (%i lightmaps)\n", i, out->texture->name, n, loadmodel->brushq3.num_lightmaps);
+                       n = -1;
+               }
+               else if (n < 0)
+                       n = -1;
+               if (n == -1)
+               {
+                       out->lightmaptexture = NULL;
+                       out->deluxemaptexture = r_texture_blanknormalmap;
+               }
+               else
+               {
+                       out->lightmaptexture = loadmodel->brushq3.data_lightmaps[n];
+                       if (loadmodel->brushq3.deluxemapping)
+                               out->deluxemaptexture = loadmodel->brushq3.data_lightmaps[n+1];
                        else
-                               out->effect = loadmodel->brushq3.data_effects + n;
-                       n = LittleLong(in->lightmapindex);
-                       if (n >= loadmodel->brushq3.num_lightmaps)
-                       {
-                               Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid lightmapindex %i (%i lightmaps)\n", i, out->texture->name, n, loadmodel->brushq3.num_lightmaps);
-                               n = -1;
-                       }
-                       else if (n < 0)
-                               n = -1;
-                       if (n == -1)
-                       {
-                               out->lightmaptexture = NULL;
                                out->deluxemaptexture = r_texture_blanknormalmap;
+               }
+
+               firstvertex = LittleLong(in->firstvertex);
+               numvertices = LittleLong(in->numvertices);
+               firstelement = LittleLong(in->firstelement);
+               numtriangles = LittleLong(in->numelements) / 3;
+               if (numtriangles * 3 != LittleLong(in->numelements))
+               {
+                       Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): numelements %i is not a multiple of 3\n", i, out->texture->name, LittleLong(in->numelements));
+                       continue;
+               }
+               if (firstvertex < 0 || firstvertex + numvertices > loadmodel->brushq3.num_vertices)
+               {
+                       Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid vertex range %i : %i (%i vertices)\n", i, out->texture->name, firstvertex, firstvertex + numvertices, loadmodel->brushq3.num_vertices);
+                       continue;
+               }
+               if (firstelement < 0 || firstelement + numtriangles * 3 > loadmodel->brushq3.num_triangles * 3)
+               {
+                       Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid element range %i : %i (%i elements)\n", i, out->texture->name, firstelement, firstelement + numtriangles * 3, loadmodel->brushq3.num_triangles * 3);
+                       continue;
+               }
+               switch(type)
+               {
+               case Q3FACETYPE_POLYGON:
+               case Q3FACETYPE_MESH:
+                       // no processing necessary
+                       break;
+               case Q3FACETYPE_PATCH:
+                       patchsize[0] = LittleLong(in->specific.patch.patchsize[0]);
+                       patchsize[1] = LittleLong(in->specific.patch.patchsize[1]);
+                       if (numvertices != (patchsize[0] * patchsize[1]) || patchsize[0] < 3 || patchsize[1] < 3 || !(patchsize[0] & 1) || !(patchsize[1] & 1) || patchsize[0] * patchsize[1] >= min(r_subdivisions_maxvertices.integer, r_subdivisions_collision_maxvertices.integer))
+                       {
+                               Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid patchsize %ix%i\n", i, out->texture->name, patchsize[0], patchsize[1]);
+                               continue;
                        }
-                       else
+                       originalvertex3f = loadmodel->brushq3.data_vertex3f + firstvertex * 3;
+                       // convert patch to Q3FACETYPE_MESH
+                       xtess = Q3PatchTesselationOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value);
+                       ytess = Q3PatchTesselationOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value);
+                       // bound to user settings
+                       xtess = bound(r_subdivisions_mintess.integer, xtess, r_subdivisions_maxtess.integer);
+                       ytess = bound(r_subdivisions_mintess.integer, ytess, r_subdivisions_maxtess.integer);
+                       // bound to sanity settings
+                       xtess = bound(1, xtess, 1024);
+                       ytess = bound(1, ytess, 1024);
+                       // bound to user limit on vertices
+                       while ((xtess > 1 || ytess > 1) && (((patchsize[0] - 1) * xtess) + 1) * (((patchsize[1] - 1) * ytess) + 1) > min(r_subdivisions_maxvertices.integer, 262144))
                        {
-                               out->lightmaptexture = loadmodel->brushq3.data_lightmaps[n];
-                               if (loadmodel->brushq3.deluxemapping)
-                                       out->deluxemaptexture = loadmodel->brushq3.data_lightmaps[n+1];
+                               if (xtess > ytess)
+                                       xtess--;
                                else
-                                       out->deluxemaptexture = r_texture_blanknormalmap;
+                                       ytess--;
                        }
+                       finalwidth = ((patchsize[0] - 1) * xtess) + 1;
+                       finalheight = ((patchsize[1] - 1) * ytess) + 1;
+                       numvertices = finalwidth * finalheight;
+                       numtriangles = (finalwidth - 1) * (finalheight - 1) * 2;
+                       break;
+               case Q3FACETYPE_FLARE:
+                       if (developer.integer >= 100)
+                               Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): Q3FACETYPE_FLARE not supported (yet)\n", i, out->texture->name);
+                       // don't render it
+                       continue;
+               }
+               out->num_vertices = numvertices;
+               out->num_triangles = numtriangles;
+               meshvertices += out->num_vertices;
+               meshtriangles += out->num_triangles;
+       }
 
-                       firstvertex = LittleLong(in->firstvertex);
-                       numvertices = LittleLong(in->numvertices);
-                       firstelement = LittleLong(in->firstelement);
-                       numtriangles = LittleLong(in->numelements) / 3;
-                       if (numtriangles * 3 != LittleLong(in->numelements))
+       i = oldi;
+       in = oldin;
+       out = oldout;
+       Mod_AllocSurfMesh(loadmodel->mempool, meshvertices, meshtriangles, false, true, false);
+       meshvertices = 0;
+       meshtriangles = 0;
+       for (;i < count && meshvertices + out->num_vertices <= loadmodel->surfmesh.num_vertices;i++, in++, out++)
+       {
+               if (out->num_vertices < 3 || out->num_triangles < 1)
+                       continue;
+
+               type = LittleLong(in->type);
+               firstvertex = LittleLong(in->firstvertex);
+               firstelement = LittleLong(in->firstelement);
+               out->num_firstvertex = meshvertices;
+               out->num_firsttriangle = meshtriangles;
+               switch(type)
+               {
+               case Q3FACETYPE_POLYGON:
+               case Q3FACETYPE_MESH:
+                       // no processing necessary
+                       for (j = 0;j < out->num_vertices;j++)
                        {
-                               Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): numelements %i is not a multiple of 3\n", i, out->texture->name, LittleLong(in->numelements));
-                               continue;
+                               (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex)[j * 3 + 0] = loadmodel->brushq3.data_vertex3f[(firstvertex + j) * 3 + 0];
+                               (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex)[j * 3 + 1] = loadmodel->brushq3.data_vertex3f[(firstvertex + j) * 3 + 1];
+                               (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex)[j * 3 + 2] = loadmodel->brushq3.data_vertex3f[(firstvertex + j) * 3 + 2];
+                               (loadmodel->surfmesh.data_texcoordtexture2f + 2 * out->num_firstvertex)[j * 2 + 0] = loadmodel->brushq3.data_texcoordtexture2f[(firstvertex + j) * 2 + 0];
+                               (loadmodel->surfmesh.data_texcoordtexture2f + 2 * out->num_firstvertex)[j * 2 + 1] = loadmodel->brushq3.data_texcoordtexture2f[(firstvertex + j) * 2 + 1];
+                               (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * out->num_firstvertex)[j * 2 + 0] = loadmodel->brushq3.data_texcoordlightmap2f[(firstvertex + j) * 2 + 0];
+                               (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * out->num_firstvertex)[j * 2 + 1] = loadmodel->brushq3.data_texcoordlightmap2f[(firstvertex + j) * 2 + 1];
+                               (loadmodel->surfmesh.data_lightmapcolor4f + 4 * out->num_firstvertex)[j * 4 + 0] = loadmodel->brushq3.data_color4f[(firstvertex + j) * 4 + 0];
+                               (loadmodel->surfmesh.data_lightmapcolor4f + 4 * out->num_firstvertex)[j * 4 + 1] = loadmodel->brushq3.data_color4f[(firstvertex + j) * 4 + 1];
+                               (loadmodel->surfmesh.data_lightmapcolor4f + 4 * out->num_firstvertex)[j * 4 + 2] = loadmodel->brushq3.data_color4f[(firstvertex + j) * 4 + 2];
+                               (loadmodel->surfmesh.data_lightmapcolor4f + 4 * out->num_firstvertex)[j * 4 + 3] = loadmodel->brushq3.data_color4f[(firstvertex + j) * 4 + 3];
                        }
-                       if (firstvertex < 0 || firstvertex + numvertices > loadmodel->brushq3.num_vertices)
+                       for (j = 0;j < out->num_triangles*3;j++)
+                               (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] = loadmodel->brushq3.data_element3i[firstelement + j] + out->num_firstvertex;
+                       break;
+               case Q3FACETYPE_PATCH:
+                       patchsize[0] = LittleLong(in->specific.patch.patchsize[0]);
+                       patchsize[1] = LittleLong(in->specific.patch.patchsize[1]);
+                       originalvertex3f = loadmodel->brushq3.data_vertex3f + firstvertex * 3;
+                       originaltexcoordtexture2f = loadmodel->brushq3.data_texcoordtexture2f + firstvertex * 2;
+                       originaltexcoordlightmap2f = loadmodel->brushq3.data_texcoordlightmap2f + firstvertex * 2;
+                       originalcolor4f = loadmodel->brushq3.data_color4f + firstvertex * 4;
+                       // convert patch to Q3FACETYPE_MESH
+                       xtess = Q3PatchTesselationOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value);
+                       ytess = Q3PatchTesselationOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value);
+                       // bound to user settings
+                       xtess = bound(r_subdivisions_mintess.integer, xtess, r_subdivisions_maxtess.integer);
+                       ytess = bound(r_subdivisions_mintess.integer, ytess, r_subdivisions_maxtess.integer);
+                       // bound to sanity settings
+                       xtess = bound(1, xtess, 1024);
+                       ytess = bound(1, ytess, 1024);
+                       // bound to user limit on vertices
+                       while ((xtess > 1 || ytess > 1) && (((patchsize[0] - 1) * xtess) + 1) * (((patchsize[1] - 1) * ytess) + 1) > min(r_subdivisions_maxvertices.integer, 262144))
                        {
-                               Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid vertex range %i : %i (%i vertices)\n", i, out->texture->name, firstvertex, firstvertex + numvertices, loadmodel->brushq3.num_vertices);
-                               continue;
+                               if (xtess > ytess)
+                                       xtess--;
+                               else
+                                       ytess--;
                        }
-                       if (firstelement < 0 || firstelement + numtriangles * 3 > loadmodel->brushq3.num_triangles * 3)
+                       finalwidth = ((patchsize[0] - 1) * xtess) + 1;
+                       finalheight = ((patchsize[1] - 1) * ytess) + 1;
+                       finalvertices = finalwidth * finalheight;
+                       finaltriangles = (finalwidth - 1) * (finalheight - 1) * 2;
+                       type = Q3FACETYPE_MESH;
+                       // generate geometry
+                       // (note: normals are skipped because they get recalculated)
+                       Q3PatchTesselateFloat(3, sizeof(float[3]), (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[3]), originalvertex3f, xtess, ytess);
+                       Q3PatchTesselateFloat(2, sizeof(float[2]), (loadmodel->surfmesh.data_texcoordtexture2f + 2 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[2]), originaltexcoordtexture2f, xtess, ytess);
+                       Q3PatchTesselateFloat(2, sizeof(float[2]), (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[2]), originaltexcoordlightmap2f, xtess, ytess);
+                       Q3PatchTesselateFloat(4, sizeof(float[4]), (loadmodel->surfmesh.data_lightmapcolor4f + 4 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[4]), originalcolor4f, xtess, ytess);
+                       Q3PatchTriangleElements((loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle), finalwidth, finalheight, out->num_firstvertex);
+                       out->num_triangles = Mod_RemoveDegenerateTriangles(out->num_triangles, (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle), (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle), loadmodel->surfmesh.data_vertex3f);
+                       if (developer.integer >= 100)
                        {
-                               Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid element range %i : %i (%i elements)\n", i, out->texture->name, firstelement, firstelement + numtriangles * 3, loadmodel->brushq3.num_triangles * 3);
-                               continue;
+                               if (out->num_triangles < finaltriangles)
+                                       Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided to %i vertices / %i triangles, %i degenerate triangles removed (leaving %i)\n", patchsize[0], patchsize[1], out->num_vertices, finaltriangles, finaltriangles - out->num_triangles, out->num_triangles);
+                               else
+                                       Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided to %i vertices / %i triangles\n", patchsize[0], patchsize[1], out->num_vertices, out->num_triangles);
                        }
-                       switch(type)
+                       // q3map does not put in collision brushes for curves... ugh
+                       // build the lower quality collision geometry
+                       xtess = Q3PatchTesselationOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_collision_tolerance.value);
+                       ytess = Q3PatchTesselationOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_collision_tolerance.value);
+                       // bound to user settings
+                       xtess = bound(r_subdivisions_collision_mintess.integer, xtess, r_subdivisions_collision_maxtess.integer);
+                       ytess = bound(r_subdivisions_collision_mintess.integer, ytess, r_subdivisions_collision_maxtess.integer);
+                       // bound to sanity settings
+                       xtess = bound(1, xtess, 1024);
+                       ytess = bound(1, ytess, 1024);
+                       // bound to user limit on vertices
+                       while ((xtess > 1 || ytess > 1) && (((patchsize[0] - 1) * xtess) + 1) * (((patchsize[1] - 1) * ytess) + 1) > min(r_subdivisions_collision_maxvertices.integer, 262144))
                        {
-                       case Q3FACETYPE_POLYGON:
-                       case Q3FACETYPE_MESH:
-                               // no processing necessary
-                               break;
-                       case Q3FACETYPE_PATCH:
-                               patchsize[0] = LittleLong(in->specific.patch.patchsize[0]);
-                               patchsize[1] = LittleLong(in->specific.patch.patchsize[1]);
-                               if (numvertices != (patchsize[0] * patchsize[1]) || patchsize[0] < 3 || patchsize[1] < 3 || !(patchsize[0] & 1) || !(patchsize[1] & 1) || patchsize[0] * patchsize[1] >= min(r_subdivisions_maxvertices.integer, r_subdivisions_collision_maxvertices.integer))
-                               {
-                                       Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid patchsize %ix%i\n", i, out->texture->name, patchsize[0], patchsize[1]);
-                                       continue;
-                               }
-                               originalvertex3f = loadmodel->brushq3.data_vertex3f + firstvertex * 3;
-                               // convert patch to Q3FACETYPE_MESH
-                               xtess = Q3PatchTesselationOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value);
-                               ytess = Q3PatchTesselationOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value);
-                               // bound to user settings
-                               xtess = bound(r_subdivisions_mintess.integer, xtess, r_subdivisions_maxtess.integer);
-                               ytess = bound(r_subdivisions_mintess.integer, ytess, r_subdivisions_maxtess.integer);
-                               // bound to sanity settings
-                               xtess = bound(1, xtess, 1024);
-                               ytess = bound(1, ytess, 1024);
-                               // bound to user limit on vertices
-                               while ((xtess > 1 || ytess > 1) && (((patchsize[0] - 1) * xtess) + 1) * (((patchsize[1] - 1) * ytess) + 1) > min(r_subdivisions_maxvertices.integer, 262144))
-                               {
-                                       if (xtess > ytess)
-                                               xtess--;
-                                       else
-                                               ytess--;
-                               }
-                               finalwidth = ((patchsize[0] - 1) * xtess) + 1;
-                               finalheight = ((patchsize[1] - 1) * ytess) + 1;
-                               numvertices = finalwidth * finalheight;
-                               numtriangles = (finalwidth - 1) * (finalheight - 1) * 2;
-                               break;
-                       case Q3FACETYPE_FLARE:
-                               if (developer.integer >= 100)
-                                       Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): Q3FACETYPE_FLARE not supported (yet)\n", i, out->texture->name);
-                               // don't render it
-                               continue;
+                               if (xtess > ytess)
+                                       xtess--;
+                               else
+                                       ytess--;
                        }
-                       out->num_vertices = numvertices;
-                       out->num_triangles = numtriangles;
-                       if (meshvertices + out->num_vertices > 65536)
-                               break;
-                       meshvertices += out->num_vertices;
-                       meshtriangles += out->num_triangles;
+                       finalwidth = ((patchsize[0] - 1) * xtess) + 1;
+                       finalheight = ((patchsize[1] - 1) * ytess) + 1;
+                       finalvertices = finalwidth * finalheight;
+                       finaltriangles = (finalwidth - 1) * (finalheight - 1) * 2;
+
+                       out->data_collisionvertex3f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * finalvertices);
+                       out->data_collisionelement3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * finaltriangles);
+                       out->num_collisionvertices = finalvertices;
+                       out->num_collisiontriangles = finaltriangles;
+                       Q3PatchTesselateFloat(3, sizeof(float[3]), out->data_collisionvertex3f, patchsize[0], patchsize[1], sizeof(float[3]), originalvertex3f, xtess, ytess);
+                       Q3PatchTriangleElements(out->data_collisionelement3i, finalwidth, finalheight, 0);
+
+                       //Mod_SnapVertices(3, out->num_vertices, (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex), 0.25);
+                       Mod_SnapVertices(3, out->num_collisionvertices, out->data_collisionvertex3f, 1);
+
+                       oldnumtriangles = out->num_triangles;
+                       oldnumtriangles2 = out->num_collisiontriangles;
+                       out->num_collisiontriangles = Mod_RemoveDegenerateTriangles(out->num_collisiontriangles, out->data_collisionelement3i, out->data_collisionelement3i, out->data_collisionvertex3f);
+                       if (developer.integer >= 100)
+                               Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve became %i:%i vertices / %i:%i triangles (%i:%i degenerate)\n", patchsize[0], patchsize[1], out->num_vertices, out->num_collisionvertices, oldnumtriangles, oldnumtriangles2, oldnumtriangles - out->num_triangles, oldnumtriangles2 - out->num_collisiontriangles);
+                       break;
+               default:
+                       break;
                }
-
-               i = oldi;
-               in = oldin;
-               out = oldout;
-               mesh = tempmeshlist[meshnum] = Mod_AllocSurfMesh(loadmodel->mempool, meshvertices, meshtriangles, false, true, false);
-               meshvertices = 0;
-               meshtriangles = 0;
-               for (;i < count && meshvertices + out->num_vertices <= mesh->num_vertices;i++, in++, out++)
+               meshvertices += out->num_vertices;
+               meshtriangles += out->num_triangles;
+               for (j = 0, invalidelements = 0;j < out->num_triangles * 3;j++)
+                       if ((loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] < out->num_firstvertex || (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] >= out->num_firstvertex + out->num_vertices)
+                               invalidelements++;
+               if (invalidelements)
                {
-                       if (out->num_vertices < 3 || out->num_triangles < 1)
-                               continue;
-
-                       type = LittleLong(in->type);
-                       firstvertex = LittleLong(in->firstvertex);
-                       firstelement = LittleLong(in->firstelement);
-                       out->groupmesh = mesh;
-                       out->num_firstvertex = meshvertices;
-                       out->num_firsttriangle = meshtriangles;
-                       switch(type)
+                       Con_Printf("Mod_Q3BSP_LoadFaces: Warning: face #%i has %i invalid elements, type = %i, texture->name = \"%s\", texture->surfaceflags = %i, firstvertex = %i, numvertices = %i, firstelement = %i, numelements = %i, elements list:\n", i, invalidelements, type, out->texture->name, out->texture->surfaceflags, firstvertex, out->num_vertices, firstelement, out->num_triangles * 3);
+                       for (j = 0;j < out->num_triangles * 3;j++)
                        {
-                       case Q3FACETYPE_POLYGON:
-                       case Q3FACETYPE_MESH:
-                               // no processing necessary
-                               for (j = 0;j < out->num_vertices;j++)
-                               {
-                                       (out->groupmesh->data_vertex3f + 3 * out->num_firstvertex)[j * 3 + 0] = loadmodel->brushq3.data_vertex3f[(firstvertex + j) * 3 + 0];
-                                       (out->groupmesh->data_vertex3f + 3 * out->num_firstvertex)[j * 3 + 1] = loadmodel->brushq3.data_vertex3f[(firstvertex + j) * 3 + 1];
-                                       (out->groupmesh->data_vertex3f + 3 * out->num_firstvertex)[j * 3 + 2] = loadmodel->brushq3.data_vertex3f[(firstvertex + j) * 3 + 2];
-                                       (out->groupmesh->data_texcoordtexture2f + 2 * out->num_firstvertex)[j * 2 + 0] = loadmodel->brushq3.data_texcoordtexture2f[(firstvertex + j) * 2 + 0];
-                                       (out->groupmesh->data_texcoordtexture2f + 2 * out->num_firstvertex)[j * 2 + 1] = loadmodel->brushq3.data_texcoordtexture2f[(firstvertex + j) * 2 + 1];
-                                       (out->groupmesh->data_texcoordlightmap2f + 2 * out->num_firstvertex)[j * 2 + 0] = loadmodel->brushq3.data_texcoordlightmap2f[(firstvertex + j) * 2 + 0];
-                                       (out->groupmesh->data_texcoordlightmap2f + 2 * out->num_firstvertex)[j * 2 + 1] = loadmodel->brushq3.data_texcoordlightmap2f[(firstvertex + j) * 2 + 1];
-                                       (out->groupmesh->data_lightmapcolor4f + 4 * out->num_firstvertex)[j * 4 + 0] = loadmodel->brushq3.data_color4f[(firstvertex + j) * 4 + 0];
-                                       (out->groupmesh->data_lightmapcolor4f + 4 * out->num_firstvertex)[j * 4 + 1] = loadmodel->brushq3.data_color4f[(firstvertex + j) * 4 + 1];
-                                       (out->groupmesh->data_lightmapcolor4f + 4 * out->num_firstvertex)[j * 4 + 2] = loadmodel->brushq3.data_color4f[(firstvertex + j) * 4 + 2];
-                                       (out->groupmesh->data_lightmapcolor4f + 4 * out->num_firstvertex)[j * 4 + 3] = loadmodel->brushq3.data_color4f[(firstvertex + j) * 4 + 3];
-                               }
-                               for (j = 0;j < out->num_triangles*3;j++)
-                                       (out->groupmesh->data_element3i + 3 * out->num_firsttriangle)[j] = loadmodel->brushq3.data_element3i[firstelement + j] + out->num_firstvertex;
-                               break;
-                       case Q3FACETYPE_PATCH:
-                               patchsize[0] = LittleLong(in->specific.patch.patchsize[0]);
-                               patchsize[1] = LittleLong(in->specific.patch.patchsize[1]);
-                               originalvertex3f = loadmodel->brushq3.data_vertex3f + firstvertex * 3;
-                               originaltexcoordtexture2f = loadmodel->brushq3.data_texcoordtexture2f + firstvertex * 2;
-                               originaltexcoordlightmap2f = loadmodel->brushq3.data_texcoordlightmap2f + firstvertex * 2;
-                               originalcolor4f = loadmodel->brushq3.data_color4f + firstvertex * 4;
-                               // convert patch to Q3FACETYPE_MESH
-                               xtess = Q3PatchTesselationOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value);
-                               ytess = Q3PatchTesselationOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value);
-                               // bound to user settings
-                               xtess = bound(r_subdivisions_mintess.integer, xtess, r_subdivisions_maxtess.integer);
-                               ytess = bound(r_subdivisions_mintess.integer, ytess, r_subdivisions_maxtess.integer);
-                               // bound to sanity settings
-                               xtess = bound(1, xtess, 1024);
-                               ytess = bound(1, ytess, 1024);
-                               // bound to user limit on vertices
-                               while ((xtess > 1 || ytess > 1) && (((patchsize[0] - 1) * xtess) + 1) * (((patchsize[1] - 1) * ytess) + 1) > min(r_subdivisions_maxvertices.integer, 262144))
-                               {
-                                       if (xtess > ytess)
-                                               xtess--;
-                                       else
-                                               ytess--;
-                               }
-                               finalwidth = ((patchsize[0] - 1) * xtess) + 1;
-                               finalheight = ((patchsize[1] - 1) * ytess) + 1;
-                               finalvertices = finalwidth * finalheight;
-                               finaltriangles = (finalwidth - 1) * (finalheight - 1) * 2;
-                               type = Q3FACETYPE_MESH;
-                               // generate geometry
-                               // (note: normals are skipped because they get recalculated)
-                               Q3PatchTesselateFloat(3, sizeof(float[3]), (out->groupmesh->data_vertex3f + 3 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[3]), originalvertex3f, xtess, ytess);
-                               Q3PatchTesselateFloat(2, sizeof(float[2]), (out->groupmesh->data_texcoordtexture2f + 2 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[2]), originaltexcoordtexture2f, xtess, ytess);
-                               Q3PatchTesselateFloat(2, sizeof(float[2]), (out->groupmesh->data_texcoordlightmap2f + 2 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[2]), originaltexcoordlightmap2f, xtess, ytess);
-                               Q3PatchTesselateFloat(4, sizeof(float[4]), (out->groupmesh->data_lightmapcolor4f + 4 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[4]), originalcolor4f, xtess, ytess);
-                               Q3PatchTriangleElements((out->groupmesh->data_element3i + 3 * out->num_firsttriangle), finalwidth, finalheight, out->num_firstvertex);
-                               out->num_triangles = Mod_RemoveDegenerateTriangles(out->num_triangles, (out->groupmesh->data_element3i + 3 * out->num_firsttriangle), (out->groupmesh->data_element3i + 3 * out->num_firsttriangle), out->groupmesh->data_vertex3f);
-                               if (developer.integer >= 100)
-                               {
-                                       if (out->num_triangles < finaltriangles)
-                                               Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided to %i vertices / %i triangles, %i degenerate triangles removed (leaving %i)\n", patchsize[0], patchsize[1], out->num_vertices, finaltriangles, finaltriangles - out->num_triangles, out->num_triangles);
-                                       else
-                                               Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided to %i vertices / %i triangles\n", patchsize[0], patchsize[1], out->num_vertices, out->num_triangles);
-                               }
-                               // q3map does not put in collision brushes for curves... ugh
-                               // build the lower quality collision geometry
-                               xtess = Q3PatchTesselationOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_collision_tolerance.value);
-                               ytess = Q3PatchTesselationOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_collision_tolerance.value);
-                               // bound to user settings
-                               xtess = bound(r_subdivisions_collision_mintess.integer, xtess, r_subdivisions_collision_maxtess.integer);
-                               ytess = bound(r_subdivisions_collision_mintess.integer, ytess, r_subdivisions_collision_maxtess.integer);
-                               // bound to sanity settings
-                               xtess = bound(1, xtess, 1024);
-                               ytess = bound(1, ytess, 1024);
-                               // bound to user limit on vertices
-                               while ((xtess > 1 || ytess > 1) && (((patchsize[0] - 1) * xtess) + 1) * (((patchsize[1] - 1) * ytess) + 1) > min(r_subdivisions_collision_maxvertices.integer, 262144))
-                               {
-                                       if (xtess > ytess)
-                                               xtess--;
-                                       else
-                                               ytess--;
-                               }
-                               finalwidth = ((patchsize[0] - 1) * xtess) + 1;
-                               finalheight = ((patchsize[1] - 1) * ytess) + 1;
-                               finalvertices = finalwidth * finalheight;
-                               finaltriangles = (finalwidth - 1) * (finalheight - 1) * 2;
-
-                               out->data_collisionvertex3f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * finalvertices);
-                               out->data_collisionelement3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * finaltriangles);
-                               out->num_collisionvertices = finalvertices;
-                               out->num_collisiontriangles = finaltriangles;
-                               Q3PatchTesselateFloat(3, sizeof(float[3]), out->data_collisionvertex3f, patchsize[0], patchsize[1], sizeof(float[3]), originalvertex3f, xtess, ytess);
-                               Q3PatchTriangleElements(out->data_collisionelement3i, finalwidth, finalheight, 0);
-
-                               //Mod_SnapVertices(3, out->num_vertices, (out->groupmesh->data_vertex3f + 3 * out->num_firstvertex), 0.25);
-                               Mod_SnapVertices(3, out->num_collisionvertices, out->data_collisionvertex3f, 1);
-
-                               oldnumtriangles = out->num_triangles;
-                               oldnumtriangles2 = out->num_collisiontriangles;
-                               out->num_collisiontriangles = Mod_RemoveDegenerateTriangles(out->num_collisiontriangles, out->data_collisionelement3i, out->data_collisionelement3i, out->data_collisionvertex3f);
-                               if (developer.integer >= 100)
-                                       Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve became %i:%i vertices / %i:%i triangles (%i:%i degenerate)\n", patchsize[0], patchsize[1], out->num_vertices, out->num_collisionvertices, oldnumtriangles, oldnumtriangles2, oldnumtriangles - out->num_triangles, oldnumtriangles2 - out->num_collisiontriangles);
-                               break;
-                       default:
-                               break;
-                       }
-                       meshvertices += out->num_vertices;
-                       meshtriangles += out->num_triangles;
-                       for (j = 0, invalidelements = 0;j < out->num_triangles * 3;j++)
-                               if ((out->groupmesh->data_element3i + 3 * out->num_firsttriangle)[j] < out->num_firstvertex || (out->groupmesh->data_element3i + 3 * out->num_firsttriangle)[j] >= out->num_firstvertex + out->num_vertices)
-                                       invalidelements++;
-                       if (invalidelements)
-                       {
-                               Con_Printf("Mod_Q3BSP_LoadFaces: Warning: face #%i has %i invalid elements, type = %i, texture->name = \"%s\", texture->surfaceflags = %i, firstvertex = %i, numvertices = %i, firstelement = %i, numelements = %i, elements list:\n", i, invalidelements, type, out->texture->name, out->texture->surfaceflags, firstvertex, out->num_vertices, firstelement, out->num_triangles * 3);
-                               for (j = 0;j < out->num_triangles * 3;j++)
-                               {
-                                       Con_Printf(" %i", (out->groupmesh->data_element3i + 3 * out->num_firsttriangle)[j] - out->num_firstvertex);
-                                       if ((out->groupmesh->data_element3i + 3 * out->num_firsttriangle)[j] < out->num_firstvertex || (out->groupmesh->data_element3i + 3 * out->num_firsttriangle)[j] >= out->num_firstvertex + out->num_vertices)
-                                               (out->groupmesh->data_element3i + 3 * out->num_firsttriangle)[j] = out->num_firstvertex;
-                               }
-                               Con_Print("\n");
+                               Con_Printf(" %i", (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] - out->num_firstvertex);
+                               if ((loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] < out->num_firstvertex || (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] >= out->num_firstvertex + out->num_vertices)
+                                       (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] = out->num_firstvertex;
                        }
-                       // for per pixel lighting
-                       Mod_BuildTextureVectorsAndNormals(out->num_firstvertex, out->num_vertices, out->num_triangles, out->groupmesh->data_vertex3f, out->groupmesh->data_texcoordtexture2f, (out->groupmesh->data_element3i + 3 * out->num_firsttriangle), out->groupmesh->data_svector3f, out->groupmesh->data_tvector3f, out->groupmesh->data_normal3f, true);
-                       // calculate a bounding box
-                       VectorClear(out->mins);
-                       VectorClear(out->maxs);
-                       if (out->num_vertices)
+                       Con_Print("\n");
+               }
+               // for per pixel lighting
+               Mod_BuildTextureVectorsAndNormals(out->num_firstvertex, out->num_vertices, out->num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle), loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, loadmodel->surfmesh.data_normal3f, true);
+               // calculate a bounding box
+               VectorClear(out->mins);
+               VectorClear(out->maxs);
+               if (out->num_vertices)
+               {
+                       VectorCopy((loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex), out->mins);
+                       VectorCopy((loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex), out->maxs);
+                       for (j = 1, v = (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex) + 3;j < out->num_vertices;j++, v += 3)
                        {
-                               VectorCopy((out->groupmesh->data_vertex3f + 3 * out->num_firstvertex), out->mins);
-                               VectorCopy((out->groupmesh->data_vertex3f + 3 * out->num_firstvertex), out->maxs);
-                               for (j = 1, v = (out->groupmesh->data_vertex3f + 3 * out->num_firstvertex) + 3;j < out->num_vertices;j++, v += 3)
-                               {
-                                       out->mins[0] = min(out->mins[0], v[0]);
-                                       out->maxs[0] = max(out->maxs[0], v[0]);
-                                       out->mins[1] = min(out->mins[1], v[1]);
-                                       out->maxs[1] = max(out->maxs[1], v[1]);
-                                       out->mins[2] = min(out->mins[2], v[2]);
-                                       out->maxs[2] = max(out->maxs[2], v[2]);
-                               }
-                               out->mins[0] -= 1.0f;
-                               out->mins[1] -= 1.0f;
-                               out->mins[2] -= 1.0f;
-                               out->maxs[0] += 1.0f;
-                               out->maxs[1] += 1.0f;
-                               out->maxs[2] += 1.0f;
+                               out->mins[0] = min(out->mins[0], v[0]);
+                               out->maxs[0] = max(out->maxs[0], v[0]);
+                               out->mins[1] = min(out->mins[1], v[1]);
+                               out->maxs[1] = max(out->maxs[1], v[1]);
+                               out->mins[2] = min(out->mins[2], v[2]);
+                               out->maxs[2] = max(out->maxs[2], v[2]);
                        }
-                       // set lightmap styles for consistency with q1bsp
-                       //out->lightmapinfo->styles[0] = 0;
-                       //out->lightmapinfo->styles[1] = 255;
-                       //out->lightmapinfo->styles[2] = 255;
-                       //out->lightmapinfo->styles[3] = 255;
+                       out->mins[0] -= 1.0f;
+                       out->mins[1] -= 1.0f;
+                       out->mins[2] -= 1.0f;
+                       out->maxs[0] += 1.0f;
+                       out->maxs[1] += 1.0f;
+                       out->maxs[2] += 1.0f;
                }
-       }
-
-       // now store the completed list of meshes
-       loadmodel->nummeshes = meshnum;
-       if (loadmodel->nummeshes)
-       {
-               loadmodel->meshlist = (surfmesh_t **)Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t *) * loadmodel->nummeshes);
-               memcpy(loadmodel->meshlist, tempmeshlist, sizeof(surfmesh_t *) * loadmodel->nummeshes);
+               // set lightmap styles for consistency with q1bsp
+               //out->lightmapinfo->styles[0] = 0;
+               //out->lightmapinfo->styles[1] = 255;
+               //out->lightmapinfo->styles[2] = 255;
+               //out->lightmapinfo->styles[3] = 255;
        }
 
        // free the no longer needed vertex data
@@ -4991,12 +4996,12 @@ static void Mod_Q3BSP_LoadLightGrid(lump_t *l)
        loadmodel->brushq3.num_lightgrid_scale[0] = 1.0f / loadmodel->brushq3.num_lightgrid_cellsize[0];
        loadmodel->brushq3.num_lightgrid_scale[1] = 1.0f / loadmodel->brushq3.num_lightgrid_cellsize[1];
        loadmodel->brushq3.num_lightgrid_scale[2] = 1.0f / loadmodel->brushq3.num_lightgrid_cellsize[2];
-       loadmodel->brushq3.num_lightgrid_imins[0] = ceil(loadmodel->brushq3.data_models->mins[0] * loadmodel->brushq3.num_lightgrid_scale[0]);
-       loadmodel->brushq3.num_lightgrid_imins[1] = ceil(loadmodel->brushq3.data_models->mins[1] * loadmodel->brushq3.num_lightgrid_scale[1]);
-       loadmodel->brushq3.num_lightgrid_imins[2] = ceil(loadmodel->brushq3.data_models->mins[2] * loadmodel->brushq3.num_lightgrid_scale[2]);
-       loadmodel->brushq3.num_lightgrid_imaxs[0] = floor(loadmodel->brushq3.data_models->maxs[0] * loadmodel->brushq3.num_lightgrid_scale[0]);
-       loadmodel->brushq3.num_lightgrid_imaxs[1] = floor(loadmodel->brushq3.data_models->maxs[1] * loadmodel->brushq3.num_lightgrid_scale[1]);
-       loadmodel->brushq3.num_lightgrid_imaxs[2] = floor(loadmodel->brushq3.data_models->maxs[2] * loadmodel->brushq3.num_lightgrid_scale[2]);
+       loadmodel->brushq3.num_lightgrid_imins[0] = (int)ceil(loadmodel->brushq3.data_models->mins[0] * loadmodel->brushq3.num_lightgrid_scale[0]);
+       loadmodel->brushq3.num_lightgrid_imins[1] = (int)ceil(loadmodel->brushq3.data_models->mins[1] * loadmodel->brushq3.num_lightgrid_scale[1]);
+       loadmodel->brushq3.num_lightgrid_imins[2] = (int)ceil(loadmodel->brushq3.data_models->mins[2] * loadmodel->brushq3.num_lightgrid_scale[2]);
+       loadmodel->brushq3.num_lightgrid_imaxs[0] = (int)floor(loadmodel->brushq3.data_models->maxs[0] * loadmodel->brushq3.num_lightgrid_scale[0]);
+       loadmodel->brushq3.num_lightgrid_imaxs[1] = (int)floor(loadmodel->brushq3.data_models->maxs[1] * loadmodel->brushq3.num_lightgrid_scale[1]);
+       loadmodel->brushq3.num_lightgrid_imaxs[2] = (int)floor(loadmodel->brushq3.data_models->maxs[2] * loadmodel->brushq3.num_lightgrid_scale[2]);
        loadmodel->brushq3.num_lightgrid_isize[0] = loadmodel->brushq3.num_lightgrid_imaxs[0] - loadmodel->brushq3.num_lightgrid_imins[0] + 1;
        loadmodel->brushq3.num_lightgrid_isize[1] = loadmodel->brushq3.num_lightgrid_imaxs[1] - loadmodel->brushq3.num_lightgrid_imins[1] + 1;
        loadmodel->brushq3.num_lightgrid_isize[2] = loadmodel->brushq3.num_lightgrid_imaxs[2] - loadmodel->brushq3.num_lightgrid_imins[2] + 1;
@@ -5534,8 +5539,8 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer, void *bufferend)
        }
        loadmodel->brush.shadowmesh = Mod_ShadowMesh_Begin(loadmodel->mempool, numshadowmeshtriangles * 3, numshadowmeshtriangles, NULL, NULL, NULL, false, false, true);
        for (j = 0, surface = loadmodel->data_surfaces;j < loadmodel->num_surfaces;j++, surface++)
-               if (surface->groupmesh)
-                       Mod_ShadowMesh_AddMesh(loadmodel->mempool, loadmodel->brush.shadowmesh, NULL, NULL, NULL, surface->groupmesh->data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+               if (surface->num_triangles > 0)
+                       Mod_ShadowMesh_AddMesh(loadmodel->mempool, loadmodel->brush.shadowmesh, NULL, NULL, NULL, loadmodel->surfmesh.data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
        loadmodel->brush.shadowmesh = Mod_ShadowMesh_Finish(loadmodel->mempool, loadmodel->brush.shadowmesh, false, true);
        Mod_BuildTriangleNeighbors(loadmodel->brush.shadowmesh->neighbor3i, loadmodel->brush.shadowmesh->element3i, loadmodel->brush.shadowmesh->numtriangles);