]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_brush.c
moved a number of msurface_t fields to a separate msurface_lightmapinfo_t structure...
[xonotic/darkplaces.git] / model_brush.c
index ec9f2a6a0abc8ddaf3159b674c803cdaece2be38..835098ec94d75cce3c255a7ea112d184f82a64ef 100644 (file)
@@ -26,8 +26,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "wad.h"
 
 
-// note: model_shared.c sets up r_notexture, and r_surf_notexture
-
 qbyte mod_q1bsp_novis[(MAX_MAP_LEAFS + 7)/ 8];
 
 //cvar_t r_subdivide_size = {CVAR_SAVE, "r_subdivide_size", "128"};
@@ -220,7 +218,7 @@ static void Mod_Q1BSP_FindNonSolidLocation_r_Leaf(findnonsolidlocationinfo_t *in
        for (surfacenum = 0, mark = leaf->firstleafsurface;surfacenum < leaf->numleafsurfaces;surfacenum++, mark++)
        {
                surface = info->model->brush.data_surfaces + *mark;
-               if (surface->flags & SURF_SOLIDCLIP)
+               if (surface->texture->supercontents & SUPERCONTENTS_SOLID)
                {
                        for (k = 0;k < surface->mesh.num_triangles;k++)
                        {
@@ -790,26 +788,26 @@ loc0:
                        surface = r_refdef.worldmodel->brush.data_surfaces + node->firstsurface;
                        for (i = 0;i < node->numsurfaces;i++, surface++)
                        {
-                               if (!(surface->texture->flags & SURF_LIGHTMAP) || !surface->samples)
+                               if (!(surface->texture->basematerialflags & MATERIALFLAG_WALL) || !surface->lightmapinfo->samples)
                                        continue;       // no lightmaps
 
-                               ds = (int) (x * surface->texinfo->vecs[0][0] + y * surface->texinfo->vecs[0][1] + mid * surface->texinfo->vecs[0][2] + surface->texinfo->vecs[0][3]) - surface->texturemins[0];
-                               dt = (int) (x * surface->texinfo->vecs[1][0] + y * surface->texinfo->vecs[1][1] + mid * surface->texinfo->vecs[1][2] + surface->texinfo->vecs[1][3]) - surface->texturemins[1];
+                               ds = (int) (x * surface->lightmapinfo->texinfo->vecs[0][0] + y * surface->lightmapinfo->texinfo->vecs[0][1] + mid * surface->lightmapinfo->texinfo->vecs[0][2] + surface->lightmapinfo->texinfo->vecs[0][3]) - surface->lightmapinfo->texturemins[0];
+                               dt = (int) (x * surface->lightmapinfo->texinfo->vecs[1][0] + y * surface->lightmapinfo->texinfo->vecs[1][1] + mid * surface->lightmapinfo->texinfo->vecs[1][2] + surface->lightmapinfo->texinfo->vecs[1][3]) - surface->lightmapinfo->texturemins[1];
 
-                               if (ds >= 0 && ds < surface->extents[0] && dt >= 0 && dt < surface->extents[1])
+                               if (ds >= 0 && ds < surface->lightmapinfo->extents[0] && dt >= 0 && dt < surface->lightmapinfo->extents[1])
                                {
                                        qbyte *lightmap;
                                        int lmwidth, lmheight, maps, line3, size3, dsfrac = ds & 15, dtfrac = dt & 15, scale = 0, r00 = 0, g00 = 0, b00 = 0, r01 = 0, g01 = 0, b01 = 0, r10 = 0, g10 = 0, b10 = 0, r11 = 0, g11 = 0, b11 = 0;
-                                       lmwidth = ((surface->extents[0]>>4)+1);
-                                       lmheight = ((surface->extents[1]>>4)+1);
+                                       lmwidth = ((surface->lightmapinfo->extents[0]>>4)+1);
+                                       lmheight = ((surface->lightmapinfo->extents[1]>>4)+1);
                                        line3 = lmwidth * 3; // LordHavoc: *3 for colored lighting
                                        size3 = lmwidth * lmheight * 3; // LordHavoc: *3 for colored lighting
 
-                                       lightmap = surface->samples + ((dt>>4) * lmwidth + (ds>>4))*3; // LordHavoc: *3 for colored lighting
+                                       lightmap = surface->lightmapinfo->samples + ((dt>>4) * lmwidth + (ds>>4))*3; // LordHavoc: *3 for colored lighting
 
-                                       for (maps = 0;maps < MAXLIGHTMAPS && surface->styles[maps] != 255;maps++)
+                                       for (maps = 0;maps < MAXLIGHTMAPS && surface->lightmapinfo->styles[maps] != 255;maps++)
                                        {
-                                               scale = d_lightstylevalue[surface->styles[maps]];
+                                               scale = d_lightstylevalue[surface->lightmapinfo->styles[maps]];
                                                r00 += lightmap[      0] * scale;g00 += lightmap[      1] * scale;b00 += lightmap[      2] * scale;
                                                r01 += lightmap[      3] * scale;g01 += lightmap[      4] * scale;b01 += lightmap[      5] * scale;
                                                r10 += lightmap[line3+0] * scale;g10 += lightmap[line3+1] * scale;b10 += lightmap[line3+2] * scale;
@@ -1008,11 +1006,18 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l)
                strcpy(tx->name, "NO TEXTURE FOUND");
                tx->width = 16;
                tx->height = 16;
-               tx->skin.base = r_notexture;
+               tx->skin.base = r_texture_notexture;
                if (i == loadmodel->brush.num_textures - 1)
-                       tx->flags = SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
+               {
+                       tx->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES;
+                       tx->supercontents = SUPERCONTENTS_WATER;
+               }
                else
-                       tx->flags = SURF_LIGHTMAP | SURF_SOLIDCLIP;
+               {
+                       tx->basematerialflags |= MATERIALFLAG_WALL;
+                       tx->supercontents = SUPERCONTENTS_SOLID;
+               }
+               tx->basematerialflags = 0;
                tx->currentframe = tx;
        }
 
@@ -1085,7 +1090,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l)
                }
                else
                {
-                       if (!Mod_LoadSkinFrame(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, true, true))
+                       if (!Mod_LoadSkinFrame(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, tx->name[0] != '*', true))
                        {
                                // did not find external texture, load it from the bsp or wad3
                                if (loadmodel->brush.ishlbsp)
@@ -1120,7 +1125,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l)
                                                Mem_Free(freepixels);
                                }
                                else if (mtdata) // texture included
-                                       Mod_LoadSkinFrame_Internal(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_PRECACHE | TEXF_PICMIP, false, true, tx->name[0] != '*' && r_fullbrights.integer, mtdata, tx->width, tx->height);
+                                       Mod_LoadSkinFrame_Internal(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_PRECACHE | TEXF_PICMIP, false, tx->name[0] != '*', tx->name[0] != '*' && r_fullbrights.integer, mtdata, tx->width, tx->height);
                        }
                }
                if (tx->skin.base == NULL)
@@ -1128,25 +1133,40 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l)
                        // no texture found
                        tx->width = 16;
                        tx->height = 16;
-                       tx->skin.base = r_notexture;
+                       tx->skin.base = r_texture_notexture;
                }
 
+               tx->basematerialflags = 0;
                if (tx->name[0] == '*')
                {
                        // turb does not block movement
-                       tx->flags = SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
+                       tx->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES;
                        // LordHavoc: some turbulent textures should be fullbright and solid
                        if (!strncmp(tx->name,"*lava",5)
                         || !strncmp(tx->name,"*teleport",9)
                         || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
-                               tx->flags |= SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA;
+                               tx->basematerialflags |= MATERIALFLAG_FULLBRIGHT;
                        else
-                               tx->flags |= SURF_WATERALPHA;
+                               tx->basematerialflags |= MATERIALFLAG_WATERALPHA;
+                       if (!strncmp(tx->name, "*lava", 5))
+                               tx->supercontents = SUPERCONTENTS_LAVA;
+                       else if (!strncmp(tx->name, "*slime", 6))
+                               tx->supercontents = SUPERCONTENTS_SLIME;
+                       else
+                               tx->supercontents = SUPERCONTENTS_WATER;
                }
                else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y')
-                       tx->flags = SURF_DRAWSKY | SURF_SOLIDCLIP;
+               {
+                       tx->supercontents = SUPERCONTENTS_SKY;
+                       tx->basematerialflags |= MATERIALFLAG_SKY;
+               }
                else
-                       tx->flags = SURF_LIGHTMAP | SURF_SOLIDCLIP;
+               {
+                       tx->supercontents = SUPERCONTENTS_SOLID;
+                       tx->basematerialflags |= MATERIALFLAG_WALL;
+               }
+               if (tx->skin.fog)
+                       tx->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT;
 
                // start out with no animation
                tx->currentframe = tx;
@@ -1576,7 +1596,7 @@ static void Mod_Q1BSP_LoadTexinfo(lump_t *l)
                {
                        // if texture chosen is NULL or the shader needs a lightmap,
                        // force to notexture water shader
-                       if (out->texture == NULL || out->texture->flags & SURF_LIGHTMAP)
+                       if (out->texture == NULL || out->texture->basematerialflags & MATERIALFLAG_WALL)
                                out->texture = loadmodel->brush.data_textures + (loadmodel->brush.num_textures - 1);
                }
                else
@@ -1734,8 +1754,8 @@ static void Mod_Q1BSP_GenerateWarpMesh(msurface_t *surface)
        for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
        {
                VectorCopy(subdivpolyvert[i], v->v);
-               v->st[0] = DotProduct(v->v, surface->texinfo->vecs[0]);
-               v->st[1] = DotProduct(v->v, surface->texinfo->vecs[1]);
+               v->st[0] = DotProduct(v->v, surface->lightmapinfo->texinfo->vecs[0]);
+               v->st[1] = DotProduct(v->v, surface->lightmapinfo->texinfo->vecs[1]);
        }
 }
 #endif
@@ -1752,6 +1772,7 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
                Host_Error("Mod_Q1BSP_LoadFaces: funny lump size in %s",loadmodel->name);
        count = l->filelen / sizeof(*in);
        loadmodel->brush.data_surfaces = Mem_Alloc(loadmodel->mempool, count*sizeof(msurface_t));
+       loadmodel->brush.data_surfaces_lightmapinfo = Mem_Alloc(loadmodel->mempool, count*sizeof(msurface_lightmapinfo_t));
 
        loadmodel->brush.num_surfaces = count;
 
@@ -1768,12 +1789,14 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
        // vertex limit
        loadmodel->nummeshes = 1;
        loadmodel->meshlist = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t *));
-       loadmodel->meshlist[0] = Mod_AllocSurfMesh(loadmodel->mempool, totalverts, totaltris, 0, 0, true, true, false);
+       loadmodel->meshlist[0] = Mod_AllocSurfMesh(loadmodel->mempool, totalverts, totaltris, true, true, false);
 
        totalverts = 0;
        totaltris = 0;
        for (surfacenum = 0, in = (void *)(mod_base + l->fileofs), surface = loadmodel->brush.data_surfaces;surfacenum < count;surfacenum++, in++, surface++)
        {
+               surface->lightmapinfo = loadmodel->brush.data_surfaces_lightmapinfo + surfacenum;
+
                // FIXME: validate edges, texinfo, etc?
                firstedge = LittleLong(in->firstedge);
                numedges = LittleShort(in->numedges);
@@ -1782,18 +1805,17 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
                i = LittleShort(in->texinfo);
                if ((unsigned int) i >= (unsigned int) loadmodel->brushq1.numtexinfo)
                        Host_Error("Mod_Q1BSP_LoadFaces: invalid texinfo index %i(model has %i texinfos)\n", i, loadmodel->brushq1.numtexinfo);
-               surface->texinfo = loadmodel->brushq1.texinfo + i;
-               surface->texture = surface->texinfo->texture;
-               surface->flags = surface->texture->flags;
+               surface->lightmapinfo->texinfo = loadmodel->brushq1.texinfo + i;
+               surface->texture = surface->lightmapinfo->texinfo->texture;
 
                planenum = LittleShort(in->planenum);
                if ((unsigned int) planenum >= (unsigned int) loadmodel->brush.num_planes)
                        Host_Error("Mod_Q1BSP_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->brush.num_planes);
 
-               if (LittleShort(in->side))
-                       surface->flags |= SURF_PLANEBACK;
-
-               surface->plane = loadmodel->brush.data_planes + planenum;
+               //surface->flags = surface->texture->flags;
+               //if (LittleShort(in->side))
+               //      surface->flags |= SURF_PLANEBACK;
+               //surface->plane = loadmodel->brush.data_planes + planenum;
 
                surface->mesh.num_vertices = numedges;
                surface->mesh.num_triangles = numedges - 2;
@@ -1819,8 +1841,8 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
                                VectorCopy(loadmodel->brushq1.vertexes[loadmodel->brushq1.edges[lindex].v[0]].position, surface->mesh.data_vertex3f + i * 3);
                        else
                                VectorCopy(loadmodel->brushq1.vertexes[loadmodel->brushq1.edges[-lindex].v[1]].position, surface->mesh.data_vertex3f + i * 3);
-                       s = DotProduct((surface->mesh.data_vertex3f + i * 3), surface->texinfo->vecs[0]) + surface->texinfo->vecs[0][3];
-                       t = DotProduct((surface->mesh.data_vertex3f + i * 3), surface->texinfo->vecs[1]) + surface->texinfo->vecs[1][3];
+                       s = DotProduct((surface->mesh.data_vertex3f + i * 3), surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3];
+                       t = DotProduct((surface->mesh.data_vertex3f + i * 3), surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3];
                        surface->mesh.data_texcoordtexture2f[i * 2 + 0] = s / surface->texture->width;
                        surface->mesh.data_texcoordtexture2f[i * 2 + 1] = t / surface->texture->height;
                        surface->mesh.data_texcoorddetail2f[i * 2 + 0] = s * (1.0f / 16.0f);
@@ -1843,67 +1865,73 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
                BoxFromPoints(surface->mins, surface->maxs, surface->mesh.num_vertices, surface->mesh.data_vertex3f);
 
                // generate surface extents information
-               texmins[0] = texmaxs[0] = DotProduct(surface->mesh.data_vertex3f, surface->texinfo->vecs[0]) + surface->texinfo->vecs[0][3];
-               texmins[1] = texmaxs[1] = DotProduct(surface->mesh.data_vertex3f, surface->texinfo->vecs[1]) + surface->texinfo->vecs[1][3];
+               texmins[0] = texmaxs[0] = DotProduct(surface->mesh.data_vertex3f, surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3];
+               texmins[1] = texmaxs[1] = DotProduct(surface->mesh.data_vertex3f, surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3];
                for (i = 1;i < surface->mesh.num_vertices;i++)
                {
                        for (j = 0;j < 2;j++)
                        {
-                               val = DotProduct(surface->mesh.data_vertex3f + i * 3, surface->texinfo->vecs[j]) + surface->texinfo->vecs[j][3];
+                               val = DotProduct(surface->mesh.data_vertex3f + 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);
                        }
                }
                for (i = 0;i < 2;i++)
                {
-                       surface->texturemins[i] = (int) floor(texmins[i] / 16.0) * 16;
-                       surface->extents[i] = (int) ceil(texmaxs[i] / 16.0) * 16 - surface->texturemins[i];
+                       surface->lightmapinfo->texturemins[i] = (int) floor(texmins[i] / 16.0) * 16;
+                       surface->lightmapinfo->extents[i] = (int) ceil(texmaxs[i] / 16.0) * 16 - surface->lightmapinfo->texturemins[i];
                }
 
-               smax = surface->extents[0] >> 4;
-               tmax = surface->extents[1] >> 4;
-               ssize = (surface->extents[0] >> 4) + 1;
-               tsize = (surface->extents[1] >> 4) + 1;
+               smax = surface->lightmapinfo->extents[0] >> 4;
+               tmax = surface->lightmapinfo->extents[1] >> 4;
+               ssize = (surface->lightmapinfo->extents[0] >> 4) + 1;
+               tsize = (surface->lightmapinfo->extents[1] >> 4) + 1;
 
                // lighting info
                for (i = 0;i < MAXLIGHTMAPS;i++)
-                       surface->styles[i] = in->styles[i];
+                       surface->lightmapinfo->styles[i] = in->styles[i];
                // force lightmap upload on first time seeing the surface
                surface->cached_dlight = true;
-               surface->lightmaptexturestride = 0;
+               surface->lightmapinfo->lightmaptexturestride = 0;
                surface->lightmaptexture = NULL;
                i = LittleLong(in->lightofs);
                if (i == -1)
-                       surface->samples = NULL;
+               {
+                       surface->lightmapinfo->samples = NULL;
+                       // give non-lightmapped water a 1x white lightmap
+                       if ((surface->texture->basematerialflags & MATERIALFLAG_WATER) && (surface->lightmapinfo->texinfo->flags & TEX_SPECIAL) && ssize <= 256 && tsize <= 256)
+                       {
+                               surface->lightmapinfo->samples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
+                               surface->lightmapinfo->styles[0] = 0;
+                               memset(surface->lightmapinfo->samples, 128, ssize * tsize * 3);
+                       }
+               }
                else if (loadmodel->brush.ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
-                       surface->samples = loadmodel->brushq1.lightdata + i;
+                       surface->lightmapinfo->samples = loadmodel->brushq1.lightdata + i;
                else // LordHavoc: white lighting (bsp version 29)
-                       surface->samples = loadmodel->brushq1.lightdata + (i * 3);
+                       surface->lightmapinfo->samples = loadmodel->brushq1.lightdata + (i * 3);
 
-               if (surface->texture->flags & SURF_LIGHTMAP)
+               if (!(surface->lightmapinfo->texinfo->flags & TEX_SPECIAL) || surface->lightmapinfo->samples)
                {
+                       int i, iu, iv;
+                       float u, v, ubase, vbase, uscale, vscale;
+
                        if (ssize > 256 || tsize > 256)
                                Host_Error("Bad surface extents");
                        // stainmap for permanent marks on walls
-                       surface->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
+                       surface->lightmapinfo->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
                        // clear to white
-                       memset(surface->stainsamples, 255, ssize * tsize * 3);
-               }
-
-               if (surface->texture->flags & SURF_LIGHTMAP)
-               {
-                       int i, iu, iv;
-                       float u, v, ubase, vbase, uscale, vscale;
+                       memset(surface->lightmapinfo->stainsamples, 255, ssize * tsize * 3);
 
                        if (r_miplightmaps.integer)
                        {
-                               surface->lightmaptexturestride = ssize;
-                               surface->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surface->lightmaptexturestride, tsize, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP | TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+                               surface->lightmapinfo->lightmaptexturestride = ssize;
+                               surface->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surface->lightmapinfo->lightmaptexturestride, tsize, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP | TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
                        }
                        else
                        {
-                               surface->lightmaptexturestride = R_CompatibleFragmentWidth(ssize, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
-                               surface->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surface->lightmaptexturestride, tsize, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+                               surface->lightmapinfo->lightmaptexturestride = R_CompatibleFragmentWidth(ssize, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
+                               surface->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surface->lightmapinfo->lightmaptexturestride, tsize, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
                        }
                        R_FragmentLocation(surface->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
                        uscale = (uscale - ubase) / ssize;
@@ -1911,8 +1939,8 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
 
                        for (i = 0;i < surface->mesh.num_vertices;i++)
                        {
-                               u = ((DotProduct((surface->mesh.data_vertex3f + i * 3), surface->texinfo->vecs[0]) + surface->texinfo->vecs[0][3]) + 8 - surface->texturemins[0]) * (1.0 / 16.0);
-                               v = ((DotProduct((surface->mesh.data_vertex3f + i * 3), surface->texinfo->vecs[1]) + surface->texinfo->vecs[1][3]) + 8 - surface->texturemins[1]) * (1.0 / 16.0);
+                               u = ((DotProduct((surface->mesh.data_vertex3f + 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->mesh.data_vertex3f + i * 3), surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3]) + 8 - surface->lightmapinfo->texturemins[1]) * (1.0 / 16.0);
                                surface->mesh.data_texcoordlightmap2f[i * 2 + 0] = u * uscale + ubase;
                                surface->mesh.data_texcoordlightmap2f[i * 2 + 1] = v * vscale + vbase;
                                // LordHavoc: calc lightmap data offset for vertex lighting to use
@@ -2716,7 +2744,7 @@ static void Mod_Q1BSP_BuildLightmapUpdateChains(mempool_t *mempool, model_t *mod
        {
                surface = model->brush.data_surfaces + model->firstmodelsurface + i;
                for (j = 0;j < MAXLIGHTMAPS;j++)
-                       stylecounts[surface->styles[j]]++;
+                       stylecounts[surface->lightmapinfo->styles[j]]++;
        }
        totalcount = 0;
        model->brushq1.light_styles = 0;
@@ -2748,8 +2776,8 @@ static void Mod_Q1BSP_BuildLightmapUpdateChains(mempool_t *mempool, model_t *mod
        {
                surface = model->brush.data_surfaces + model->firstmodelsurface + i;
                for (j = 0;j < MAXLIGHTMAPS;j++)
-                       if (surface->styles[j] != 255)
-                               *model->brushq1.light_styleupdatechains[remapstyles[surface->styles[j]]]++ = surface;
+                       if (surface->lightmapinfo->styles[j] != 255)
+                               *model->brushq1.light_styleupdatechains[remapstyles[surface->lightmapinfo->styles[j]]]++ = surface;
        }
        j = 0;
        for (i = 0;i < model->brushq1.light_styles;i++)
@@ -2853,7 +2881,7 @@ static void Mod_Q1BSP_RoundUpToHullSize(model_t *cmodel, const vec3_t inmins, co
 extern void R_Q1BSP_DrawSky(entity_render_t *ent);
 extern void R_Q1BSP_Draw(entity_render_t *ent);
 extern void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outclusterlist, qbyte *outclusterpvs, int *outnumclusterspointer, int *outsurfacelist, qbyte *outsurfacepvs, int *outnumsurfacespointer);
-extern void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist);
+extern void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs);
 extern void R_Q1BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int numsurfaces, const int *surfacelist);
 void Mod_Q1BSP_Load(model_t *mod, void *buffer)
 {
@@ -2957,6 +2985,14 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer)
        if (loadmodel->brush.numsubmodels)
                loadmodel->brush.submodels = Mem_Alloc(loadmodel->mempool, loadmodel->brush.numsubmodels * sizeof(model_t *));
 
+       if (loadmodel->isworldmodel)
+       {
+               // clear out any stale submodels or worldmodels lying around
+               // if we did this clear before now, an error might abort loading and
+               // leave things in a bad state
+               Mod_RemoveStaleWorldModels(loadmodel);
+       }
+
        // LordHavoc: to clear the fog around the original quake submodel code, I
        // will explain:
        // first of all, some background info on the submodels:
@@ -3044,11 +3080,8 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer)
                        for (j = 0, surface = &mod->brush.data_surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surface++)
                        {
                                // we only need to have a drawsky function if it is used(usually only on world model)
-                               if (surface->texture->flags & SURF_DRAWSKY)
+                               if (surface->texture->basematerialflags & MATERIALFLAG_SKY)
                                        mod->DrawSky = R_Q1BSP_DrawSky;
-                               // LordHavoc: submodels always clip, even if water
-                               if (i)
-                                       surface->flags |= SURF_SOLIDCLIP;
                                // calculate bounding shapes
                                for (k = 0, vec = surface->mesh.data_vertex3f;k < surface->mesh.num_vertices;k++, vec += 3)
                                {
@@ -3784,6 +3817,23 @@ static void Mod_Q3BSP_LoadTextures(lump_t *l)
                                                        {
                                                                out->surfaceparms = flags;
                                                                out->textureflags = flags2;
+                                                               out->basematerialflags = 0;
+                                                               if (out->surfaceparms & Q3SURFACEPARM_NODRAW)
+                                                                       out->basematerialflags |= MATERIALFLAG_NODRAW;
+                                                               else if (out->surfaceparms & Q3SURFACEPARM_SKY)
+                                                                       out->basematerialflags |= MATERIALFLAG_SKY;
+                                                               else if (out->surfaceparms & Q3SURFACEPARM_LAVA)
+                                                                       out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_FULLBRIGHT;
+                                                               else if (out->surfaceparms & Q3SURFACEPARM_SLIME)
+                                                                       out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_WATERALPHA;
+                                                               else if (out->surfaceparms & Q3SURFACEPARM_WATER)
+                                                                       out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_WATERALPHA;
+                                                               else
+                                                                       out->basematerialflags |= MATERIALFLAG_WALL;
+                                                               if (out->surfaceparms & Q3SURFACEPARM_TRANS)
+                                                                       out->basematerialflags |= MATERIALFLAG_TRANSPARENT;
+                                                               if (out->textureflags & Q3TEXTUREFLAG_ADDITIVE)
+                                                                       out->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_TRANSPARENT;
                                                                strlcpy(out->firstpasstexturename, firstpasstexturename, sizeof(out->firstpasstexturename));
                                                                if ((flags & Q3SURFACEPARM_SKY) && sky[0])
                                                                {
@@ -3813,6 +3863,12 @@ parseerror:
                        c++;
                        Con_DPrintf("%s: No shader found for texture \"%s\"\n", loadmodel->name, out->name);
                        out->surfaceparms = 0;
+                       if (out->surfaceflags & Q3SURFACEFLAG_NODRAW)
+                               out->basematerialflags |= MATERIALFLAG_NODRAW;
+                       else if (out->surfaceflags & Q3SURFACEFLAG_SKY)
+                               out->basematerialflags |= MATERIALFLAG_SKY;
+                       else
+                               out->basematerialflags |= MATERIALFLAG_WALL;
                        // these are defaults
                        //if (!strncmp(out->name, "textures/skies/", 15))
                        //      out->surfaceparms |= Q3SURFACEPARM_SKY;
@@ -3822,9 +3878,13 @@ parseerror:
                        //if (R_TextureHasAlpha(out->skin.base))
                        //      out->surfaceparms |= Q3SURFACEPARM_TRANS;
                }
-               if (!Mod_LoadSkinFrame(&out->skin, out->name, (((out->textureflags & Q3TEXTUREFLAG_NOMIPMAPS) || (out->surfaceparms & Q3SURFACEPARM_NOMIPMAPS)) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (out->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP), false, true, true))
-                       if (!Mod_LoadSkinFrame(&out->skin, out->firstpasstexturename, (((out->textureflags & Q3TEXTUREFLAG_NOMIPMAPS) || (out->surfaceparms & Q3SURFACEPARM_NOMIPMAPS)) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (out->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP), false, true, true))
+               if (!Mod_LoadSkinFrame(&out->skin, out->name, (((out->textureflags & Q3TEXTUREFLAG_NOMIPMAPS) || (out->surfaceparms & Q3SURFACEPARM_NOMIPMAPS)) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (out->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP), false, false, true))
+                       if (!Mod_LoadSkinFrame(&out->skin, out->firstpasstexturename, (((out->textureflags & Q3TEXTUREFLAG_NOMIPMAPS) || (out->surfaceparms & Q3SURFACEPARM_NOMIPMAPS)) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (out->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP), false, false, true))
                                Con_Printf("%s: texture loading for shader \"%s\" failed (first layer \"%s\" not found either)\n", loadmodel->name, out->name, out->firstpasstexturename);
+               if (out->skin.fog)
+                       out->basematerialflags |= (MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT);
+               // no animation
+               out->currentframe = out;
        }
        if (c)
                Con_DPrintf("%s: %i textures missing shaders\n", loadmodel->name, c);
@@ -4190,7 +4250,7 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l)
                i = oldi;
                in = oldin;
                out = oldout;
-               mesh = tempmeshlist[meshnum] = Mod_AllocSurfMesh(loadmodel->mempool, meshvertices, meshtriangles, 0, 0, false, false, true);
+               mesh = tempmeshlist[meshnum] = Mod_AllocSurfMesh(loadmodel->mempool, meshvertices, meshtriangles, false, false, true);
                meshvertices = 0;
                meshtriangles = 0;
                for (;i < count && meshvertices + out->mesh.num_vertices <= mesh->num_vertices;i++, in++, out++)
@@ -4299,21 +4359,21 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l)
                                finalvertices = finalwidth * finalheight;
                                finaltriangles = (finalwidth - 1) * (finalheight - 1) * 2;
 
-                               out->mesh.data_collisionvertex3f = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * finalvertices);
-                               out->mesh.data_collisionelement3i = Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * finaltriangles);
-                               out->mesh.num_collisionvertices = finalvertices;
-                               out->mesh.num_collisiontriangles = finaltriangles;
-                               Q3PatchTesselateFloat(3, sizeof(float[3]), out->mesh.data_collisionvertex3f, patchsize[0], patchsize[1], sizeof(float[3]), originalvertex3f, xtess, ytess);
-                               Q3PatchTriangleElements(out->mesh.data_collisionelement3i, finalwidth, finalheight);
+                               out->data_collisionvertex3f = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * finalvertices);
+                               out->data_collisionelement3i = 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);
 
                                //Mod_SnapVertices(3, out->mesh.num_vertices, out->mesh.data_vertex3f, 0.25);
-                               Mod_SnapVertices(3, out->mesh.num_collisionvertices, out->mesh.data_collisionvertex3f, 1);
+                               Mod_SnapVertices(3, out->num_collisionvertices, out->data_collisionvertex3f, 1);
 
                                oldnumtriangles = out->mesh.num_triangles;
-                               oldnumtriangles2 = out->mesh.num_collisiontriangles;
-                               out->mesh.num_collisiontriangles = Mod_RemoveDegenerateTriangles(out->mesh.num_collisiontriangles, out->mesh.data_collisionelement3i, out->mesh.data_collisionelement3i, out->mesh.data_collisionvertex3f);
+                               oldnumtriangles2 = out->num_collisiontriangles;
+                               out->num_collisiontriangles = Mod_RemoveDegenerateTriangles(out->num_collisiontriangles, out->data_collisionelement3i, out->data_collisionelement3i, out->data_collisionvertex3f);
                                if (developer.integer)
-                                       Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve became %i:%i vertices / %i:%i triangles (%i:%i degenerate)\n", patchsize[0], patchsize[1], out->mesh.num_vertices, out->mesh.num_collisionvertices, oldnumtriangles, oldnumtriangles2, oldnumtriangles - out->mesh.num_triangles, oldnumtriangles2 - out->mesh.num_collisiontriangles);
+                                       Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve became %i:%i vertices / %i:%i triangles (%i:%i degenerate)\n", patchsize[0], patchsize[1], out->mesh.num_vertices, out->num_collisionvertices, oldnumtriangles, oldnumtriangles2, oldnumtriangles - out->mesh.num_triangles, oldnumtriangles2 - out->num_collisiontriangles);
                                break;
                        default:
                                break;
@@ -4361,6 +4421,11 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l)
                                out->maxs[1] += 1.0f;
                                out->maxs[2] += 1.0f;
                        }
+                       // 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;
                }
        }
 
@@ -4810,10 +4875,10 @@ static void Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace_t *trace, model_t *model,
                for (i = 0;i < leaf->numleafsurfaces;i++)
                {
                        surface = model->brush.data_surfaces + leaf->firstleafsurface[i];
-                       if (surface->mesh.num_collisiontriangles && surface->collisionmarkframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, surface->mins, surface->maxs))
+                       if (surface->num_collisiontriangles && surface->collisionmarkframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, surface->mins, surface->maxs))
                        {
                                surface->collisionmarkframe = markframe;
-                               Collision_TraceLineTriangleMeshFloat(trace, linestart, lineend, surface->mesh.num_collisiontriangles, surface->mesh.data_collisionelement3i, surface->mesh.data_collisionvertex3f, surface->texture->supercontents, segmentmins, segmentmaxs);
+                               Collision_TraceLineTriangleMeshFloat(trace, linestart, lineend, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->texture->supercontents, segmentmins, segmentmaxs);
                                if (startfrac > trace->realfraction)
                                        return;
                        }
@@ -5190,10 +5255,10 @@ static void Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace_t *trace, model_t *model
                for (i = 0;i < leaf->numleafsurfaces;i++)
                {
                        surface = model->brush.data_surfaces + leaf->firstleafsurface[i];
-                       if (surface->mesh.num_collisiontriangles && surface->collisionmarkframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, surface->mins, surface->maxs))
+                       if (surface->num_collisiontriangles && surface->collisionmarkframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, surface->mins, surface->maxs))
                        {
                                surface->collisionmarkframe = markframe;
-                               Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, surface->mesh.num_collisiontriangles, surface->mesh.data_collisionelement3i, surface->mesh.data_collisionvertex3f, surface->texture->supercontents, segmentmins, segmentmaxs);
+                               Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->texture->supercontents, segmentmins, segmentmaxs);
                        }
                }
        }
@@ -5244,8 +5309,8 @@ static void Mod_Q3BSP_TraceBox(model_t *model, int frame, trace_t *trace, const
                                                Collision_TraceLineBrushFloat(trace, boxstartmins, boxendmins, brush->colbrushf, brush->colbrushf);
                                if (mod_q3bsp_curves_collisions.integer)
                                        for (i = 0, surface = model->brush.data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
-                                               if (surface->mesh.num_collisiontriangles)
-                                                       Collision_TraceLineTriangleMeshFloat(trace, boxstartmins, boxendmins, surface->mesh.num_collisiontriangles, surface->mesh.data_collisionelement3i, surface->mesh.data_collisionvertex3f, surface->texture->supercontents, segmentmins, segmentmaxs);
+                                               if (surface->num_collisiontriangles)
+                                                       Collision_TraceLineTriangleMeshFloat(trace, boxstartmins, boxendmins, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->texture->supercontents, segmentmins, segmentmaxs);
                        }
                        else
                                Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, model, model->brush.data_nodes, boxstartmins, boxendmins, 0, 1, boxstartmins, boxendmins, ++markframe, segmentmins, segmentmaxs);
@@ -5263,8 +5328,8 @@ static void Mod_Q3BSP_TraceBox(model_t *model, int frame, trace_t *trace, const
                                        Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, brush->colbrushf, brush->colbrushf);
                        if (mod_q3bsp_curves_collisions.integer)
                                for (i = 0, surface = model->brush.data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
-                                       if (surface->mesh.num_collisiontriangles)
-                                               Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, surface->mesh.num_collisiontriangles, surface->mesh.data_collisionelement3i, surface->mesh.data_collisionvertex3f, surface->texture->supercontents, segmentmins, segmentmaxs);
+                                       if (surface->num_collisiontriangles)
+                                               Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->texture->supercontents, segmentmins, segmentmaxs);
                }
                else
                        Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, model, model->brush.data_nodes, thisbrush_start, thisbrush_end, ++markframe, segmentmins, segmentmaxs);
@@ -5324,11 +5389,6 @@ void Mod_Q3BSP_RecursiveFindNumLeafs(mnode_t *node)
                loadmodel->brush.num_leafs = numleafs;
 }
 
-extern void R_Q3BSP_DrawSky(struct entity_render_s *ent);
-extern void R_Q3BSP_Draw(struct entity_render_s *ent);
-extern void R_Q3BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outclusterlist, qbyte *outclusterpvs, int *outnumclusterspointer, int *outsurfacelist, qbyte *outsurfacepvs, int *outnumsurfacespointer);
-extern void R_Q3BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist);
-extern void R_Q3BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int numsurfaces, const int *surfacelist);
 void Mod_Q3BSP_Load(model_t *mod, void *buffer)
 {
        int i, j, numshadowmeshtriangles;
@@ -5358,11 +5418,10 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer)
        mod->brush.BoxTouchingVisibleLeafs = Mod_Q1BSP_BoxTouchingVisibleLeafs;
        mod->brush.LightPoint = Mod_Q3BSP_LightPoint;
        mod->brush.FindNonSolidLocation = Mod_Q1BSP_FindNonSolidLocation;
-       //mod->DrawSky = R_Q3BSP_DrawSky;
-       mod->Draw = R_Q3BSP_Draw;
-       mod->GetLightInfo = R_Q3BSP_GetLightInfo;
-       mod->DrawShadowVolume = R_Q3BSP_DrawShadowVolume;
-       mod->DrawLight = R_Q3BSP_DrawLight;
+       mod->Draw = R_Q1BSP_Draw;
+       mod->GetLightInfo = R_Q1BSP_GetLightInfo;
+       mod->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
+       mod->DrawLight = R_Q1BSP_DrawLight;
 
        mod_base = (qbyte *)header;
 
@@ -5410,6 +5469,14 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer)
        loadmodel->brush.num_leafs = 0;
        Mod_Q3BSP_RecursiveFindNumLeafs(loadmodel->brush.data_nodes);
 
+       if (loadmodel->isworldmodel)
+       {
+               // clear out any stale submodels or worldmodels lying around
+               // if we did this clear before now, an error might abort loading and
+               // leave things in a bad state
+               Mod_RemoveStaleWorldModels(loadmodel);
+       }
+
        mod = loadmodel;
        for (i = 0;i < loadmodel->brush.numsubmodels;i++)
        {
@@ -5467,7 +5534,7 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer)
                        if (mod->brush.data_surfaces[j + mod->firstmodelsurface].texture->surfaceflags & Q3SURFACEFLAG_SKY)
                                break;
                if (j < mod->nummodelsurfaces)
-                       mod->DrawSky = R_Q3BSP_DrawSky;
+                       mod->DrawSky = R_Q1BSP_DrawSky;
        }
 }