]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_brush.c
lights now have an orientation (this isn't editable yet, and is infact not really...
[xonotic/darkplaces.git] / model_brush.c
index ea39f1cd305cb740db69892adc8980b015454f72..20a57fafda9bac3902bcae39804fa97d25618c6f 100644 (file)
@@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 #include "image.h"
+#include "r_shadow.h"
 
 // note: model_shared.c sets up r_notexture, and r_surf_notexture
 
@@ -33,10 +34,6 @@ cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1"};
 cvar_t r_nosurftextures = {0, "r_nosurftextures", "0"};
 cvar_t r_sortsurfaces = {0, "r_sortsurfaces", "0"};
 
-#define NUM_DETAILTEXTURES 1
-static rtexture_t *detailtextures[NUM_DETAILTEXTURES];
-static rtexturepool_t *detailtexturepool;
-
 /*
 ===============
 Mod_BrushInit
@@ -54,55 +51,6 @@ void Mod_BrushInit (void)
        memset(mod_novis, 0xff, sizeof(mod_novis));
 }
 
-void Mod_BrushStartup (void)
-{
-       int i, x, y, light;
-       float vc[3], vx[3], vy[3], vn[3], lightdir[3];
-#define DETAILRESOLUTION 256
-       qbyte data[DETAILRESOLUTION][DETAILRESOLUTION][4], noise[DETAILRESOLUTION][DETAILRESOLUTION];
-       detailtexturepool = R_AllocTexturePool();
-       lightdir[0] = 0.5;
-       lightdir[1] = 1;
-       lightdir[2] = -0.25;
-       VectorNormalize(lightdir);
-       for (i = 0;i < NUM_DETAILTEXTURES;i++)
-       {
-               fractalnoise(&noise[0][0], DETAILRESOLUTION, DETAILRESOLUTION >> 4);
-               for (y = 0;y < DETAILRESOLUTION;y++)
-               {
-                       for (x = 0;x < DETAILRESOLUTION;x++)
-                       {
-                               vc[0] = x;
-                               vc[1] = y;
-                               vc[2] = noise[y][x] * (1.0f / 32.0f);
-                               vx[0] = x + 1;
-                               vx[1] = y;
-                               vx[2] = noise[y][(x + 1) % DETAILRESOLUTION] * (1.0f / 32.0f);
-                               vy[0] = x;
-                               vy[1] = y + 1;
-                               vy[2] = noise[(y + 1) % DETAILRESOLUTION][x] * (1.0f / 32.0f);
-                               VectorSubtract(vx, vc, vx);
-                               VectorSubtract(vy, vc, vy);
-                               CrossProduct(vx, vy, vn);
-                               VectorNormalize(vn);
-                               light = 128 - DotProduct(vn, lightdir) * 128;
-                               light = bound(0, light, 255);
-                               data[y][x][0] = data[y][x][1] = data[y][x][2] = light;
-                               data[y][x][3] = 255;
-                       }
-               }
-               detailtextures[i] = R_LoadTexture2D(detailtexturepool, va("detailtexture%i", i), DETAILRESOLUTION, DETAILRESOLUTION, &data[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_PRECACHE, NULL);
-       }
-}
-
-void Mod_BrushShutdown (void)
-{
-       int i;
-       for (i = 0;i < NUM_DETAILTEXTURES;i++)
-               R_FreeTexture(detailtextures[i]);
-       R_FreeTexturePool(&detailtexturepool);
-}
-
 /*
 ===============
 Mod_PointInLeaf
@@ -214,11 +162,6 @@ static void Mod_LoadTextures (lump_t *l)
        dmiptexlump_t *m;
        qbyte *data, *mtdata;
        char name[256];
-       qbyte *basepixels, *bumppixels, *nmappixels, *glosspixels, *glowpixels, *maskpixels;
-       int basepixels_width, basepixels_height, bumppixels_width, bumppixels_height;
-       int nmappixels_width, nmappixels_height, glosspixels_width, glosspixels_height;
-       int glowpixels_width, glowpixels_height, maskpixels_width, maskpixels_height;
-       rtexture_t *detailtexture;
 
        loadmodel->textures = NULL;
 
@@ -237,13 +180,15 @@ static void Mod_LoadTextures (lump_t *l)
        for (i = 0, tx = loadmodel->textures;i < loadmodel->numtextures;i++, tx++)
        {
                tx->number = i;
+               strcpy(tx->name, "NO TEXTURE FOUND");
                tx->width = 16;
                tx->height = 16;
-               tx->texture = r_notexture;
+               tx->skin.base = r_notexture;
                tx->shader = &Cshader_wall_lightmap;
+               tx->flags = SURF_SOLIDCLIP;
                if (i == loadmodel->numtextures - 1)
                {
-                       tx->flags = SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
+                       tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
                        tx->shader = &Cshader_water;
                }
                tx->currentframe = tx;
@@ -298,14 +243,6 @@ static void Mod_LoadTextures (lump_t *l)
                        Con_Printf("warning: unnamed texture in %s, renaming to %s\n", loadmodel->name, tx->name);
                }
 
-               basepixels = NULL;basepixels_width = 0;basepixels_height = 0;
-               bumppixels = NULL;bumppixels_width = 0;bumppixels_height = 0;
-               nmappixels = NULL;nmappixels_width = 0;nmappixels_height = 0;
-               glosspixels = NULL;glosspixels_width = 0;glosspixels_height = 0;
-               glowpixels = NULL;glowpixels_width = 0;glowpixels_height = 0;
-               maskpixels = NULL;maskpixels_width = 0;maskpixels_height = 0;
-               detailtexture = NULL;
-
                // LordHavoc: HL sky textures are entirely different than quake
                if (!loadmodel->ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == 256 && mtheight == 128)
                {
@@ -333,162 +270,43 @@ static void Mod_LoadTextures (lump_t *l)
                }
                else
                {
-                       if ((basepixels = loadimagepixels(tx->name, false, 0, 0)) != NULL)
-                       {
-                               basepixels_width = image_width;
-                               basepixels_height = image_height;
-                       }
-                       // _luma is supported for tenebrae compatibility
-                       // (I think it's a very stupid name, but oh well)
-                       if ((glowpixels = loadimagepixels(va("%s_glow", tx->name), false, 0, 0)) != NULL
-                        || (glowpixels = loadimagepixels(va("%s_luma", tx->name), false, 0, 0)) != NULL)
-                       {
-                               glowpixels_width = image_width;
-                               glowpixels_height = image_height;
-                       }
-                       if ((bumppixels = loadimagepixels(va("%s_bump", tx->name), false, 0, 0)) != NULL)
-                       {
-                               bumppixels_width = image_width;
-                               bumppixels_height = image_height;
-                       }
-                       if ((glosspixels = loadimagepixels(va("%s_gloss", tx->name), false, 0, 0)) != NULL)
-                       {
-                               glosspixels_width = image_width;
-                               glosspixels_height = image_height;
-                       }
-                       if (!basepixels)
+                       if (!Mod_LoadSkinFrame(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, false, true, true))
                        {
+                               // did not find external texture, load it from the bsp or wad3
                                if (loadmodel->ishlbsp)
                                {
                                        // internal texture overrides wad
-                                       if (mtdata && (basepixels = W_ConvertWAD3Texture(dmiptex)) != NULL)
+                                       qbyte *pixels, *freepixels;
+                                       pixels = freepixels = NULL;
+                                       if (mtdata)
+                                               pixels = W_ConvertWAD3Texture(dmiptex);
+                                       if (pixels == NULL)
+                                               pixels = freepixels = W_GetTexture(tx->name);
+                                       if (pixels != NULL)
                                        {
-                                               basepixels_width = image_width;
-                                               basepixels_height = image_height;
+                                               tx->width = image_width;
+                                               tx->height = image_height;
+                                               tx->skin.base = tx->skin.merged = R_LoadTexture2D(loadmodel->texturepool, tx->name, image_width, image_height, pixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
                                        }
-                                       else if ((basepixels = W_GetTexture(tx->name)) != NULL)
-                                       {
-                                               // get the size from the wad texture
-                                               tx->width = basepixels_width = image_width;
-                                               tx->height = basepixels_height = image_height;
-                                       }
-                               }
-                               else
-                               {
-                                       if (mtdata) // texture included
-                                       {
-                                               if (r_fullbrights.integer && tx->name[0] != '*')
-                                               {
-                                                       basepixels_width = tx->width;
-                                                       basepixels_height = tx->height;
-                                                       basepixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4);
-                                                       Image_Copy8bitRGBA(mtdata, basepixels, basepixels_width * basepixels_height, palette_nofullbrights);
-                                                       if (!glowpixels)
-                                                       {
-                                                               for (j = 0;j < (int)(tx->width*tx->height);j++)
-                                                                       if (((qbyte *)&palette_onlyfullbrights[mtdata[j]])[3] > 0) // fullbright
-                                                                               break;
-                                                               if (j < (int)(tx->width * tx->height))
-                                                               {
-                                                                       glowpixels_width = tx->width;
-                                                                       glowpixels_height = tx->height;
-                                                                       glowpixels = Mem_Alloc(loadmodel->mempool, glowpixels_width * glowpixels_height * 4);
-                                                                       Image_Copy8bitRGBA(mtdata, glowpixels, glowpixels_width * glowpixels_height, palette_onlyfullbrights);
-                                                               }
-                                                       }
-                                               }
-                                               else
-                                               {
-                                                       basepixels_width = tx->width;
-                                                       basepixels_height = tx->height;
-                                                       basepixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4);
-                                                       Image_Copy8bitRGBA(mtdata, basepixels, tx->width * tx->height, palette_complete);
-                                               }
-                                       }
-                               }
-                       }
-               }
-
-               if (basepixels)
-               {
-                       for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
-                               if (basepixels[j] < 255)
-                                       break;
-                       if (j < basepixels_width * basepixels_height * 4)
-                       {
-                               maskpixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4);
-                               maskpixels_width = basepixels_width;
-                               maskpixels_height = basepixels_height;
-                               for (j = 0;j < basepixels_width * basepixels_height * 4;j += 4)
-                               {
-                                       maskpixels[j+0] = 255;
-                                       maskpixels[j+1] = 255;
-                                       maskpixels[j+2] = 255;
-                                       maskpixels[j+3] = basepixels[j+3];
+                                       if (freepixels)
+                                               Mem_Free(freepixels);
                                }
-                       }
-
-                       if (!bumppixels)
-                       {
-                               bumppixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4);
-                               bumppixels_width = basepixels_width;
-                               bumppixels_height = basepixels_height;
-                               memcpy(bumppixels, basepixels, bumppixels_width * bumppixels_height * 4);
-                       }
-
-                       if (!nmappixels && bumppixels)
-                       {
-                               nmappixels = Mem_Alloc(loadmodel->mempool, bumppixels_width * bumppixels_height * 4);
-                               nmappixels_width = bumppixels_width;
-                               nmappixels_height = bumppixels_height;
-                               Image_HeightmapToNormalmap(bumppixels, nmappixels, nmappixels_width, nmappixels_height, false, 1);
+                               else if (mtdata) // texture included
+                                       Mod_LoadSkinFrame_Internal(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, false, true, tx->name[0] != '*' && r_fullbrights.integer, mtdata, tx->width, tx->height);
                        }
                }
-
-               if (!detailtexture)
-                       detailtexture = detailtextures[i % NUM_DETAILTEXTURES];
-
-               if (basepixels)
-               {
-                       tx->texture = R_LoadTexture2D (loadmodel->texturepool, tx->name, basepixels_width, basepixels_height, basepixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
-                       if (nmappixels)
-                               tx->nmaptexture = R_LoadTexture2D (loadmodel->texturepool, va("%s_nmap", tx->name), basepixels_width, basepixels_height, nmappixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
-                       if (glosspixels)
-                               tx->glosstexture = R_LoadTexture2D (loadmodel->texturepool, va("%s_gloss", tx->name), glosspixels_width, glosspixels_height, glosspixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
-                       if (glowpixels)
-                               tx->glowtexture = R_LoadTexture2D (loadmodel->texturepool, va("%s_glow", tx->name), glowpixels_width, glowpixels_height, glowpixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
-                       if (maskpixels)
-                               tx->fogtexture = R_LoadTexture2D (loadmodel->texturepool, va("%s_mask", tx->name), maskpixels_width, maskpixels_height, maskpixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
-                       tx->detailtexture = detailtexture;
-               }
-               else
+               if (tx->skin.base == NULL)
                {
                        // no texture found
                        tx->width = 16;
                        tx->height = 16;
-                       tx->texture = r_notexture;
-                       tx->nmaptexture = NULL;
-                       tx->glosstexture = NULL;
-                       tx->glowtexture = NULL;
-                       tx->fogtexture = NULL;
-                       tx->detailtexture = NULL;
-               }
-
-               if (basepixels)
-                       Mem_Free(basepixels);
-               if (bumppixels)
-                       Mem_Free(bumppixels);
-               if (nmappixels)
-                       Mem_Free(nmappixels);
-               if (glosspixels)
-                       Mem_Free(glosspixels);
-               if (glowpixels)
-                       Mem_Free(glowpixels);
-               if (maskpixels)
-                       Mem_Free(maskpixels);
+                       tx->skin.base = r_notexture;
+               }
 
                if (tx->name[0] == '*')
                {
+                       // turb does not block movement
+                       tx->flags &= ~SURF_SOLIDCLIP;
                        tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
                        // LordHavoc: some turbulent textures should be fullbright and solid
                        if (!strncmp(tx->name,"*lava",5)
@@ -507,7 +325,7 @@ static void Mod_LoadTextures (lump_t *l)
                else
                {
                        tx->flags |= SURF_LIGHTMAP;
-                       if (!tx->fogtexture)
+                       if (!tx->skin.fog)
                                tx->flags |= SURF_SHADOWCAST | SURF_SHADOWLIGHT;
                        tx->shader = &Cshader_wall_lightmap;
                }
@@ -648,7 +466,7 @@ static void Mod_LoadLighting (lump_t *l)
                                i = LittleLong(((int *)data)[1]);
                                if (i == 1)
                                {
-                                       Con_DPrintf("%s loaded", litfilename);
+                                       Con_DPrintf("loaded %s\n", litfilename);
                                        loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, loadsize - 8);
                                        memcpy(loadmodel->lightdata, data + 8, loadsize - 8);
                                        Mem_Free(data);
@@ -1241,58 +1059,6 @@ static void Mod_LoadTexinfo (lump_t *l)
        }
 }
 
-/*
-================
-CalcSurfaceExtents
-
-Fills in s->texturemins[] and s->extents[]
-================
-*/
-static void CalcSurfaceExtents (msurface_t *s)
-{
-       float   mins[2], maxs[2], val;
-       int             i,j, e;
-       mvertex_t       *v;
-       mtexinfo_t      *tex;
-       int             bmins[2], bmaxs[2];
-
-       mins[0] = mins[1] = 999999999;
-       maxs[0] = maxs[1] = -999999999;
-
-       tex = s->texinfo;
-
-       for (i=0 ; i<s->numedges ; i++)
-       {
-               e = loadmodel->surfedges[s->firstedge+i];
-               if (e >= 0)
-                       v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
-               else
-                       v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
-
-               for (j=0 ; j<2 ; j++)
-               {
-                       val = v->position[0] * tex->vecs[j][0] +
-                               v->position[1] * tex->vecs[j][1] +
-                               v->position[2] * tex->vecs[j][2] +
-                               tex->vecs[j][3];
-                       if (val < mins[j])
-                               mins[j] = val;
-                       if (val > maxs[j])
-                               maxs[j] = val;
-               }
-       }
-
-       for (i=0 ; i<2 ; i++)
-       {
-               bmins[i] = floor(mins[i]/16);
-               bmaxs[i] = ceil(maxs[i]/16);
-
-               s->texturemins[i] = bmins[i] * 16;
-               s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
-       }
-}
-
-
 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
 {
        int             i, j;
@@ -1588,17 +1354,18 @@ void Mod_GenerateVertexMesh (msurface_t *surf)
        Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->verts, mesh->str, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals);
 }
 
-void Mod_GenerateSurfacePolygon (msurface_t *surf)
+void Mod_GenerateSurfacePolygon (msurface_t *surf, int firstedge, int numedges)
 {
-       int i, lindex;
-       float *vec, *vert, mins[3], maxs[3];
+       int i, lindex, j;
+       float *vec, *vert, mins[3], maxs[3], val, *v;
+       mtexinfo_t *tex;
 
        // convert edges back to a normal polygon
-       surf->poly_numverts = surf->numedges;
-       vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * surf->numedges);
-       for (i = 0;i < surf->numedges;i++)
+       surf->poly_numverts = numedges;
+       vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * numedges);
+       for (i = 0;i < numedges;i++)
        {
-               lindex = loadmodel->surfedges[surf->firstedge + i];
+               lindex = loadmodel->surfedges[firstedge + i];
                if (lindex > 0)
                        vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
                else
@@ -1606,6 +1373,8 @@ void Mod_GenerateSurfacePolygon (msurface_t *surf)
                VectorCopy (vec, vert);
                vert += 3;
        }
+
+       // calculate polygon bounding box and center
        vert = surf->poly_verts;
        VectorCopy(vert, mins);
        VectorCopy(vert, maxs);
@@ -1621,6 +1390,27 @@ void Mod_GenerateSurfacePolygon (msurface_t *surf)
        surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
        surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
        surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
+
+       // generate surface extents information
+       tex = surf->texinfo;
+       mins[0] = maxs[0] = DotProduct(surf->poly_verts, tex->vecs[0]) + tex->vecs[0][3];
+       mins[1] = maxs[1] = DotProduct(surf->poly_verts, tex->vecs[1]) + tex->vecs[1][3];
+       for (i = 1, v = surf->poly_verts + 3;i < surf->poly_numverts;i++, v += 3)
+       {
+               for (j = 0;j < 2;j++)
+               {
+                       val = DotProduct(v, tex->vecs[j]) + tex->vecs[j][3];
+                       if (mins[j] > val)
+                               mins[j] = val;
+                       if (maxs[j] < val)
+                               maxs[j] = val;
+               }
+       }
+       for (i = 0;i < 2;i++)
+       {
+               surf->texturemins[i] = (int) floor(mins[i] / 16) * 16;
+               surf->extents[i] = (int) ceil(maxs[i] / 16) * 16 - surf->texturemins[i];
+       }
 }
 
 /*
@@ -1632,7 +1422,7 @@ static void Mod_LoadFaces (lump_t *l)
 {
        dface_t *in;
        msurface_t      *out;
-       int i, count, surfnum, planenum, ssize, tsize;
+       int i, count, surfnum, planenum, ssize, tsize, firstedge, numedges;
 
        in = (void *)(mod_base + l->fileofs);
        if (l->filelen % sizeof(*in))
@@ -1650,10 +1440,10 @@ static void Mod_LoadFaces (lump_t *l)
        {
                out->number = surfnum;
                // FIXME: validate edges, texinfo, etc?
-               out->firstedge = LittleLong(in->firstedge);
-               out->numedges = LittleShort(in->numedges);
-               if ((unsigned int) out->firstedge + (unsigned int) out->numedges > (unsigned int) loadmodel->numsurfedges)
-                       Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", out->firstedge, out->numedges, loadmodel->numsurfedges);
+               firstedge = LittleLong(in->firstedge);
+               numedges = LittleShort(in->numedges);
+               if ((unsigned int) firstedge + (unsigned int) numedges > (unsigned int) loadmodel->numsurfedges)
+                       Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", firstedge, numedges, loadmodel->numsurfedges);
 
                i = LittleShort (in->texinfo);
                if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo)
@@ -1676,7 +1466,7 @@ static void Mod_LoadFaces (lump_t *l)
                // force lightmap upload on first time seeing the surface
                out->cached_dlight = true;
 
-               CalcSurfaceExtents (out);
+               Mod_GenerateSurfacePolygon(out, firstedge, numedges);
 
                ssize = (out->extents[0] >> 4) + 1;
                tsize = (out->extents[1] >> 4) + 1;
@@ -1692,7 +1482,6 @@ static void Mod_LoadFaces (lump_t *l)
                else // LordHavoc: white lighting (bsp version 29)
                        out->samples = loadmodel->lightdata + (i * 3);
 
-               Mod_GenerateSurfacePolygon(out);
                if (out->texinfo->texture->shader == &Cshader_wall_lightmap)
                {
                        if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256))
@@ -2836,15 +2625,18 @@ Mod_LoadBrushModel
 extern void R_Model_Brush_DrawSky(entity_render_t *ent);
 extern void R_Model_Brush_Draw(entity_render_t *ent);
 extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
-extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor);
+extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
 void Mod_LoadBrushModel (model_t *mod, void *buffer)
 {
-       int                     i, j;
-       dheader_t       *header;
-       dmodel_t        *bm;
-       mempool_t       *mainmempool;
-       char            *loadname;
-       model_t         *originalloadmodel;
+       int i, j, k;
+       dheader_t *header;
+       dmodel_t *bm;
+       mempool_t *mainmempool;
+       char *loadname;
+       model_t *originalloadmodel;
+       float dist, modelyawradius, modelradius, *vec;
+       msurface_t *surf;
+       surfmesh_t *mesh;
 
        mod->type = mod_brush;
 
@@ -2904,10 +2696,6 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer)
 //
        for (i = 0;i < mod->numsubmodels;i++)
        {
-               int k, l;
-               float dist, modelyawradius, modelradius, *vec;
-               msurface_t *surf;
-
                bm = &mod->submodels[i];
 
                mod->hulls[0].firstclipnode = bm->headnode[0];
@@ -2943,26 +2731,27 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer)
                                // we only need to have a drawsky function if it is used (usually only on world model)
                                if (surf->texinfo->texture->shader == &Cshader_sky)
                                        mod->DrawSky = R_Model_Brush_DrawSky;
+                               // LordHavoc: submodels always clip, even if water
+                               if (mod->numsubmodels - 1)
+                                       surf->flags |= SURF_SOLIDCLIP;
                                // calculate bounding shapes
-                               for (k = 0;k < surf->numedges;k++)
+                               for (mesh = surf->mesh;mesh;mesh = mesh->chain)
                                {
-                                       l = mod->surfedges[k + surf->firstedge];
-                                       if (l > 0)
-                                               vec = mod->vertexes[mod->edges[l].v[0]].position;
-                                       else
-                                               vec = mod->vertexes[mod->edges[-l].v[1]].position;
-                                       if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
-                                       if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
-                                       if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
-                                       if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
-                                       if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
-                                       if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
-                                       dist = vec[0]*vec[0]+vec[1]*vec[1];
-                                       if (modelyawradius < dist)
-                                               modelyawradius = dist;
-                                       dist += vec[2]*vec[2];
-                                       if (modelradius < dist)
-                                               modelradius = dist;
+                                       for (k = 0, vec = mesh->verts;k < mesh->numverts;k++, vec += 4)
+                                       {
+                                               if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
+                                               if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
+                                               if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
+                                               if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
+                                               if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
+                                               if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
+                                               dist = vec[0]*vec[0]+vec[1]*vec[1];
+                                               if (modelyawradius < dist)
+                                                       modelyawradius = dist;
+                                               dist += vec[2]*vec[2];
+                                               if (modelradius < dist)
+                                                       modelradius = dist;
+                                       }
                                }
                        }
                        modelyawradius = sqrt(modelyawradius);