]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_brush.c
model_vbsp: Move magic header define to its appropriate place
[xonotic/darkplaces.git] / model_brush.c
index b56321f51ad3da6d57cb59f8386550b958c36187..47e16229ad3e46e384e0bb1074f3ed9b16371d7e 100644 (file)
@@ -26,46 +26,46 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "wad.h"
 
 
-//cvar_t r_subdivide_size = {CVAR_CLIENT | CVAR_SAVE, "r_subdivide_size", "128", "how large water polygons should be (smaller values produce more polygons which give better warping effects)"};
-cvar_t mod_bsp_portalize = {CVAR_CLIENT | CVAR_SERVER, "mod_bsp_portalize", "1", "enables portal generation from BSP tree (may take several seconds per map), used by r_drawportals, r_useportalculling, r_shadow_realtime_world_compileportalculling, sv_cullentities_portal"};
-cvar_t r_novis = {CVAR_CLIENT, "r_novis", "0", "draws whole level, see also sv_cullentities_pvs 0"};
-cvar_t r_nosurftextures = {CVAR_CLIENT, "r_nosurftextures", "0", "pretends there was no texture lump found in the q1bsp/hlbsp loading (useful for debugging this rare case)"};
-cvar_t r_subdivisions_tolerance = {CVAR_CLIENT, "r_subdivisions_tolerance", "4", "maximum error tolerance on curve subdivision for rendering purposes (in other words, the curves will be given as many polygons as necessary to represent curves at this quality)"};
-cvar_t r_subdivisions_mintess = {CVAR_CLIENT, "r_subdivisions_mintess", "0", "minimum number of subdivisions (values above 0 will smooth curves that don't need it)"};
-cvar_t r_subdivisions_maxtess = {CVAR_CLIENT, "r_subdivisions_maxtess", "1024", "maximum number of subdivisions (prevents curves beyond a certain detail level, limits smoothing)"};
-cvar_t r_subdivisions_maxvertices = {CVAR_CLIENT, "r_subdivisions_maxvertices", "65536", "maximum vertices allowed per subdivided curve"};
-cvar_t r_subdivisions_collision_tolerance = {CVAR_CLIENT, "r_subdivisions_collision_tolerance", "15", "maximum error tolerance on curve subdivision for collision purposes (usually a larger error tolerance than for rendering)"};
-cvar_t r_subdivisions_collision_mintess = {CVAR_CLIENT, "r_subdivisions_collision_mintess", "0", "minimum number of subdivisions (values above 0 will smooth curves that don't need it)"};
-cvar_t r_subdivisions_collision_maxtess = {CVAR_CLIENT, "r_subdivisions_collision_maxtess", "1024", "maximum number of subdivisions (prevents curves beyond a certain detail level, limits smoothing)"};
-cvar_t r_subdivisions_collision_maxvertices = {CVAR_CLIENT, "r_subdivisions_collision_maxvertices", "4225", "maximum vertices allowed per subdivided curve"};
-cvar_t r_trippy = {CVAR_CLIENT, "r_trippy", "0", "easter egg"};
-cvar_t r_fxaa = {CVAR_CLIENT | CVAR_SAVE, "r_fxaa", "0", "fast approximate anti aliasing"};
-cvar_t mod_noshader_default_offsetmapping = {CVAR_CLIENT | CVAR_SAVE, "mod_noshader_default_offsetmapping", "1", "use offsetmapping by default on all surfaces that are not using q3 shader files"};
-cvar_t mod_obj_orientation = {CVAR_CLIENT | CVAR_SERVER, "mod_obj_orientation", "1", "fix orientation of OBJ models to the usual conventions (if zero, use coordinates as is)"};
-cvar_t mod_q2bsp_littransparentsurfaces = {CVAR_CLIENT, "mod_q2bsp_littransparentsurfaces", "0", "allows lighting on rain in 3v3gloom3 and other cases of transparent surfaces that have lightmaps that were ignored by quake2"};
-cvar_t mod_q3bsp_curves_collisions = {CVAR_CLIENT | CVAR_SERVER, "mod_q3bsp_curves_collisions", "1", "enables collisions with curves (SLOW)"};
-cvar_t mod_q3bsp_curves_collisions_stride = {CVAR_CLIENT | CVAR_SERVER, "mod_q3bsp_curves_collisions_stride", "16", "collisions against curves: optimize performance by doing a combined collision check for this triangle amount first (-1 avoids any box tests)"};
-cvar_t mod_q3bsp_curves_stride = {CVAR_CLIENT | CVAR_SERVER, "mod_q3bsp_curves_stride", "16", "particle effect collisions against curves: optimize performance by doing a combined collision check for this triangle amount first (-1 avoids any box tests)"};
-cvar_t mod_q3bsp_optimizedtraceline = {CVAR_CLIENT | CVAR_SERVER, "mod_q3bsp_optimizedtraceline", "1", "whether to use optimized traceline code for line traces (as opposed to tracebox code)"};
-cvar_t mod_q3bsp_debugtracebrush = {CVAR_CLIENT | CVAR_SERVER, "mod_q3bsp_debugtracebrush", "0", "selects different tracebrush bsp recursion algorithms (for debugging purposes only)"};
-cvar_t mod_q3bsp_lightmapmergepower = {CVAR_CLIENT | CVAR_SAVE, "mod_q3bsp_lightmapmergepower", "4", "merges the quake3 128x128 lightmap textures into larger lightmap group textures to speed up rendering, 1 = 256x256, 2 = 512x512, 3 = 1024x1024, 4 = 2048x2048, 5 = 4096x4096, ..."};
-cvar_t mod_q3bsp_nolightmaps = {CVAR_CLIENT | CVAR_SAVE, "mod_q3bsp_nolightmaps", "0", "do not load lightmaps in Q3BSP maps (to save video RAM, but be warned: it looks ugly)"};
-cvar_t mod_q3bsp_tracelineofsight_brushes = {CVAR_CLIENT | CVAR_SERVER, "mod_q3bsp_tracelineofsight_brushes", "0", "enables culling of entities behind detail brushes, curves, etc"};
-cvar_t mod_q3bsp_sRGBlightmaps = {CVAR_CLIENT, "mod_q3bsp_sRGBlightmaps", "0", "treat lightmaps from Q3 maps as sRGB when vid_sRGB is active"};
-cvar_t mod_q3bsp_lightgrid_texture = {CVAR_CLIENT, "mod_q3bsp_lightgrid_texture", "1", "directly apply the lightgrid as a global texture rather than only reading it at the entity origin"};
-cvar_t mod_q3bsp_lightgrid_world_surfaces = {CVAR_CLIENT, "mod_q3bsp_lightgrid_world_surfaces", "0", "apply lightgrid lighting to the world bsp geometry rather than using lightmaps (experimental/debug tool)"};
-cvar_t mod_q3bsp_lightgrid_bsp_surfaces = {CVAR_CLIENT, "mod_q3bsp_lightgrid_bsp_surfaces", "0", "apply lightgrid lighting to bsp models other than the world rather than using their lightmaps (experimental/debug tool)"};
-cvar_t mod_q3shader_default_offsetmapping = {CVAR_CLIENT | CVAR_SAVE, "mod_q3shader_default_offsetmapping", "1", "use offsetmapping by default on all surfaces that are using q3 shader files"};
-cvar_t mod_q3shader_default_offsetmapping_scale = {CVAR_CLIENT | CVAR_SAVE, "mod_q3shader_default_offsetmapping_scale", "1", "default scale used for offsetmapping"};
-cvar_t mod_q3shader_default_offsetmapping_bias = {CVAR_CLIENT | CVAR_SAVE, "mod_q3shader_default_offsetmapping_bias", "0", "default bias used for offsetmapping"};
-cvar_t mod_q3shader_default_polygonfactor = {CVAR_CLIENT, "mod_q3shader_default_polygonfactor", "0", "biases depth values of 'polygonoffset' shaders to prevent z-fighting artifacts"};
-cvar_t mod_q3shader_default_polygonoffset = {CVAR_CLIENT, "mod_q3shader_default_polygonoffset", "-2", "biases depth values of 'polygonoffset' shaders to prevent z-fighting artifacts"};
-cvar_t mod_q3shader_default_refractive_index = {CVAR_CLIENT, "mod_q3shader_default_refractive_index", "1.33", "angle of refraction specified as n to apply when a photon is refracted, example values are: 1.0003 = air, water = 1.333, crown glass = 1.517, flint glass = 1.655, diamond = 2.417"};
-cvar_t mod_q3shader_force_addalpha = {CVAR_CLIENT, "mod_q3shader_force_addalpha", "0", "treat GL_ONE GL_ONE (or add) blendfunc as GL_SRC_ALPHA GL_ONE for compatibility with older DarkPlaces releases"};
-cvar_t mod_q3shader_force_terrain_alphaflag = {CVAR_CLIENT, "mod_q3shader_force_terrain_alphaflag", "0", "for multilayered terrain shaders force TEXF_ALPHA flag on both layers"};
-
-cvar_t mod_q1bsp_polygoncollisions = {CVAR_CLIENT | CVAR_SERVER, "mod_q1bsp_polygoncollisions", "0", "disables use of precomputed cliphulls and instead collides with polygons (uses Bounding Interval Hierarchy optimizations)"};
-cvar_t mod_recalculatenodeboxes = {CVAR_CLIENT | CVAR_SERVER, "mod_recalculatenodeboxes", "1", "enables use of generated node bounding boxes based on BSP tree portal reconstruction, rather than the node boxes supplied by the map compiler"};
+//cvar_t r_subdivide_size = {CF_CLIENT | CF_ARCHIVE, "r_subdivide_size", "128", "how large water polygons should be (smaller values produce more polygons which give better warping effects)"};
+cvar_t mod_bsp_portalize = {CF_CLIENT | CF_SERVER, "mod_bsp_portalize", "1", "enables portal generation from BSP tree (may take several seconds per map), used by r_drawportals, r_useportalculling, r_shadow_realtime_world_compileportalculling, sv_cullentities_portal"};
+cvar_t r_novis = {CF_CLIENT, "r_novis", "0", "draws whole level, see also sv_cullentities_pvs 0"};
+cvar_t r_nosurftextures = {CF_CLIENT, "r_nosurftextures", "0", "pretends there was no texture lump found in the q1bsp/hlbsp loading (useful for debugging this rare case)"};
+cvar_t r_subdivisions_tolerance = {CF_CLIENT, "r_subdivisions_tolerance", "4", "maximum error tolerance on curve subdivision for rendering purposes (in other words, the curves will be given as many polygons as necessary to represent curves at this quality)"};
+cvar_t r_subdivisions_mintess = {CF_CLIENT, "r_subdivisions_mintess", "0", "minimum number of subdivisions (values above 0 will smooth curves that don't need it)"};
+cvar_t r_subdivisions_maxtess = {CF_CLIENT, "r_subdivisions_maxtess", "1024", "maximum number of subdivisions (prevents curves beyond a certain detail level, limits smoothing)"};
+cvar_t r_subdivisions_maxvertices = {CF_CLIENT, "r_subdivisions_maxvertices", "65536", "maximum vertices allowed per subdivided curve"};
+cvar_t r_subdivisions_collision_tolerance = {CF_CLIENT, "r_subdivisions_collision_tolerance", "15", "maximum error tolerance on curve subdivision for collision purposes (usually a larger error tolerance than for rendering)"};
+cvar_t r_subdivisions_collision_mintess = {CF_CLIENT, "r_subdivisions_collision_mintess", "0", "minimum number of subdivisions (values above 0 will smooth curves that don't need it)"};
+cvar_t r_subdivisions_collision_maxtess = {CF_CLIENT, "r_subdivisions_collision_maxtess", "1024", "maximum number of subdivisions (prevents curves beyond a certain detail level, limits smoothing)"};
+cvar_t r_subdivisions_collision_maxvertices = {CF_CLIENT, "r_subdivisions_collision_maxvertices", "4225", "maximum vertices allowed per subdivided curve"};
+cvar_t r_trippy = {CF_CLIENT, "r_trippy", "0", "easter egg"};
+cvar_t r_fxaa = {CF_CLIENT | CF_ARCHIVE, "r_fxaa", "0", "fast approximate anti aliasing"};
+cvar_t mod_noshader_default_offsetmapping = {CF_CLIENT | CF_ARCHIVE, "mod_noshader_default_offsetmapping", "1", "use offsetmapping by default on all surfaces that are not using q3 shader files"};
+cvar_t mod_obj_orientation = {CF_CLIENT | CF_SERVER, "mod_obj_orientation", "1", "fix orientation of OBJ models to the usual conventions (if zero, use coordinates as is)"};
+cvar_t mod_q2bsp_littransparentsurfaces = {CF_CLIENT, "mod_q2bsp_littransparentsurfaces", "0", "allows lighting on rain in 3v3gloom3 and other cases of transparent surfaces that have lightmaps that were ignored by quake2"};
+cvar_t mod_q3bsp_curves_collisions = {CF_CLIENT | CF_SERVER, "mod_q3bsp_curves_collisions", "1", "enables collisions with curves (SLOW)"};
+cvar_t mod_q3bsp_curves_collisions_stride = {CF_CLIENT | CF_SERVER, "mod_q3bsp_curves_collisions_stride", "16", "collisions against curves: optimize performance by doing a combined collision check for this triangle amount first (-1 avoids any box tests)"};
+cvar_t mod_q3bsp_curves_stride = {CF_CLIENT | CF_SERVER, "mod_q3bsp_curves_stride", "16", "particle effect collisions against curves: optimize performance by doing a combined collision check for this triangle amount first (-1 avoids any box tests)"};
+cvar_t mod_q3bsp_optimizedtraceline = {CF_CLIENT | CF_SERVER, "mod_q3bsp_optimizedtraceline", "1", "whether to use optimized traceline code for line traces (as opposed to tracebox code)"};
+cvar_t mod_q3bsp_debugtracebrush = {CF_CLIENT | CF_SERVER, "mod_q3bsp_debugtracebrush", "0", "selects different tracebrush bsp recursion algorithms (for debugging purposes only)"};
+cvar_t mod_q3bsp_lightmapmergepower = {CF_CLIENT | CF_ARCHIVE, "mod_q3bsp_lightmapmergepower", "4", "merges the quake3 128x128 lightmap textures into larger lightmap group textures to speed up rendering, 1 = 256x256, 2 = 512x512, 3 = 1024x1024, 4 = 2048x2048, 5 = 4096x4096, ..."};
+cvar_t mod_q3bsp_nolightmaps = {CF_CLIENT | CF_ARCHIVE, "mod_q3bsp_nolightmaps", "0", "do not load lightmaps in Q3BSP maps (to save video RAM, but be warned: it looks ugly)"};
+cvar_t mod_q3bsp_tracelineofsight_brushes = {CF_CLIENT | CF_SERVER, "mod_q3bsp_tracelineofsight_brushes", "0", "enables culling of entities behind detail brushes, curves, etc"};
+cvar_t mod_q3bsp_sRGBlightmaps = {CF_CLIENT, "mod_q3bsp_sRGBlightmaps", "0", "treat lightmaps from Q3 maps as sRGB when vid_sRGB is active"};
+cvar_t mod_q3bsp_lightgrid_texture = {CF_CLIENT, "mod_q3bsp_lightgrid_texture", "1", "directly apply the lightgrid as a global texture rather than only reading it at the entity origin"};
+cvar_t mod_q3bsp_lightgrid_world_surfaces = {CF_CLIENT, "mod_q3bsp_lightgrid_world_surfaces", "0", "apply lightgrid lighting to the world bsp geometry rather than using lightmaps (experimental/debug tool)"};
+cvar_t mod_q3bsp_lightgrid_bsp_surfaces = {CF_CLIENT, "mod_q3bsp_lightgrid_bsp_surfaces", "0", "apply lightgrid lighting to bsp models other than the world rather than using their lightmaps (experimental/debug tool)"};
+cvar_t mod_q3shader_default_offsetmapping = {CF_CLIENT | CF_ARCHIVE, "mod_q3shader_default_offsetmapping", "1", "use offsetmapping by default on all surfaces that are using q3 shader files"};
+cvar_t mod_q3shader_default_offsetmapping_scale = {CF_CLIENT | CF_ARCHIVE, "mod_q3shader_default_offsetmapping_scale", "1", "default scale used for offsetmapping"};
+cvar_t mod_q3shader_default_offsetmapping_bias = {CF_CLIENT | CF_ARCHIVE, "mod_q3shader_default_offsetmapping_bias", "0", "default bias used for offsetmapping"};
+cvar_t mod_q3shader_default_polygonfactor = {CF_CLIENT, "mod_q3shader_default_polygonfactor", "0", "biases depth values of 'polygonoffset' shaders to prevent z-fighting artifacts"};
+cvar_t mod_q3shader_default_polygonoffset = {CF_CLIENT, "mod_q3shader_default_polygonoffset", "-2", "biases depth values of 'polygonoffset' shaders to prevent z-fighting artifacts"};
+cvar_t mod_q3shader_default_refractive_index = {CF_CLIENT, "mod_q3shader_default_refractive_index", "1.33", "angle of refraction specified as n to apply when a photon is refracted, example values are: 1.0003 = air, water = 1.333, crown glass = 1.517, flint glass = 1.655, diamond = 2.417"};
+cvar_t mod_q3shader_force_addalpha = {CF_CLIENT, "mod_q3shader_force_addalpha", "0", "treat GL_ONE GL_ONE (or add) blendfunc as GL_SRC_ALPHA GL_ONE for compatibility with older DarkPlaces releases"};
+cvar_t mod_q3shader_force_terrain_alphaflag = {CF_CLIENT, "mod_q3shader_force_terrain_alphaflag", "0", "for multilayered terrain shaders force TEXF_ALPHA flag on both layers"};
+
+cvar_t mod_q1bsp_polygoncollisions = {CF_CLIENT | CF_SERVER, "mod_q1bsp_polygoncollisions", "0", "disables use of precomputed cliphulls and instead collides with polygons (uses Bounding Interval Hierarchy optimizations)"};
+cvar_t mod_recalculatenodeboxes = {CF_CLIENT | CF_SERVER, "mod_recalculatenodeboxes", "1", "enables use of generated node bounding boxes based on BSP tree portal reconstruction, rather than the node boxes supplied by the map compiler"};
 
 static texture_t mod_q1bsp_texture_solid;
 static texture_t mod_q1bsp_texture_sky;
@@ -73,7 +73,7 @@ static texture_t mod_q1bsp_texture_lava;
 static texture_t mod_q1bsp_texture_slime;
 static texture_t mod_q1bsp_texture_water;
 
-static qboolean Mod_Q3BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end, const vec3_t acceptmins, const vec3_t acceptmaxs);
+static qbool Mod_Q3BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end, const vec3_t acceptmins, const vec3_t acceptmaxs);
 
 void Mod_BrushInit(void)
 {
@@ -148,7 +148,7 @@ void Mod_BrushInit(void)
        mod_q1bsp_texture_water.supercontents = SUPERCONTENTS_WATER;
 }
 
-static mleaf_t *Mod_BSP_PointInLeaf(dp_model_t *model, const vec3_t p)
+static mleaf_t *Mod_BSP_PointInLeaf(model_t *model, const vec3_t p)
 {
        mnode_t *node;
 
@@ -164,7 +164,7 @@ static mleaf_t *Mod_BSP_PointInLeaf(dp_model_t *model, const vec3_t p)
        return (mleaf_t *)node;
 }
 
-static void Mod_Q1BSP_AmbientSoundLevelsForPoint(dp_model_t *model, const vec3_t p, unsigned char *out, int outsize)
+static void Mod_Q1BSP_AmbientSoundLevelsForPoint(model_t *model, const vec3_t p, unsigned char *out, int outsize)
 {
        int i;
        mleaf_t *leaf;
@@ -183,7 +183,7 @@ static void Mod_Q1BSP_AmbientSoundLevelsForPoint(dp_model_t *model, const vec3_t
                memset(out, 0, outsize);
 }
 
-static int Mod_BSP_FindBoxClusters(dp_model_t *model, const vec3_t mins, const vec3_t maxs, int maxclusters, int *clusterlist)
+static int Mod_BSP_FindBoxClusters(model_t *model, const vec3_t mins, const vec3_t maxs, int maxclusters, int *clusterlist)
 {
        int numclusters = 0;
        int nodestackindex = 0;
@@ -249,7 +249,7 @@ static int Mod_BSP_FindBoxClusters(dp_model_t *model, const vec3_t mins, const v
        return numclusters;
 }
 
-static int Mod_BSP_BoxTouchingPVS(dp_model_t *model, const unsigned char *pvs, const vec3_t mins, const vec3_t maxs)
+static int Mod_BSP_BoxTouchingPVS(model_t *model, const unsigned char *pvs, const vec3_t mins, const vec3_t maxs)
 {
        int nodestackindex = 0;
        mnode_t *node, *nodestack[1024];
@@ -320,7 +320,7 @@ static int Mod_BSP_BoxTouchingPVS(dp_model_t *model, const unsigned char *pvs, c
        return false;
 }
 
-static int Mod_BSP_BoxTouchingLeafPVS(dp_model_t *model, const unsigned char *pvs, const vec3_t mins, const vec3_t maxs)
+static int Mod_BSP_BoxTouchingLeafPVS(model_t *model, const unsigned char *pvs, const vec3_t mins, const vec3_t maxs)
 {
        int nodestackindex = 0;
        mnode_t *node, *nodestack[1024];
@@ -391,7 +391,7 @@ static int Mod_BSP_BoxTouchingLeafPVS(dp_model_t *model, const unsigned char *pv
        return false;
 }
 
-static int Mod_BSP_BoxTouchingVisibleLeafs(dp_model_t *model, const unsigned char *visibleleafs, const vec3_t mins, const vec3_t maxs)
+static int Mod_BSP_BoxTouchingVisibleLeafs(model_t *model, const unsigned char *visibleleafs, const vec3_t mins, const vec3_t maxs)
 {
        int nodestackindex = 0;
        mnode_t *node, *nodestack[1024];
@@ -467,7 +467,7 @@ typedef struct findnonsolidlocationinfo_s
        vec_t radius;
        vec3_t nudge;
        vec_t bestdist;
-       dp_model_t *model;
+       model_t *model;
 }
 findnonsolidlocationinfo_t;
 
@@ -595,7 +595,7 @@ static void Mod_Q1BSP_FindNonSolidLocation_r(findnonsolidlocationinfo_t *info, m
        }
 }
 
-static void Mod_BSP_FindNonSolidLocation(dp_model_t *model, const vec3_t in, vec3_t out, float radius)
+static void Mod_BSP_FindNonSolidLocation(model_t *model, const vec3_t in, vec3_t out, float radius)
 {
        int i;
        findnonsolidlocationinfo_t info;
@@ -1176,14 +1176,14 @@ void Collision_ClipTrace_Point(trace_t *trace, const vec3_t cmins, const vec3_t
        }
 }
 
-static qboolean Mod_Q1BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end, const vec3_t acceptmins, const vec3_t acceptmaxs)
+static qbool Mod_Q1BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end, const vec3_t acceptmins, const vec3_t acceptmaxs)
 {
        trace_t trace;
        Mod_Q1BSP_TraceLine(model, NULL, NULL, &trace, start, end, SUPERCONTENTS_VISBLOCKERMASK, 0, MATERIALFLAGMASK_TRANSLUCENT);
        return trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, acceptmins, acceptmaxs);
 }
 
-static int Mod_Q1BSP_LightPoint_RecursiveBSPNode(dp_model_t *model, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const mnode_t *node, float x, float y, float startz, float endz)
+static int Mod_BSP_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;
        float front, back;
@@ -1225,7 +1225,7 @@ static int Mod_Q1BSP_LightPoint_RecursiveBSPNode(dp_model_t *model, vec3_t ambie
                }
 
                // go down front side
-               if (node->children[side]->plane && Mod_Q1BSP_LightPoint_RecursiveBSPNode(model, ambientcolor, diffusecolor, diffusenormal, node->children[side], x, y, startz, mid))
+               if (node->children[side]->plane && Mod_BSP_LightPoint_RecursiveBSPNode(model, ambientcolor, diffusecolor, diffusenormal, node->children[side], x, y, startz, mid))
                        return true;    // hit something
 
                // check for impact on this node
@@ -1327,7 +1327,7 @@ static int Mod_Q1BSP_LightPoint_RecursiveBSPNode(dp_model_t *model, vec3_t ambie
        return false;
 }
 
-static void Mod_BSP_LightPoint(dp_model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal)
+static void Mod_BSP_LightPoint(model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal)
 {
        // pretend lighting is coming down from above (due to lack of a lightgrid to know primary lighting direction)
        VectorSet(diffusenormal, 0, 0, 1);
@@ -1339,10 +1339,10 @@ static void Mod_BSP_LightPoint(dp_model_t *model, const vec3_t p, vec3_t ambient
                return;
        }
 
-       Mod_Q1BSP_LightPoint_RecursiveBSPNode(model, ambientcolor, diffusecolor, diffusenormal, model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode, p[0], p[1], p[2] + 0.125, p[2] - 65536);
+       Mod_BSP_LightPoint_RecursiveBSPNode(model, ambientcolor, diffusecolor, diffusenormal, model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode, p[0], p[1], p[2] + 0.125, p[2] - 65536);
 }
 
-static const texture_t *Mod_Q1BSP_TraceLineAgainstSurfacesFindTextureOnNode(RecursiveHullCheckTraceInfo_t *t, const dp_model_t *model, const mnode_t *node, double mid[3])
+static const texture_t *Mod_Q1BSP_TraceLineAgainstSurfacesFindTextureOnNode(RecursiveHullCheckTraceInfo_t *t, const model_t *model, const mnode_t *node, double mid[3])
 {
        unsigned int i;
        int j;
@@ -1413,7 +1413,7 @@ static const texture_t *Mod_Q1BSP_TraceLineAgainstSurfacesFindTextureOnNode(Recu
        return NULL;
 }
 
-static int Mod_Q1BSP_TraceLineAgainstSurfacesRecursiveBSPNode(RecursiveHullCheckTraceInfo_t *t, const dp_model_t *model, const mnode_t *node, const double p1[3], const double p2[3])
+static int Mod_Q1BSP_TraceLineAgainstSurfacesRecursiveBSPNode(RecursiveHullCheckTraceInfo_t *t, const model_t *model, const mnode_t *node, const double p1[3], const double p2[3])
 {
        const mplane_t *plane;
        double t1, t2;
@@ -1526,7 +1526,7 @@ static void Mod_Q1BSP_TraceLineAgainstSurfaces(struct model_s *model, const fram
        VectorMA(rhc.start, rhc.trace->fraction, rhc.dist, rhc.trace->endpos);
 }
 
-static void Mod_Q1BSP_DecompressVis(const unsigned char *in, const unsigned char *inend, unsigned char *out, unsigned char *outend)
+static void Mod_BSP_DecompressVis(const unsigned char *in, const unsigned char *inend, unsigned char *out, unsigned char *outend)
 {
        int c;
        unsigned char *outstart = out;
@@ -1534,7 +1534,7 @@ static void Mod_Q1BSP_DecompressVis(const unsigned char *in, const unsigned char
        {
                if (in == inend)
                {
-                       Con_Printf("Mod_Q1BSP_DecompressVis: input underrun on model \"%s\" (decompressed %i of %i output bytes)\n", loadmodel->name, (int)(out - outstart), (int)(outend - outstart));
+                       Con_Printf("Mod_BSP_DecompressVis: input underrun on model \"%s\" (decompressed %i of %i output bytes)\n", loadmodel->name, (int)(out - outstart), (int)(outend - outstart));
                        return;
                }
                c = *in++;
@@ -1544,14 +1544,14 @@ static void Mod_Q1BSP_DecompressVis(const unsigned char *in, const unsigned char
                {
                        if (in == inend)
                        {
-                               Con_Printf("Mod_Q1BSP_DecompressVis: input underrun (during zero-run) on model \"%s\" (decompressed %i of %i output bytes)\n", loadmodel->name, (int)(out - outstart), (int)(outend - outstart));
+                               Con_Printf("Mod_BSP_DecompressVis: input underrun (during zero-run) on model \"%s\" (decompressed %i of %i output bytes)\n", loadmodel->name, (int)(out - outstart), (int)(outend - outstart));
                                return;
                        }
                        for (c = *in++;c > 0;c--)
                        {
                                if (out == outend)
                                {
-                                       Con_Printf("Mod_Q1BSP_DecompressVis: output overrun on model \"%s\" (decompressed %i of %i output bytes)\n", loadmodel->name, (int)(out - outstart), (int)(outend - outstart));
+                                       Con_Printf("Mod_BSP_DecompressVis: output overrun on model \"%s\" (decompressed %i of %i output bytes)\n", loadmodel->name, (int)(out - outstart), (int)(outend - outstart));
                                        return;
                                }
                                *out++ = 0;
@@ -2278,14 +2278,14 @@ static void Mod_Q1BSP_LoadVertexes(sizebuf_t *sb)
        }
 }
 
-static void Mod_Q1BSP_LoadSubmodels(sizebuf_t *sb, hullinfo_t *hullinfo)
+static void Mod_BSP_LoadSubmodels(sizebuf_t *sb, hullinfo_t *hullinfo)
 {
        mmodel_t        *out;
        int                     i, j, count;
-       int                     structsize = (48+4*hullinfo->filehulls);
+       int                     structsize = hullinfo ? (48+4*hullinfo->filehulls) : 48;
 
        if (sb->cursize % structsize)
-               Host_Error ("Mod_Q1BSP_LoadSubmodels: funny lump size in %s", loadmodel->name);
+               Host_Error ("Mod_BSP_LoadSubmodels: funny lump size in %s", loadmodel->name);
 
        count = sb->cursize / structsize;
        out = (mmodel_t *)Mem_Alloc (loadmodel->mempool, count*sizeof(*out));
@@ -2305,9 +2305,15 @@ static void Mod_Q1BSP_LoadSubmodels(sizebuf_t *sb, hullinfo_t *hullinfo)
                out->origin[0] = MSG_ReadLittleFloat(sb);
                out->origin[1] = MSG_ReadLittleFloat(sb);
                out->origin[2] = MSG_ReadLittleFloat(sb);
-               for (j = 0; j < hullinfo->filehulls; j++)
-                       out->headnode[j] = MSG_ReadLittleLong(sb);
-               out->visleafs  = MSG_ReadLittleLong(sb);
+               if(hullinfo)
+               {
+                       for (j = 0; j < hullinfo->filehulls; j++)
+                               out->headnode[j] = MSG_ReadLittleLong(sb);
+                       out->visleafs  = MSG_ReadLittleLong(sb);
+               }
+               else // Quake 2 has only one hull
+                       out->headnode[0] = MSG_ReadLittleLong(sb);
+
                out->firstface = MSG_ReadLittleLong(sb);
                out->numfaces  = MSG_ReadLittleLong(sb);
        }
@@ -2828,16 +2834,16 @@ static void Mod_Q1BSP_LoadFaces(sizebuf_t *sb)
                        loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
 }
 
-static void Mod_Q1BSP_LoadNodes_RecursiveSetParent(mnode_t *node, mnode_t *parent)
+static void Mod_BSP_LoadNodes_RecursiveSetParent(mnode_t *node, mnode_t *parent)
 {
        //if (node->parent)
-       //      Host_Error("Mod_Q1BSP_LoadNodes_RecursiveSetParent: runaway recursion");
+       //      Host_Error("Mod_BSP_LoadNodes_RecursiveSetParent: runaway recursion");
        node->parent = parent;
        if (node->plane)
        {
                // this is a node, recurse to children
-               Mod_Q1BSP_LoadNodes_RecursiveSetParent(node->children[0], node);
-               Mod_Q1BSP_LoadNodes_RecursiveSetParent(node->children[1], node);
+               Mod_BSP_LoadNodes_RecursiveSetParent(node->children[0], node);
+               Mod_BSP_LoadNodes_RecursiveSetParent(node->children[1], node);
                // combine supercontents of children
                node->combinedsupercontents = node->children[0]->combinedsupercontents | node->children[1]->combinedsupercontents;
        }
@@ -2966,7 +2972,7 @@ static void Mod_Q1BSP_LoadNodes(sizebuf_t *sb)
                }
        }
 
-       Mod_Q1BSP_LoadNodes_RecursiveSetParent(loadmodel->brush.data_nodes, NULL);      // sets nodes and leafs
+       Mod_BSP_LoadNodes_RecursiveSetParent(loadmodel->brush.data_nodes, NULL);        // sets nodes and leafs
 }
 
 static void Mod_Q1BSP_LoadLeafs(sizebuf_t *sb)
@@ -3004,7 +3010,7 @@ static void Mod_Q1BSP_LoadLeafs(sizebuf_t *sb)
                        if (p >= loadmodel->brushq1.num_compressedpvs)
                                Con_Print("Mod_Q1BSP_LoadLeafs: invalid visofs\n");
                        else
-                               Mod_Q1BSP_DecompressVis(loadmodel->brushq1.data_compressedpvs + p, loadmodel->brushq1.data_compressedpvs + loadmodel->brushq1.num_compressedpvs, loadmodel->brush.data_pvsclusters + out->clusterindex * loadmodel->brush.num_pvsclusterbytes, loadmodel->brush.data_pvsclusters + (out->clusterindex + 1) * loadmodel->brush.num_pvsclusterbytes);
+                               Mod_BSP_DecompressVis(loadmodel->brushq1.data_compressedpvs + p, loadmodel->brushq1.data_compressedpvs + loadmodel->brushq1.num_compressedpvs, loadmodel->brush.data_pvsclusters + out->clusterindex * loadmodel->brush.num_pvsclusterbytes, loadmodel->brush.data_pvsclusters + (out->clusterindex + 1) * loadmodel->brush.num_pvsclusterbytes);
                }
 
                if (loadmodel->brush.isbsp2rmqe)
@@ -3061,7 +3067,7 @@ static void Mod_Q1BSP_LoadLeafs(sizebuf_t *sb)
        }
 }
 
-static qboolean Mod_Q1BSP_CheckWaterAlphaSupport(void)
+static qbool Mod_Q1BSP_CheckWaterAlphaSupport(void)
 {
        int i, j;
        mleaf_t *leaf;
@@ -3238,14 +3244,15 @@ static void Mod_Q1BSP_LoadPlanes(sizebuf_t *sb)
 }
 
 // fixes up sky surfaces that have SKY contents behind them, so that they do not cast shadows (e1m5 logo shadow trick).
-static void Mod_Q1BSP_AssignNoShadowSkySurfaces(dp_model_t *mod)
+static void Mod_Q1BSP_AssignNoShadowSkySurfaces(model_t *mod)
 {
-       int i;
+       int surfaceindex;
        msurface_t *surface;
        vec3_t center;
        int contents;
-       for (i = 0, surface = mod->data_surfaces + mod->firstmodelsurface; i < mod->nummodelsurfaces; i++, surface++)
+       for (surfaceindex = mod->submodelsurfaces_start; surfaceindex < mod->submodelsurfaces_end;surfaceindex++)
        {
+               surface = mod->data_surfaces + surfaceindex;
                if (surface->texture->basematerialflags & MATERIALFLAG_SKY)
                {
                        // check if the point behind the surface polygon is SOLID or SKY contents
@@ -3262,7 +3269,7 @@ static void Mod_Q1BSP_LoadMapBrushes(void)
 #if 0
 // unfinished
        int submodel, numbrushes;
-       qboolean firstbrush;
+       qbool firstbrush;
        char *text, *maptext;
        char mapfilename[MAX_QPATH];
        FS_StripExtension (loadmodel->name, mapfilename, sizeof (mapfilename));
@@ -3629,7 +3636,7 @@ static void Mod_BSP_RecursiveNodePortals(mnode_t *node)
        // TODO: calculate node bounding boxes during recursion and calculate a maximum plane size accordingly to improve precision (as most maps do not need 1 billion unit plane polygons)
        PolygonD_QuadForPlane(nodeportal->points, nodeportal->plane.normal[0], nodeportal->plane.normal[1], nodeportal->plane.normal[2], nodeportal->plane.dist, 1024.0*1024.0*1024.0);
        nodeportal->numpoints = 4;
-       // side = 0;    // shut up compiler warning -> should be no longer needed, Host_Error is declared noreturn now
+
        for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
        {
                clipplane = portal->plane;
@@ -3758,7 +3765,7 @@ static void Mod_BSP_MakePortals(void)
 
 //Returns PVS data for a given point
 //(note: can return NULL)
-static unsigned char *Mod_BSP_GetPVS(dp_model_t *model, const vec3_t p)
+static unsigned char *Mod_BSP_GetPVS(model_t *model, const vec3_t p)
 {
        mnode_t *node;
        node = model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode;
@@ -3770,7 +3777,7 @@ static unsigned char *Mod_BSP_GetPVS(dp_model_t *model, const vec3_t p)
                return NULL;
 }
 
-static void Mod_BSP_FatPVS_RecursiveBSPNode(dp_model_t *model, const vec3_t org, vec_t radius, unsigned char *pvsbuffer, int pvsbytes, mnode_t *node)
+static void Mod_BSP_FatPVS_RecursiveBSPNode(model_t *model, const vec3_t org, vec_t radius, unsigned char *pvsbuffer, int pvsbytes, mnode_t *node)
 {
        while (node->plane)
        {
@@ -3798,7 +3805,7 @@ static void Mod_BSP_FatPVS_RecursiveBSPNode(dp_model_t *model, const vec3_t org,
 
 //Calculates a PVS that is the inclusive or of all leafs within radius pixels
 //of the given point.
-static int Mod_BSP_FatPVS(dp_model_t *model, const vec3_t org, vec_t radius, unsigned char *pvsbuffer, int pvsbufferlength, qboolean merge)
+static int Mod_BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, unsigned char *pvsbuffer, int pvsbufferlength, qbool merge)
 {
        int bytes = model->brush.num_pvsclusterbytes;
        bytes = min(bytes, pvsbufferlength);
@@ -3813,7 +3820,7 @@ static int Mod_BSP_FatPVS(dp_model_t *model, const vec3_t org, vec_t radius, uns
        return bytes;
 }
 
-static void Mod_Q1BSP_RoundUpToHullSize(dp_model_t *cmodel, const vec3_t inmins, const vec3_t inmaxs, vec3_t outmins, vec3_t outmaxs)
+static void Mod_Q1BSP_RoundUpToHullSize(model_t *cmodel, const vec3_t inmins, const vec3_t inmaxs, vec3_t outmins, vec3_t outmaxs)
 {
        vec3_t size;
        const hull_t *hull;
@@ -3846,9 +3853,31 @@ static void Mod_Q1BSP_RoundUpToHullSize(dp_model_t *cmodel, const vec3_t inmins,
        VectorAdd(inmins, hull->clip_size, outmaxs);
 }
 
-void Mod_CollisionBIH_TraceLineAgainstSurfaces(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask);
+void Mod_CollisionBIH_TraceLineAgainstSurfaces(model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask);
+
+void Mod_2PSB_Load(model_t *mod, void *buffer, void *bufferend)
+{
+       mod->brush.isbsp2 = true;
+       mod->brush.isbsp2rmqe = true; // like bsp2 except leaf/node bounds are 16bit (unexpanded)
+       mod->modeldatatypestring = "Q1BSP2rmqe";
+       Mod_Q1BSP_Load(mod, buffer, bufferend);
+}
+
+void Mod_BSP2_Load(model_t *mod, void *buffer, void *bufferend)
+{
+       mod->brush.isbsp2 = true;
+       mod->modeldatatypestring = "Q1BSP2";
+       Mod_Q1BSP_Load(mod, buffer, bufferend);
+}
 
-void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
+void Mod_HLBSP_Load(model_t *mod, void *buffer, void *bufferend)
+{
+       mod->brush.ishlbsp = true;
+       mod->modeldatatypestring = "HLBSP";
+       Mod_Q1BSP_Load(mod, buffer, bufferend);
+}
+
+void Mod_Q1BSP_Load(model_t *mod, void *buffer, void *bufferend)
 {
        int i, j, k;
        sizebuf_t lumpsb[HEADER_LUMPS];
@@ -3865,36 +3894,11 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
 
        mod->type = mod_brushq1;
 
-       mod->brush.ishlbsp = false;
-       mod->brush.isbsp2rmqe = false;
-       mod->brush.isbsp2 = false;
-       mod->brush.isq2bsp = false;
-       mod->brush.isq3bsp = false;
        mod->brush.skymasking = true;
        i = MSG_ReadLittleLong(&sb);
-       switch(i)
-       {
-       case BSPVERSION:
+
+       if(!mod->modeldatatypestring)
                mod->modeldatatypestring = "Q1BSP";
-               break;
-       case 30:
-               mod->brush.ishlbsp = true;
-               mod->modeldatatypestring = "HLBSP";
-               break;
-       case ('2' + 'P' * 256 + 'S' * 65536 + 'B' * 16777216):
-               mod->brush.isbsp2 = true;
-               mod->brush.isbsp2rmqe = true; // like bsp2 except leaf/node bounds are 16bit (unexpanded)
-               mod->modeldatatypestring = "Q1BSP2rmqe";
-               break;
-       case ('B' + 'S' * 256 + 'P' * 65536 + '2' * 16777216):
-               mod->brush.isbsp2 = true;
-               mod->modeldatatypestring = "Q1BSP2";
-               break;
-       default:
-               mod->modeldatatypestring = "Unknown BSP";
-               Host_Error("Mod_Q1BSP_Load: %s has wrong version number %i: supported versions are 29 (Quake), 30 (Half-Life), \"BSP2\" or \"2PSB\" (rmqe)", mod->name, i);
-               return;
-       }
 
 // fill in hull info
        VectorClear (hullinfo.hullsizes[0][0]);
@@ -3985,7 +3989,7 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
        Mod_Q1BSP_LoadLeaffaces(&lumpsb[LUMP_MARKSURFACES]);
        Mod_Q1BSP_LoadVisibility(&lumpsb[LUMP_VISIBILITY]);
        // load submodels before leafs because they contain the number of vis leafs
-       Mod_Q1BSP_LoadSubmodels(&lumpsb[LUMP_MODELS], &hullinfo);
+       Mod_BSP_LoadSubmodels(&lumpsb[LUMP_MODELS], &hullinfo);
        Mod_Q1BSP_LoadLeafs(&lumpsb[LUMP_LEAFS]);
        Mod_Q1BSP_LoadNodes(&lumpsb[LUMP_NODES]);
        Mod_Q1BSP_LoadClipnodes(&lumpsb[LUMP_CLIPNODES], &hullinfo);
@@ -4011,7 +4015,7 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
        mod->numskins = 1;
 
        if (loadmodel->brush.numsubmodels)
-               loadmodel->brush.submodels = (dp_model_t **)Mem_Alloc(loadmodel->mempool, loadmodel->brush.numsubmodels * sizeof(dp_model_t *));
+               loadmodel->brush.submodels = (model_t **)Mem_Alloc(loadmodel->mempool, loadmodel->brush.numsubmodels * sizeof(model_t *));
 
        // LadyHavoc: to clear the fog around the original quake submodel code, I
        // will explain:
@@ -4046,6 +4050,7 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
                }
        }
        datapointer = (unsigned char *)Mem_Alloc(mod->mempool, mod->num_surfaces * sizeof(int) + totalstyles * sizeof(model_brush_lightstyleinfo_t) + totalstylesurfaces * sizeof(int *));
+       mod->modelsurfaces_sorted = (int*)datapointer;datapointer += mod->num_surfaces * sizeof(int);
        for (i = 0;i < mod->brush.numsubmodels;i++)
        {
                // LadyHavoc: this code was originally at the end of this loop, but
@@ -4089,19 +4094,15 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
                        mod->brushq1.hulls[j].lastclipnode = mod->brushq1.numclipnodes - 1;
                }
 
-               mod->firstmodelsurface = bm->firstface;
-               mod->nummodelsurfaces = bm->numfaces;
+               mod->submodelsurfaces_start = bm->firstface;
+               mod->submodelsurfaces_end = bm->firstface + bm->numfaces;
 
                // set node/leaf parents for this submodel
-               Mod_Q1BSP_LoadNodes_RecursiveSetParent(mod->brush.data_nodes + mod->brushq1.hulls[0].firstclipnode, NULL);
+               Mod_BSP_LoadNodes_RecursiveSetParent(mod->brush.data_nodes + mod->brushq1.hulls[0].firstclipnode, NULL);
 
                // this has to occur after hull info has been set, as it uses Mod_Q1BSP_PointSuperContents
                Mod_Q1BSP_AssignNoShadowSkySurfaces(mod);
 
-               // make the model surface list (used by shadowing/lighting)
-               mod->sortedmodelsurfaces = (int *)datapointer;datapointer += mod->nummodelsurfaces * sizeof(int);
-               Mod_MakeSortedSurfaces(mod);
-
                // copy the submodel bounds, then enlarge the yaw and rotated bounds according to radius
                // (previously this code measured the radius of the vertices of surfaces in the submodel, but that broke submodels that contain only CLIP brushes, which do not produce surfaces)
                VectorCopy(bm->mins, mod->normalmins);
@@ -4122,36 +4123,17 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
                mod->radius = modelradius;
                mod->radius2 = modelradius * modelradius;
 
-               // this gets altered below if sky or water is used
-               mod->DrawSky = NULL;
-               mod->DrawAddWaterPlanes = NULL;
+               Mod_SetDrawSkyAndWater(mod);
 
-               // scan surfaces for sky and water and flag the submodel as possessing these features or not
-               // build lightstyle lists for quick marking of dirty lightmaps when lightstyles flicker
-               if (mod->nummodelsurfaces)
+               if (mod->submodelsurfaces_start < mod->submodelsurfaces_end)
                {
-                       for (j = 0, surface = &mod->data_surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surface++)
-                               if (surface->texture->basematerialflags & MATERIALFLAG_SKY)
-                                       break;
-                       if (j < mod->nummodelsurfaces)
-                               mod->DrawSky = R_Mod_DrawSky;
-
-                       for (j = 0, surface = &mod->data_surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surface++)
-                               if (surface->texture && surface->texture->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
-                                       break;
-                       if (j < mod->nummodelsurfaces)
-                               mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
-
                        // build lightstyle update chains
                        // (used to rapidly mark lightmapupdateflags on many surfaces
                        // when d_lightstylevalue changes)
                        memset(stylecounts, 0, sizeof(stylecounts));
-                       for (k = 0;k < mod->nummodelsurfaces;k++)
-                       {
-                               surface = mod->data_surfaces + mod->firstmodelsurface + k;
+                       for (k = mod->submodelsurfaces_start;k < mod->submodelsurfaces_end;k++)
                                for (j = 0;j < MAXLIGHTMAPS;j++)
-                                       stylecounts[surface->lightmapinfo->styles[j]]++;
-                       }
+                                       stylecounts[mod->data_surfaces[k].lightmapinfo->styles[j]]++;
                        mod->brushq1.num_lightstyles = 0;
                        for (k = 0;k < 255;k++)
                        {
@@ -4165,15 +4147,15 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
                                        mod->brushq1.num_lightstyles++;
                                }
                        }
-                       for (k = 0;k < mod->nummodelsurfaces;k++)
+                       for (k = mod->submodelsurfaces_start;k < mod->submodelsurfaces_end;k++)
                        {
-                               surface = mod->data_surfaces + mod->firstmodelsurface + k;
+                               surface = mod->data_surfaces + k;
                                for (j = 0;j < MAXLIGHTMAPS;j++)
                                {
                                        if (surface->lightmapinfo->styles[j] != 255)
                                        {
                                                int r = remapstyles[surface->lightmapinfo->styles[j]];
-                                               styleinfo[r].surfacelist[styleinfo[r].numsurfaces++] = mod->firstmodelsurface + k;
+                                               styleinfo[r].surfacelist[styleinfo[r].numsurfaces++] = k;
                                        }
                                }
                        }
@@ -4208,6 +4190,10 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
                        //Mod_Q1BSP_ProcessLightList();
                }
        }
+       mod = loadmodel;
+
+       // make the model surface list (used by shadowing/lighting)
+       Mod_MakeSortedSurfaces(loadmodel);
 
        Con_DPrintf("Stats for q1bsp model \"%s\": %i faces, %i nodes, %i leafs, %i visleafs, %i visleafportals, mesh: %i vertices, %i triangles, %i surfaces\n", loadmodel->name, loadmodel->num_surfaces, loadmodel->brush.num_nodes, loadmodel->brush.num_leafs, mod->brush.num_pvsclusters, loadmodel->brush.num_portals, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->num_surfaces);
 }
@@ -4282,7 +4268,7 @@ static void Mod_Q2BSP_LoadVisibility(sizebuf_t *sb)
                /*int phsofs = */MSG_ReadLittleLong(sb);
                // decompress the vis data for this cluster
                // (note this accesses the underlying data store of sb, which is kind of evil)
-               Mod_Q1BSP_DecompressVis(sb->data + pvsofs, sb->data + sb->cursize, loadmodel->brush.data_pvsclusters + i * loadmodel->brush.num_pvsclusterbytes, loadmodel->brush.data_pvsclusters + (i+1) * loadmodel->brush.num_pvsclusterbytes);
+               Mod_BSP_DecompressVis(sb->data + pvsofs, sb->data + sb->cursize, loadmodel->brush.data_pvsclusters + i * loadmodel->brush.num_pvsclusterbytes, loadmodel->brush.data_pvsclusters + (i+1) * loadmodel->brush.num_pvsclusterbytes);
        }
        // hush the loading error check later - we had to do random access on this lump, so we didn't read to the end
        sb->readcount = sb->cursize;
@@ -4354,7 +4340,7 @@ static void Mod_Q2BSP_LoadNodes(sizebuf_t *sb)
                }
        }
 
-       Mod_Q1BSP_LoadNodes_RecursiveSetParent(loadmodel->brush.data_nodes, NULL);      // sets nodes and leafs
+       Mod_BSP_LoadNodes_RecursiveSetParent(loadmodel->brush.data_nodes, NULL);        // sets nodes and leafs
 }
 
 static void Mod_Q2BSP_LoadTexinfo(sizebuf_t *sb)
@@ -4696,7 +4682,7 @@ static void Mod_Q2BSP_LoadBrushes(sizebuf_t *sb)
        int i, j, firstside, numsides, contents, count, maxplanes, q3surfaceflags, supercontents;
        colplanef_t *planes;
        int structsize = 12;
-       qboolean brushmissingtextures;
+       qbool brushmissingtextures;
        int numbrushesmissingtextures = 0;
        int numcreatedtextures = 0;
 
@@ -4809,41 +4795,7 @@ static void Mod_Q2BSP_LoadAreaPortals(sizebuf_t *sb)
        sb->readcount = sb->cursize;
 }
 
-static void Mod_Q2BSP_LoadSubmodels(sizebuf_t *sb)
-{
-       mmodel_t        *out;
-       int                     i, count;
-       int                     structsize = 48;
-
-       if (sb->cursize % structsize)
-               Host_Error ("Mod_Q2BSP_LoadSubmodels: funny lump size in %s", loadmodel->name);
-
-       count = sb->cursize / structsize;
-       out = (mmodel_t *)Mem_Alloc (loadmodel->mempool, count*sizeof(*out));
-
-       loadmodel->brushq1.submodels = out;
-       loadmodel->brush.numsubmodels = count;
-
-       // this is identical to the q1 submodel structure except for having 1 hull
-       for (i = 0; i < count; i++, out++)
-       {
-               // spread out the mins / maxs by a pixel
-               out->mins[0] = MSG_ReadLittleFloat(sb) - 1;
-               out->mins[1] = MSG_ReadLittleFloat(sb) - 1;
-               out->mins[2] = MSG_ReadLittleFloat(sb) - 1;
-               out->maxs[0] = MSG_ReadLittleFloat(sb) + 1;
-               out->maxs[1] = MSG_ReadLittleFloat(sb) + 1;
-               out->maxs[2] = MSG_ReadLittleFloat(sb) + 1;
-               out->origin[0] = MSG_ReadLittleFloat(sb);
-               out->origin[1] = MSG_ReadLittleFloat(sb);
-               out->origin[2] = MSG_ReadLittleFloat(sb);
-               out->headnode[0] = MSG_ReadLittleLong(sb);
-               out->firstface = MSG_ReadLittleLong(sb);
-               out->numfaces  = MSG_ReadLittleLong(sb);
-       }
-}
-
-static void Mod_Q2BSP_FindSubmodelBrushRange_r(dp_model_t *mod, mnode_t *node, int *first, int *last)
+static void Mod_Q2BSP_FindSubmodelBrushRange_r(model_t *mod, mnode_t *node, int *first, int *last)
 {
        int i;
        mleaf_t *leaf;
@@ -4863,7 +4815,7 @@ static void Mod_Q2BSP_FindSubmodelBrushRange_r(dp_model_t *mod, mnode_t *node, i
        }
 }
 
-static void Mod_Q2BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
+static void Mod_Q2BSP_Load(model_t *mod, void *buffer, void *bufferend)
 {
        int i, j, k;
        sizebuf_t lumpsb[Q2HEADER_LUMPS];
@@ -4970,7 +4922,7 @@ static void Mod_Q2BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
        Mod_Q2BSP_LoadAreaPortals(&lumpsb[Q2LUMP_AREAPORTALS]);
        Mod_Q2BSP_LoadLeafs(&lumpsb[Q2LUMP_LEAFS]);
        Mod_Q2BSP_LoadNodes(&lumpsb[Q2LUMP_NODES]);
-       Mod_Q2BSP_LoadSubmodels(&lumpsb[Q2LUMP_MODELS]);
+       Mod_BSP_LoadSubmodels(&lumpsb[Q2LUMP_MODELS], NULL);
 
        for (i = 0; i < Q2HEADER_LUMPS; i++)
                if (lumpsb[i].readcount != lumpsb[i].cursize)
@@ -4994,7 +4946,7 @@ static void Mod_Q2BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
        mod->numskins = 1;
 
        if (loadmodel->brush.numsubmodels)
-               loadmodel->brush.submodels = (dp_model_t **)Mem_Alloc(loadmodel->mempool, loadmodel->brush.numsubmodels * sizeof(dp_model_t *));
+               loadmodel->brush.submodels = (model_t **)Mem_Alloc(loadmodel->mempool, loadmodel->brush.numsubmodels * sizeof(model_t *));
 
        totalstylesurfaces = 0;
        totalstyles = 0;
@@ -5015,6 +4967,7 @@ static void Mod_Q2BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
                }
        }
        datapointer = (unsigned char *)Mem_Alloc(mod->mempool, mod->num_surfaces * sizeof(int) + totalstyles * sizeof(model_brush_lightstyleinfo_t) + totalstylesurfaces * sizeof(int *));
+       mod->modelsurfaces_sorted = (int*)datapointer; datapointer += mod->num_surfaces * sizeof(int);
        // set up the world model, then on each submodel copy from the world model
        // and set up the submodel with the respective model info.
        mod = loadmodel;
@@ -5054,8 +5007,8 @@ static void Mod_Q2BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
                // we store the headnode (there's only one in Q2BSP) as if it were the first hull
                mod->brushq1.hulls[0].firstclipnode = bm->headnode[0];
 
-               mod->firstmodelsurface = bm->firstface;
-               mod->nummodelsurfaces = bm->numfaces;
+               mod->submodelsurfaces_start = bm->firstface;
+               mod->submodelsurfaces_end = bm->firstface + bm->numfaces;
 
                // set node/leaf parents for this submodel
                // note: if the root of this submodel is a leaf (headnode[0] < 0) then there is nothing to do...
@@ -5064,10 +5017,9 @@ static void Mod_Q2BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
                        rootnode = mod->brush.data_nodes + bm->headnode[0];
                else
                        rootnode = (mnode_t*)(mod->brush.data_leafs + -1 - bm->headnode[0]);
-               Mod_Q1BSP_LoadNodes_RecursiveSetParent(rootnode, NULL);
+               Mod_BSP_LoadNodes_RecursiveSetParent(rootnode, NULL);
 
                // make the model surface list (used by shadowing/lighting)
-               mod->sortedmodelsurfaces = (int *)datapointer;datapointer += mod->nummodelsurfaces * sizeof(int);
                Mod_Q2BSP_FindSubmodelBrushRange_r(mod, rootnode, &firstbrush, &lastbrush);
                if (firstbrush <= lastbrush)
                {
@@ -5079,7 +5031,6 @@ static void Mod_Q2BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
                        mod->firstmodelbrush = 0;
                        mod->nummodelbrushes = 0;
                }
-               Mod_MakeSortedSurfaces(mod);
 
                VectorCopy(bm->mins, mod->normalmins);
                VectorCopy(bm->maxs, mod->normalmaxs);
@@ -5099,36 +5050,18 @@ static void Mod_Q2BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
                mod->radius = modelradius;
                mod->radius2 = modelradius * modelradius;
 
-               // this gets altered below if sky or water is used
-               mod->DrawSky = NULL;
-               mod->DrawAddWaterPlanes = NULL;
+               Mod_SetDrawSkyAndWater(mod);
 
-               // scan surfaces for sky and water and flag the submodel as possessing these features or not
                // build lightstyle lists for quick marking of dirty lightmaps when lightstyles flicker
-               if (mod->nummodelsurfaces)
+               if (mod->submodelsurfaces_start < mod->submodelsurfaces_end)
                {
-                       for (j = 0, surface = &mod->data_surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surface++)
-                               if (surface->texture->basematerialflags & MATERIALFLAG_SKY)
-                                       break;
-                       if (j < mod->nummodelsurfaces)
-                               mod->DrawSky = R_Mod_DrawSky;
-
-                       for (j = 0, surface = &mod->data_surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surface++)
-                               if (surface->texture->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
-                                       break;
-                       if (j < mod->nummodelsurfaces)
-                               mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
-
                        // build lightstyle update chains
                        // (used to rapidly mark lightmapupdateflags on many surfaces
                        // when d_lightstylevalue changes)
                        memset(stylecounts, 0, sizeof(stylecounts));
-                       for (k = 0;k < mod->nummodelsurfaces;k++)
-                       {
-                               surface = mod->data_surfaces + mod->firstmodelsurface + k;
+                       for (k = mod->submodelsurfaces_start;k < mod->submodelsurfaces_end;k++)
                                for (j = 0;j < MAXLIGHTMAPS;j++)
-                                       stylecounts[surface->lightmapinfo->styles[j]]++;
-                       }
+                                       stylecounts[mod->data_surfaces[k].lightmapinfo->styles[j]]++;
                        mod->brushq1.num_lightstyles = 0;
                        for (k = 0;k < 255;k++)
                        {
@@ -5142,15 +5075,15 @@ static void Mod_Q2BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
                                        mod->brushq1.num_lightstyles++;
                                }
                        }
-                       for (k = 0;k < mod->nummodelsurfaces;k++)
+                       for (k = mod->submodelsurfaces_start;k < mod->submodelsurfaces_end;k++)
                        {
-                               surface = mod->data_surfaces + mod->firstmodelsurface + k;
+                               surface = mod->data_surfaces + k;
                                for (j = 0;j < MAXLIGHTMAPS;j++)
                                {
                                        if (surface->lightmapinfo->styles[j] != 255)
                                        {
                                                int r = remapstyles[surface->lightmapinfo->styles[j]];
-                                               styleinfo[r].surfacelist[styleinfo[r].numsurfaces++] = mod->firstmodelsurface + k;
+                                               styleinfo[r].surfacelist[styleinfo[r].numsurfaces++] = k;
                                        }
                                }
                        }
@@ -5175,6 +5108,9 @@ static void Mod_Q2BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
        }
        mod = loadmodel;
 
+       // make the model surface list (used by shadowing/lighting)
+       Mod_MakeSortedSurfaces(loadmodel);
+
        Con_DPrintf("Stats for q2bsp model \"%s\": %i faces, %i nodes, %i leafs, %i clusters, %i clusterportals, mesh: %i vertices, %i triangles, %i surfaces\n", loadmodel->name, loadmodel->num_surfaces, loadmodel->brush.num_nodes, loadmodel->brush.num_leafs, mod->brush.num_pvsclusters, loadmodel->brush.num_portals, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->num_surfaces);
 }
 
@@ -5575,7 +5511,7 @@ static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump)
        unsigned char *mergeddeluxepixels;
        unsigned char *mergebuf;
        char mapname[MAX_QPATH];
-       qboolean external;
+       qbool external;
        unsigned char *inpixels[10000]; // max count q3map2 can output (it uses 4 digits)
        char vabuf[1024];
 
@@ -5611,19 +5547,16 @@ static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump)
        {
                // no internal lightmaps
                // try external lightmaps
-               if (developer_loading.integer)
-                       Con_Printf("Using external lightmaps\n");
                FS_StripExtension(loadmodel->name, mapname, sizeof(mapname));
                inpixels[0] = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s/lm_%04d", mapname, 0), false, false, false, NULL);
                if(!inpixels[0])
                        return;
+               else
+                       Con_Printf("Using external lightmaps\n");
 
                // using EXTERNAL lightmaps instead
                if(image_width != (int) CeilPowerOf2(image_width) || image_width != image_height)
-               {
-                       Mem_Free(inpixels[0]);
-                       Host_Error("Mod_Q3BSP_LoadLightmaps: invalid external lightmap size in %s",loadmodel->name);
-               }
+                       Con_Printf("Mod_Q3BSP_LoadLightmaps: irregularly sized external lightmap in %s",loadmodel->name);
 
                size = image_width;
                bytesperpixel = 4;
@@ -5712,7 +5645,7 @@ static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump)
                }
        }
 
-       Con_DPrintf("%s is %sdeluxemapped\n", loadmodel->name, loadmodel->brushq3.deluxemapping ? "" : "not ");
+       Con_Printf("%s is %sdeluxemapped\n", loadmodel->name, loadmodel->brushq3.deluxemapping ? "" : "not ");
 
        // figure out what the most reasonable merge power is within limits
 
@@ -5858,7 +5791,7 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l)
        float *v;
        patchtess_t *patchtess = NULL;
        int patchtesscount = 0;
-       qboolean again;
+       qbool again;
 
        in = (q3dface_t *)(mod_base + l->fileofs);
        if (l->filelen % sizeof(*in))
@@ -6472,7 +6405,7 @@ static void Mod_Q3BSP_LoadNodes(lump_t *l)
        }
 
        // set the parent pointers
-       Mod_Q1BSP_LoadNodes_RecursiveSetParent(loadmodel->brush.data_nodes, NULL);
+       Mod_BSP_LoadNodes_RecursiveSetParent(loadmodel->brush.data_nodes, NULL);
 }
 
 static void Mod_Q3BSP_LoadLightGrid(lump_t *l)
@@ -6675,7 +6608,7 @@ static void Mod_Q3BSP_LoadPVS(lump_t *l)
        memcpy(loadmodel->brush.data_pvsclusters, (unsigned char *)(in + 1), totalchains);
 }
 
-static void Mod_Q3BSP_LightPoint(dp_model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal)
+static void Mod_Q3BSP_LightPoint(model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal)
 {
        int i, j, k, index[3];
        float transformed[3], blend1, blend2, blend, stylescale = 1;
@@ -6804,7 +6737,7 @@ static int Mod_Q3BSP_TraceLineOfSight_RecursiveNodeCheck(mnode_t *node, double p
        return ((mleaf_t *)node)->clusterindex < 0;
 }
 
-static qboolean Mod_Q3BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end, const vec3_t acceptmins, const vec3_t acceptmaxs)
+static qbool Mod_Q3BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end, const vec3_t acceptmins, const vec3_t acceptmaxs)
 {
        if (model->brush.submodel || mod_q3bsp_tracelineofsight_brushes.integer)
        {
@@ -6823,7 +6756,7 @@ static qboolean Mod_Q3BSP_TraceLineOfSight(struct model_s *model, const vec3_t s
        }
 }
 
-void Mod_CollisionBIH_TracePoint(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
+void Mod_CollisionBIH_TracePoint(model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
 {
        const bih_t *bih;
        const bih_leaf_t *leaf;
@@ -6889,7 +6822,7 @@ void Mod_CollisionBIH_TracePoint(dp_model_t *model, const frameblend_t *frameble
        }
 }
 
-static void Mod_CollisionBIH_TraceLineShared(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, const bih_t *bih)
+static void Mod_CollisionBIH_TraceLineShared(model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, const bih_t *bih)
 {
        const bih_leaf_t *leaf;
        const bih_node_t *node;
@@ -6990,6 +6923,7 @@ static void Mod_CollisionBIH_TraceLineShared(dp_model_t *model, const frameblend
                        for (axis = 0;axis < BIH_MAXUNORDEREDCHILDREN && node->children[axis] >= 0;axis++)
                        {
                                leaf = bih->leafs + node->children[axis];
+                               // TODO: This is very expensive in Steel Storm. Framerate halved during even light combat.
                                if (!BoxesOverlap(sweepnodemins, sweepnodemaxs, leaf->mins, leaf->maxs))
                                        continue;
                                switch(leaf->type)
@@ -7016,7 +6950,7 @@ static void Mod_CollisionBIH_TraceLineShared(dp_model_t *model, const frameblend
        }
 }
 
-void Mod_CollisionBIH_TraceLine(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
+void Mod_CollisionBIH_TraceLine(model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
 {
        if (VectorCompare(start, end))
        {
@@ -7026,7 +6960,7 @@ void Mod_CollisionBIH_TraceLine(dp_model_t *model, const frameblend_t *frameblen
        Mod_CollisionBIH_TraceLineShared(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, &model->collision_bih);
 }
 
-void Mod_CollisionBIH_TraceBrush(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, colbrushf_t *thisbrush_start, colbrushf_t *thisbrush_end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
+void Mod_CollisionBIH_TraceBrush(model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, colbrushf_t *thisbrush_start, colbrushf_t *thisbrush_end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
 {
        const bih_t *bih;
        const bih_leaf_t *leaf;
@@ -7171,7 +7105,7 @@ void Mod_CollisionBIH_TraceBrush(dp_model_t *model, const frameblend_t *frameble
        }
 }
 
-void Mod_CollisionBIH_TraceBox(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
+void Mod_CollisionBIH_TraceBox(model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
 {
        colboxbrushf_t thisbrush_start, thisbrush_end;
        vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
@@ -7194,14 +7128,14 @@ int Mod_CollisionBIH_PointSuperContents(struct model_s *model, int frame, const
        return trace.startsupercontents;
 }
 
-qboolean Mod_CollisionBIH_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end, const vec3_t acceptmins, const vec3_t acceptmaxs)
+qbool Mod_CollisionBIH_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end, const vec3_t acceptmins, const vec3_t acceptmaxs)
 {
        trace_t trace;
        Mod_CollisionBIH_TraceLine(model, NULL, NULL, &trace, start, end, SUPERCONTENTS_VISBLOCKERMASK, 0, MATERIALFLAGMASK_TRANSLUCENT);
        return trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, acceptmins, acceptmaxs);
 }
 
-void Mod_CollisionBIH_TracePoint_Mesh(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
+void Mod_CollisionBIH_TracePoint_Mesh(model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
 {
 #if 0
        // broken - needs to be modified to count front faces and backfaces to figure out if it is in solid
@@ -7245,13 +7179,13 @@ int Mod_CollisionBIH_PointSuperContents_Mesh(struct model_s *model, int frame, c
 #endif
 }
 
-void Mod_CollisionBIH_TraceLineAgainstSurfaces(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
+void Mod_CollisionBIH_TraceLineAgainstSurfaces(model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
 {
        Mod_CollisionBIH_TraceLineShared(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, &model->render_bih);
 }
 
 
-bih_t *Mod_MakeCollisionBIH(dp_model_t *model, qboolean userendersurfaces, bih_t *out)
+bih_t *Mod_MakeCollisionBIH(model_t *model, qbool userendersurfaces, bih_t *out)
 {
        int j;
        int bihnumleafs;
@@ -7260,7 +7194,6 @@ bih_t *Mod_MakeCollisionBIH(dp_model_t *model, qboolean userendersurfaces, bih_t
        int triangleindex;
        int bihleafindex;
        int nummodelbrushes = model->nummodelbrushes;
-       int nummodelsurfaces = model->nummodelsurfaces;
        const int *e;
        const int *collisionelement3i;
        const float *collisionvertex3f;
@@ -7277,20 +7210,20 @@ bih_t *Mod_MakeCollisionBIH(dp_model_t *model, qboolean userendersurfaces, bih_t
        bihnumleafs = 0;
        if (userendersurfaces)
        {
-               for (j = 0, surface = model->data_surfaces + model->firstmodelsurface;j < nummodelsurfaces;j++, surface++)
-                       bihnumleafs += surface->num_triangles;
+               for (j = model->submodelsurfaces_start;j < model->submodelsurfaces_end;j++)
+                       bihnumleafs += model->data_surfaces[j].num_triangles;
        }
        else
        {
                for (brushindex = 0, brush = model->brush.data_brushes + brushindex+model->firstmodelbrush;brushindex < nummodelbrushes;brushindex++, brush++)
                        if (brush->colbrushf)
                                bihnumleafs++;
-               for (j = 0, surface = model->data_surfaces + model->firstmodelsurface;j < nummodelsurfaces;j++, surface++)
+               for (j = model->submodelsurfaces_start;j < model->submodelsurfaces_end;j++)
                {
-                       if (surface->texture->basematerialflags & MATERIALFLAG_MESHCOLLISIONS)
-                               bihnumleafs += surface->num_triangles + surface->num_collisiontriangles;
+                       if (model->data_surfaces[j].texture->basematerialflags & MATERIALFLAG_MESHCOLLISIONS)
+                               bihnumleafs += model->data_surfaces[j].num_triangles + model->data_surfaces[j].num_collisiontriangles;
                        else
-                               bihnumleafs += surface->num_collisiontriangles;
+                               bihnumleafs += model->data_surfaces[j].num_collisiontriangles;
                }
        }
 
@@ -7306,8 +7239,9 @@ bih_t *Mod_MakeCollisionBIH(dp_model_t *model, qboolean userendersurfaces, bih_t
        // add render surfaces
        renderelement3i = model->surfmesh.data_element3i;
        rendervertex3f = model->surfmesh.data_vertex3f;
-       for (j = 0, surface = model->data_surfaces + model->firstmodelsurface;j < nummodelsurfaces;j++, surface++)
+       for (j = model->submodelsurfaces_start; j < model->submodelsurfaces_end; j++)
        {
+               surface = model->data_surfaces + j;
                for (triangleindex = 0, e = renderelement3i + 3*surface->num_firsttriangle;triangleindex < surface->num_triangles;triangleindex++, e += 3)
                {
                        if (!userendersurfaces && !(surface->texture->basematerialflags & MATERIALFLAG_MESHCOLLISIONS))
@@ -7345,8 +7279,9 @@ bih_t *Mod_MakeCollisionBIH(dp_model_t *model, qboolean userendersurfaces, bih_t
                // add collision surfaces
                collisionelement3i = model->brush.data_collisionelement3i;
                collisionvertex3f = model->brush.data_collisionvertex3f;
-               for (j = 0, surface = model->data_surfaces + model->firstmodelsurface;j < nummodelsurfaces;j++, surface++)
+               for (j = model->submodelsurfaces_start; j < model->submodelsurfaces_end; j++)
                {
+                       surface = model->data_surfaces + j;
                        for (triangleindex = 0, e = collisionelement3i + 3*surface->num_firstcollisiontriangle;triangleindex < surface->num_collisiontriangles;triangleindex++, e += 3)
                        {
                                bihleafs[bihleafindex].type = BIH_COLLISIONTRIANGLE;
@@ -7459,7 +7394,7 @@ static void Mod_Q3BSP_RecursiveFindNumLeafs(mnode_t *node)
                loadmodel->brush.num_leafs = numleafs;
 }
 
-static void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
+static void Mod_Q3BSP_Load(model_t *mod, void *buffer, void *bufferend)
 {
        int i, j, lumps;
        q3dheader_t *header;
@@ -7595,9 +7530,10 @@ static void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
        Mod_Q3BSP_RecursiveFindNumLeafs(loadmodel->brush.data_nodes);
 
        if (loadmodel->brush.numsubmodels)
-               loadmodel->brush.submodels = (dp_model_t **)Mem_Alloc(loadmodel->mempool, loadmodel->brush.numsubmodels * sizeof(dp_model_t *));
+               loadmodel->brush.submodels = (model_t **)Mem_Alloc(loadmodel->mempool, loadmodel->brush.numsubmodels * sizeof(model_t *));
 
        mod = loadmodel;
+       mod->modelsurfaces_sorted = (int*)Mem_Alloc(loadmodel->mempool, mod->num_surfaces * sizeof(*mod->modelsurfaces_sorted));
        for (i = 0;i < loadmodel->brush.numsubmodels;i++)
        {
                if (i > 0)
@@ -7628,12 +7564,10 @@ static void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
                        loadmodel->brush.submodels[i] = mod;
 
                // make the model surface list (used by shadowing/lighting)
-               mod->firstmodelsurface = mod->brushq3.data_models[i].firstface;
-               mod->nummodelsurfaces = mod->brushq3.data_models[i].numfaces;
+               mod->submodelsurfaces_start = mod->brushq3.data_models[i].firstface;
+               mod->submodelsurfaces_end = mod->brushq3.data_models[i].firstface + mod->brushq3.data_models[i].numfaces;
                mod->firstmodelbrush = mod->brushq3.data_models[i].firstbrush;
                mod->nummodelbrushes = mod->brushq3.data_models[i].numbrushes;
-               mod->sortedmodelsurfaces = (int *)Mem_Alloc(loadmodel->mempool, mod->nummodelsurfaces * sizeof(*mod->sortedmodelsurfaces));
-               Mod_MakeSortedSurfaces(mod);
 
                VectorCopy(mod->brushq3.data_models[i].mins, mod->normalmins);
                VectorCopy(mod->brushq3.data_models[i].maxs, mod->normalmaxs);
@@ -7643,9 +7577,9 @@ static void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
                // outside the level - an unimportant concern)
 
                //printf("Editing model %d... BEFORE re-bounding: %f %f %f - %f %f %f\n", i, mod->normalmins[0], mod->normalmins[1], mod->normalmins[2], mod->normalmaxs[0], mod->normalmaxs[1], mod->normalmaxs[2]);
-               for (j = 0;j < mod->nummodelsurfaces;j++)
+               for (j = mod->submodelsurfaces_start;j < mod->submodelsurfaces_end;j++)
                {
-                       const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface;
+                       const msurface_t *surface = mod->data_surfaces + j;
                        const float *v = mod->surfmesh.data_vertex3f + 3 * surface->num_firstvertex;
                        int k;
                        if (!surface->num_vertices)
@@ -7675,22 +7609,7 @@ static void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
                mod->radius = modelradius;
                mod->radius2 = modelradius * modelradius;
 
-               // this gets altered below if sky or water is used
-               mod->DrawSky = NULL;
-               mod->DrawAddWaterPlanes = NULL;
-
-               for (j = 0;j < mod->nummodelsurfaces;j++)
-                       if (mod->data_surfaces[j + mod->firstmodelsurface].texture->basematerialflags & MATERIALFLAG_SKY)
-                               break;
-               if (j < mod->nummodelsurfaces)
-                       mod->DrawSky = R_Mod_DrawSky;
-
-               for (j = 0;j < mod->nummodelsurfaces;j++)
-                       if (mod->data_surfaces[j + mod->firstmodelsurface].texture->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
-                               break;
-               if (j < mod->nummodelsurfaces)
-                       mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
-
+               Mod_SetDrawSkyAndWater(mod);
                Mod_MakeCollisionBIH(mod, false, &mod->collision_bih);
                Mod_MakeCollisionBIH(mod, true, &mod->render_bih);
 
@@ -7698,6 +7617,10 @@ static void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
                if (i == 0)
                        Mod_BuildVBOs();
        }
+       mod = loadmodel;
+
+       // make the model surface list (used by shadowing/lighting)
+       Mod_MakeSortedSurfaces(loadmodel);
 
        if (mod_q3bsp_sRGBlightmaps.integer)
        {
@@ -7726,7 +7649,7 @@ static void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
        Con_DPrintf("Stats for q3bsp model \"%s\": %i faces, %i nodes, %i leafs, %i clusters, %i clusterportals, mesh: %i vertices, %i triangles, %i surfaces\n", loadmodel->name, loadmodel->num_surfaces, loadmodel->brush.num_nodes, loadmodel->brush.num_leafs, mod->brush.num_pvsclusters, loadmodel->brush.num_portals, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->num_surfaces);
 }
 
-void Mod_IBSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
+void Mod_IBSP_Load(model_t *mod, void *buffer, void *bufferend)
 {
        int i = LittleLong(((int *)buffer)[1]);
        if (i == Q3BSPVERSION || i == Q3BSPVERSION_IG || i == Q3BSPVERSION_LIVE)
@@ -7737,7 +7660,12 @@ void Mod_IBSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
                Host_Error("Mod_IBSP_Load: unknown/unsupported version %i", i);
 }
 
-void Mod_MAP_Load(dp_model_t *mod, void *buffer, void *bufferend)
+void Mod_VBSP_Load(model_t *mod, void *buffer, void *bufferend)
+{
+       Host_Error("Mod_VBSP_Load: not yet implemented");
+}
+
+void Mod_MAP_Load(model_t *mod, void *buffer, void *bufferend)
 {
        Host_Error("Mod_MAP_Load: not yet implemented");
 }
@@ -7755,7 +7683,7 @@ objvertex_t;
 
 static unsigned char nobsp_pvs[1] = {1};
 
-void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend)
+void Mod_OBJ_Load(model_t *mod, void *buffer, void *bufferend)
 {
        const char *textbase = (char *)buffer, *text = textbase;
        char *s;
@@ -8168,9 +8096,9 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend)
        // allocate storage for final mesh data
        loadmodel->num_textures = numtextures * loadmodel->numskins;
        loadmodel->num_texturesperskin = numtextures;
-       data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + numtriangles * sizeof(int[3]) + (numvertices <= 65536 ? numtriangles * sizeof(unsigned short[3]) : 0) + numvertices * sizeof(float[14]) + loadmodel->brush.numsubmodels * sizeof(dp_model_t *));
-       loadmodel->brush.submodels = (dp_model_t **)data;data += loadmodel->brush.numsubmodels * sizeof(dp_model_t *);
-       loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
+       data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + numtriangles * sizeof(int[3]) + (numvertices <= 65536 ? numtriangles * sizeof(unsigned short[3]) : 0) + numvertices * sizeof(float[14]) + loadmodel->brush.numsubmodels * sizeof(model_t *));
+       loadmodel->brush.submodels = (model_t **)data;data += loadmodel->brush.numsubmodels * sizeof(model_t *);
+       loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
        loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
        loadmodel->surfmesh.num_vertices = numvertices;
        loadmodel->surfmesh.num_triangles = numtriangles;
@@ -8231,7 +8159,7 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->brush.data_pvsclusters = nobsp_pvs;
        //if (loadmodel->num_nodes) loadmodel->data_nodes = (mnode_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_nodes * sizeof(mnode_t));
        //loadmodel->data_leafsurfaces = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->num_leafsurfaces * sizeof(int));
-       loadmodel->brush.data_leafsurfaces = loadmodel->sortedmodelsurfaces;
+       loadmodel->brush.data_leafsurfaces = loadmodel->modelsurfaces_sorted;
        VectorCopy(loadmodel->normalmins, loadmodel->brush.data_leafs->mins);
        VectorCopy(loadmodel->normalmaxs, loadmodel->brush.data_leafs->maxs);
        loadmodel->brush.data_leafs->combinedsupercontents = 0; // FIXME?
@@ -8244,7 +8172,7 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->brush.supportwateralpha = true;
 
        if (loadmodel->brush.numsubmodels)
-               loadmodel->brush.submodels = (dp_model_t **)Mem_Alloc(loadmodel->mempool, loadmodel->brush.numsubmodels * sizeof(dp_model_t *));
+               loadmodel->brush.submodels = (model_t **)Mem_Alloc(loadmodel->mempool, loadmodel->brush.numsubmodels * sizeof(model_t *));
 
        mod = loadmodel;
        for (i = 0;i < loadmodel->brush.numsubmodels;i++)
@@ -8277,19 +8205,17 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend)
                        loadmodel->brush.submodels[i] = mod;
 
                // make the model surface list (used by shadowing/lighting)
-               mod->firstmodelsurface = submodelfirstsurface[i];
-               mod->nummodelsurfaces = submodelfirstsurface[i+1] - submodelfirstsurface[i];
+               mod->submodelsurfaces_start = submodelfirstsurface[i];
+               mod->submodelsurfaces_end = submodelfirstsurface[i+1];
                mod->firstmodelbrush = 0;
                mod->nummodelbrushes = 0;
-               mod->sortedmodelsurfaces = loadmodel->sortedmodelsurfaces + mod->firstmodelsurface;
-               Mod_MakeSortedSurfaces(mod);
 
                VectorClear(mod->normalmins);
                VectorClear(mod->normalmaxs);
                l = false;
-               for (j = 0;j < mod->nummodelsurfaces;j++)
+               for (j = mod->submodelsurfaces_start;j < mod->submodelsurfaces_end;j++)
                {
-                       const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface;
+                       const msurface_t *surface = mod->data_surfaces + j;
                        const float *v3f = mod->surfmesh.data_vertex3f + 3 * surface->num_firstvertex;
                        int k;
                        if (!surface->num_vertices)
@@ -8324,21 +8250,7 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend)
                mod->radius = modelradius;
                mod->radius2 = modelradius * modelradius;
 
-               // this gets altered below if sky or water is used
-               mod->DrawSky = NULL;
-               mod->DrawAddWaterPlanes = NULL;
-
-               for (j = 0;j < mod->nummodelsurfaces;j++)
-                       if (mod->data_surfaces[j + mod->firstmodelsurface].texture->basematerialflags & MATERIALFLAG_SKY)
-                               break;
-               if (j < mod->nummodelsurfaces)
-                       mod->DrawSky = R_Mod_DrawSky;
-
-               for (j = 0;j < mod->nummodelsurfaces;j++)
-                       if (mod->data_surfaces[j + mod->firstmodelsurface].texture->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
-                               break;
-               if (j < mod->nummodelsurfaces)
-                       mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
+               Mod_SetDrawSkyAndWater(mod);
 
                Mod_MakeCollisionBIH(mod, true, &mod->collision_bih);
                mod->render_bih = mod->collision_bih;
@@ -8350,5 +8262,8 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend)
        mod = loadmodel;
        Mem_Free(submodelfirstsurface);
 
+       // make the model surface list (used by shadowing/lighting)
+       Mod_MakeSortedSurfaces(loadmodel);
+
        Con_DPrintf("Stats for obj model \"%s\": %i faces, %i nodes, %i leafs, %i clusters, %i clusterportals, mesh: %i vertices, %i triangles, %i surfaces\n", loadmodel->name, loadmodel->num_surfaces, loadmodel->brush.num_nodes, loadmodel->brush.num_leafs, mod->brush.num_pvsclusters, loadmodel->brush.num_portals, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->num_surfaces);
 }