]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_shared.c
Also actually include the .enc file for the key.
[xonotic/darkplaces.git] / model_shared.c
index ab44ba1edb65f389af6051b4fb03b873f08145cb..e7d3228d13f8ed5e1fc377ccaf412ffaa1bea85c 100644 (file)
@@ -27,19 +27,42 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "r_shadow.h"
 #include "polygon.h"
 
-cvar_t r_mipskins = {CVAR_SAVE, "r_mipskins", "0", "mipmaps model skins so they render faster in the distance and do not display noise artifacts, can cause discoloration of skins if they contain undesirable border colors"};
-cvar_t r_mipnormalmaps = {CVAR_SAVE, "r_mipnormalmaps", "1", "mipmaps normalmaps (turning it off looks sharper but may have aliasing)"};
-cvar_t mod_generatelightmaps_unitspersample = {CVAR_SAVE, "mod_generatelightmaps_unitspersample", "8", "lightmap resolution"};
-cvar_t mod_generatelightmaps_borderpixels = {CVAR_SAVE, "mod_generatelightmaps_borderpixels", "2", "extra space around polygons to prevent sampling artifacts"};
-cvar_t mod_generatelightmaps_texturesize = {CVAR_SAVE, "mod_generatelightmaps_texturesize", "1024", "size of lightmap textures"};
-cvar_t mod_generatelightmaps_lightmapsamples = {CVAR_SAVE, "mod_generatelightmaps_lightmapsamples", "16", "number of shadow tests done per lightmap pixel"};
-cvar_t mod_generatelightmaps_vertexsamples = {CVAR_SAVE, "mod_generatelightmaps_vertexsamples", "16", "number of shadow tests done per vertex"};
-cvar_t mod_generatelightmaps_gridsamples = {CVAR_SAVE, "mod_generatelightmaps_gridsamples", "64", "number of shadow tests done per lightgrid cell"};
-cvar_t mod_generatelightmaps_lightmapradius = {CVAR_SAVE, "mod_generatelightmaps_lightmapradius", "16", "sampling area around each lightmap pixel"};
-cvar_t mod_generatelightmaps_vertexradius = {CVAR_SAVE, "mod_generatelightmaps_vertexradius", "16", "sampling area around each vertex"};
-cvar_t mod_generatelightmaps_gridradius = {CVAR_SAVE, "mod_generatelightmaps_gridradius", "64", "sampling area around each lightgrid cell center"};
-
-dp_model_t *loadmodel;
+cvar_t r_mipskins = {CF_CLIENT | CF_ARCHIVE, "r_mipskins", "0", "mipmaps model skins so they render faster in the distance and do not display noise artifacts, can cause discoloration of skins if they contain undesirable border colors"};
+cvar_t r_mipnormalmaps = {CF_CLIENT | CF_ARCHIVE, "r_mipnormalmaps", "1", "mipmaps normalmaps (turning it off looks sharper but may have aliasing)"};
+cvar_t mod_generatelightmaps_unitspersample = {CF_CLIENT | CF_ARCHIVE, "mod_generatelightmaps_unitspersample", "8", "lightmap resolution"};
+cvar_t mod_generatelightmaps_borderpixels = {CF_CLIENT | CF_ARCHIVE, "mod_generatelightmaps_borderpixels", "2", "extra space around polygons to prevent sampling artifacts"};
+cvar_t mod_generatelightmaps_texturesize = {CF_CLIENT | CF_ARCHIVE, "mod_generatelightmaps_texturesize", "1024", "size of lightmap textures"};
+cvar_t mod_generatelightmaps_lightmapsamples = {CF_CLIENT | CF_ARCHIVE, "mod_generatelightmaps_lightmapsamples", "16", "number of shadow tests done per lightmap pixel"};
+cvar_t mod_generatelightmaps_vertexsamples = {CF_CLIENT | CF_ARCHIVE, "mod_generatelightmaps_vertexsamples", "16", "number of shadow tests done per vertex"};
+cvar_t mod_generatelightmaps_gridsamples = {CF_CLIENT | CF_ARCHIVE, "mod_generatelightmaps_gridsamples", "64", "number of shadow tests done per lightgrid cell"};
+cvar_t mod_generatelightmaps_lightmapradius = {CF_CLIENT | CF_ARCHIVE, "mod_generatelightmaps_lightmapradius", "16", "sampling area around each lightmap pixel"};
+cvar_t mod_generatelightmaps_vertexradius = {CF_CLIENT | CF_ARCHIVE, "mod_generatelightmaps_vertexradius", "16", "sampling area around each vertex"};
+cvar_t mod_generatelightmaps_gridradius = {CF_CLIENT | CF_ARCHIVE, "mod_generatelightmaps_gridradius", "64", "sampling area around each lightgrid cell center"};
+
+model_t *loadmodel;
+
+// Supported model formats
+static modloader_t loader[] =
+{
+       {"obj", NULL, 0, Mod_OBJ_Load},
+       {NULL, "IDPO", 4, Mod_IDP0_Load},
+       {NULL, "IDP2", 4, Mod_IDP2_Load},
+       {NULL, "IDP3", 4, Mod_IDP3_Load},
+       {NULL, "IDSP", 4, Mod_IDSP_Load},
+       {NULL, "IDS2", 4, Mod_IDS2_Load},
+       {NULL, "\035", 1, Mod_Q1BSP_Load},
+       {NULL, "\036", 1, Mod_HLBSP_Load},
+       {NULL, "BSP2", 4, Mod_BSP2_Load},
+       {NULL, "2PSB", 4, Mod_2PSB_Load},
+       {NULL, "IBSP", 4, Mod_IBSP_Load},
+       {NULL, "VBSP", 4, Mod_VBSP_Load},
+       {NULL, "ZYMOTICMODEL", 13, Mod_ZYMOTICMODEL_Load},
+       {NULL, "DARKPLACESMODEL", 16, Mod_DARKPLACESMODEL_Load},
+       {NULL, "PSKMODEL", 9, Mod_PSKMODEL_Load},
+       {NULL, "INTERQUAKEMODEL", 16, Mod_INTERQUAKEMODEL_Load},
+       {"map", NULL, 0, Mod_MAP_Load},
+       {NULL, NULL, 0, NULL}
+};
 
 static mempool_t *mod_mempool;
 static memexpandablearray_t models;
@@ -47,7 +70,7 @@ static memexpandablearray_t models;
 static mempool_t* q3shaders_mem;
 typedef struct q3shader_hash_entry_s
 {
-  q3shaderinfo_t shader;
+  shader_t shader;
   struct q3shader_hash_entry_s* chain;
 } q3shader_hash_entry_t;
 #define Q3SHADER_HASH_SIZE  1021
@@ -63,19 +86,19 @@ static void mod_start(void)
 {
        int i, count;
        int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
-       dp_model_t *mod;
+       model_t *mod;
 
-       SCR_PushLoadingScreen(false, "Loading models", 1.0);
+       SCR_PushLoadingScreen("Loading models", 1.0);
        count = 0;
        for (i = 0;i < nummodels;i++)
-               if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*')
+               if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*')
                        if (mod->used)
                                ++count;
        for (i = 0;i < nummodels;i++)
-               if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*')
+               if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*')
                        if (mod->used)
                        {
-                               SCR_PushLoadingScreen(true, mod->name, 1.0 / count);
+                               SCR_PushLoadingScreen(mod->name, 1.0 / count);
                                Mod_LoadModel(mod, true, false);
                                SCR_PopLoadingScreen(false);
                        }
@@ -86,10 +109,10 @@ static void mod_shutdown(void)
 {
        int i;
        int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
-       dp_model_t *mod;
+       model_t *mod;
 
        for (i = 0;i < nummodels;i++)
-               if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && (mod->loaded || mod->mempool))
+               if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && (mod->loaded || mod->mempool))
                        Mod_UnloadModel(mod);
 
        Mod_FreeQ3Shaders();
@@ -101,11 +124,11 @@ static void mod_newmap(void)
        msurface_t *surface;
        int i, j, k, l, surfacenum, ssize, tsize;
        int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
-       dp_model_t *mod;
+       model_t *mod;
 
        for (i = 0;i < nummodels;i++)
        {
-               if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->mempool)
+               if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->mempool)
                {
                        for (j = 0;j < mod->num_textures && mod->data_textures;j++)
                        {
@@ -127,7 +150,7 @@ static void mod_newmap(void)
 
        for (i = 0;i < nummodels;i++)
        {
-               if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->mempool && mod->data_surfaces)
+               if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->mempool && mod->data_surfaces)
                {
                        for (surfacenum = 0, surface = mod->data_surfaces;surfacenum < mod->num_surfaces;surfacenum++, surface++)
                        {
@@ -148,14 +171,14 @@ static void mod_newmap(void)
 Mod_Init
 ===============
 */
-static void Mod_Print(void);
-static void Mod_Precache (void);
-static void Mod_Decompile_f(void);
-static void Mod_GenerateLightmaps_f(void);
+static void Mod_Print_f(cmd_state_t *cmd);
+static void Mod_Precache_f(cmd_state_t *cmd);
+static void Mod_Decompile_f(cmd_state_t *cmd);
+static void Mod_GenerateLightmaps_f(cmd_state_t *cmd);
 void Mod_Init (void)
 {
        mod_mempool = Mem_AllocPool("modelinfo", 0, NULL);
-       Mem_ExpandableArray_NewArray(&models, mod_mempool, sizeof(dp_model_t), 16);
+       Mem_ExpandableArray_NewArray(&models, mod_mempool, sizeof(model_t), 16);
 
        Mod_BrushInit();
        Mod_AliasInit();
@@ -174,10 +197,10 @@ void Mod_Init (void)
        Cvar_RegisterVariable(&mod_generatelightmaps_vertexradius);
        Cvar_RegisterVariable(&mod_generatelightmaps_gridradius);
 
-       Cmd_AddCommand ("modellist", Mod_Print, "prints a list of loaded models");
-       Cmd_AddCommand ("modelprecache", Mod_Precache, "load a model");
-       Cmd_AddCommand ("modeldecompile", Mod_Decompile_f, "exports a model in several formats for editing purposes");
-       Cmd_AddCommand ("mod_generatelightmaps", Mod_GenerateLightmaps_f, "rebuilds lighting on current worldmodel");
+       Cmd_AddCommand(CF_CLIENT, "modellist", Mod_Print_f, "prints a list of loaded models");
+       Cmd_AddCommand(CF_CLIENT, "modelprecache", Mod_Precache_f, "load a model");
+       Cmd_AddCommand(CF_CLIENT, "modeldecompile", Mod_Decompile_f, "exports a model in several formats for editing purposes");
+       Cmd_AddCommand(CF_CLIENT, "mod_generatelightmaps", Mod_GenerateLightmaps_f, "rebuilds lighting on current worldmodel");
 }
 
 void Mod_RenderInit(void)
@@ -185,11 +208,11 @@ void Mod_RenderInit(void)
        R_RegisterModule("Models", mod_start, mod_shutdown, mod_newmap, NULL, NULL);
 }
 
-void Mod_UnloadModel (dp_model_t *mod)
+void Mod_UnloadModel (model_t *mod)
 {
        char name[MAX_QPATH];
-       qboolean used;
-       dp_model_t *parentmodel;
+       qbool used;
+       model_t *parentmodel;
 
        if (developer_loading.integer)
                Con_Printf("unloading model %s\n", mod->name);
@@ -199,21 +222,29 @@ void Mod_UnloadModel (dp_model_t *mod)
        used = mod->used;
        if (mod->mempool)
        {
-               if (mod->surfmesh.data_element3i_indexbuffer)
+               if (mod->surfmesh.data_element3i_indexbuffer && !mod->surfmesh.data_element3i_indexbuffer->isdynamic)
                        R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3i_indexbuffer);
                mod->surfmesh.data_element3i_indexbuffer = NULL;
-               if (mod->surfmesh.data_element3s_indexbuffer)
+               if (mod->surfmesh.data_element3s_indexbuffer && !mod->surfmesh.data_element3s_indexbuffer->isdynamic)
                        R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3s_indexbuffer);
                mod->surfmesh.data_element3s_indexbuffer = NULL;
-               if (mod->surfmesh.vbo_vertexbuffer)
-                       R_Mesh_DestroyMeshBuffer(mod->surfmesh.vbo_vertexbuffer);
-               mod->surfmesh.vbo_vertexbuffer = NULL;
+               if (mod->surfmesh.data_vertex3f_vertexbuffer && !mod->surfmesh.data_vertex3f_vertexbuffer->isdynamic)
+                       R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_vertex3f_vertexbuffer);
+               mod->surfmesh.data_vertex3f_vertexbuffer = NULL;
+               mod->surfmesh.data_svector3f_vertexbuffer = NULL;
+               mod->surfmesh.data_tvector3f_vertexbuffer = NULL;
+               mod->surfmesh.data_normal3f_vertexbuffer = NULL;
+               mod->surfmesh.data_texcoordtexture2f_vertexbuffer = NULL;
+               mod->surfmesh.data_texcoordlightmap2f_vertexbuffer = NULL;
+               mod->surfmesh.data_lightmapcolor4f_vertexbuffer = NULL;
+               mod->surfmesh.data_skeletalindex4ub_vertexbuffer = NULL;
+               mod->surfmesh.data_skeletalweight4ub_vertexbuffer = NULL;
        }
        // free textures/memory attached to the model
        R_FreeTexturePool(&mod->texturepool);
        Mem_FreePool(&mod->mempool);
        // clear the struct to make it available
-       memset(mod, 0, sizeof(dp_model_t));
+       memset(mod, 0, sizeof(model_t));
        // restore the fields we want to preserve
        strlcpy(mod->name, name, sizeof(mod->name));
        mod->brush.parentmodel = parentmodel;
@@ -227,7 +258,7 @@ static void R_Model_Null_Draw(entity_render_t *ent)
 }
 
 
-typedef void (*mod_framegroupify_parsegroups_t) (unsigned int i, int start, int len, float fps, qboolean loop, const char *name, void *pass);
+typedef void (*mod_framegroupify_parsegroups_t) (unsigned int i, int start, int len, float fps, qbool loop, const char *name, void *pass);
 
 static int Mod_FrameGroupify_ParseGroups(const char *buf, mod_framegroupify_parsegroups_t cb, void *pass)
 {
@@ -235,7 +266,7 @@ static int Mod_FrameGroupify_ParseGroups(const char *buf, mod_framegroupify_pars
        int start, len;
        float fps;
        unsigned int i;
-       qboolean loop;
+       qbool loop;
        char name[64];
 
        bufptr = buf;
@@ -302,9 +333,9 @@ static int Mod_FrameGroupify_ParseGroups(const char *buf, mod_framegroupify_pars
        return i;
 }
 
-static void Mod_FrameGroupify_ParseGroups_Store (unsigned int i, int start, int len, float fps, qboolean loop, const char *name, void *pass)
+static void Mod_FrameGroupify_ParseGroups_Store (unsigned int i, int start, int len, float fps, qbool loop, const char *name, void *pass)
 {
-       dp_model_t *mod = (dp_model_t *) pass;
+       model_t *mod = (model_t *) pass;
        animscene_t *anim = &mod->animscenes[i];
        if(name)
                strlcpy(anim->name, name, sizeof(anim[i].name));
@@ -317,7 +348,7 @@ static void Mod_FrameGroupify_ParseGroups_Store (unsigned int i, int start, int
        //Con_Printf("frame group %d is %d %d %f %d\n", i, start, len, fps, loop);
 }
 
-static void Mod_FrameGroupify(dp_model_t *mod, const char *buf)
+static void Mod_FrameGroupify(model_t *mod, const char *buf)
 {
        unsigned int cnt;
 
@@ -338,7 +369,7 @@ static void Mod_FrameGroupify(dp_model_t *mod, const char *buf)
        Mod_FrameGroupify_ParseGroups(buf, Mod_FrameGroupify_ParseGroups_Store, mod);
 }
 
-static void Mod_FindPotentialDeforms(dp_model_t *mod)
+static void Mod_FindPotentialDeforms(model_t *mod)
 {
        int i, j;
        texture_t *texture;
@@ -372,9 +403,8 @@ Mod_LoadModel
 Loads a model
 ==================
 */
-dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk)
+model_t *Mod_LoadModel(model_t *mod, qbool crash, qbool checkdisk)
 {
-       int num;
        unsigned int crc;
        void *buf;
        fs_offset_t filesize = 0;
@@ -450,9 +480,9 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk)
        if (developer_loading.integer)
                Con_Printf("loading model %s\n", mod->name);
        
-       SCR_PushLoadingScreen(true, mod->name, 1);
+       SCR_PushLoadingScreen(mod->name, 1);
 
-       // LordHavoc: unload the existing model in this slot (if there is one)
+       // LadyHavoc: unload the existing model in this slot (if there is one)
        if (mod->loaded || mod->mempool)
                Mod_UnloadModel(mod);
 
@@ -482,46 +512,46 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk)
 
        if (buf)
        {
+               int i;
+               const char *ext = FS_FileExtension(mod->name);  
                char *bufend = (char *)buf + filesize;
-
                // all models use memory, so allocate a memory pool
                mod->mempool = Mem_AllocPool(mod->name, 0, NULL);
 
-               num = LittleLong(*((int *)buf));
-               // call the apropriate loader
+               // We need to have a reference to the base model in case we're parsing submodels
                loadmodel = mod;
-               if (!strcasecmp(FS_FileExtension(mod->name), "obj")) Mod_OBJ_Load(mod, buf, bufend);
-               else if (!memcmp(buf, "IDPO", 4)) Mod_IDP0_Load(mod, buf, bufend);
-               else if (!memcmp(buf, "IDP2", 4)) Mod_IDP2_Load(mod, buf, bufend);
-               else if (!memcmp(buf, "IDP3", 4)) Mod_IDP3_Load(mod, buf, bufend);
-               else if (!memcmp(buf, "IDSP", 4)) Mod_IDSP_Load(mod, buf, bufend);
-               else if (!memcmp(buf, "IDS2", 4)) Mod_IDS2_Load(mod, buf, bufend);
-               else if (!memcmp(buf, "IBSP", 4)) Mod_IBSP_Load(mod, buf, bufend);
-               else if (!memcmp(buf, "ZYMOTICMODEL", 12)) Mod_ZYMOTICMODEL_Load(mod, buf, bufend);
-               else if (!memcmp(buf, "DARKPLACESMODEL", 16)) Mod_DARKPLACESMODEL_Load(mod, buf, bufend);
-               else if (!memcmp(buf, "ACTRHEAD", 8)) Mod_PSKMODEL_Load(mod, buf, bufend);
-               else if (!memcmp(buf, "INTERQUAKEMODEL", 16)) Mod_INTERQUAKEMODEL_Load(mod, buf, bufend);
-               else if (strlen(mod->name) >= 4 && !strcmp(mod->name + strlen(mod->name) - 4, ".map")) Mod_MAP_Load(mod, buf, bufend);
-               else if (num == BSPVERSION || num == 30 || !memcmp(buf, "BSP2", 4) || !memcmp(buf, "2PSB", 4)) Mod_Q1BSP_Load(mod, buf, bufend);
-               else Con_Printf("Mod_LoadModel: model \"%s\" is of unknown/unsupported type\n", mod->name);
-               Mem_Free(buf);
-
-               Mod_FindPotentialDeforms(mod);
-
-               buf = FS_LoadFile(va(vabuf, sizeof(vabuf), "%s.framegroups", mod->name), tempmempool, false, &filesize);
-               if(buf)
+
+               // Call the appropriate loader. Try matching magic bytes.
+               for (i = 0; loader[i].Load; i++)
                {
-                       Mod_FrameGroupify(mod, (const char *)buf);
-                       Mem_Free(buf);
-               }
+                       // Headerless formats can just load based on extension. Otherwise match the magic string.
+                       if((loader[i].extension && !strcasecmp(ext, loader[i].extension) && !loader[i].header) ||
+                          (loader[i].header && !memcmp(buf, loader[i].header, loader[i].headersize)))
+                       {
+                               // Matched. Load it.
+                               loader[i].Load(mod, buf, bufend);
+                               Mem_Free(buf);
 
-               Mod_BuildVBOs();
+                               Mod_FindPotentialDeforms(mod);
+
+                               buf = FS_LoadFile(va(vabuf, sizeof(vabuf), "%s.framegroups", mod->name), tempmempool, false, &filesize);
+                               if(buf)
+                               {
+                                       Mod_FrameGroupify(mod, (const char *)buf);
+                                       Mem_Free(buf);
+                               }
+
+                               Mod_SetDrawSkyAndWater(mod);
+                               Mod_BuildVBOs();
+                               break;
+                       }
+               }
+               if(!loader[i].Load)
+                       Con_Printf(CON_ERROR "Mod_LoadModel: model \"%s\" is of unknown/unsupported type\n", mod->name);
        }
        else if (crash)
-       {
-               // LordHavoc: Sys_Error was *ANNOYING*
-               Con_Printf ("Mod_LoadModel: %s not found\n", mod->name);
-       }
+               // LadyHavoc: Sys_Error was *ANNOYING*
+               Con_Printf (CON_ERROR "Mod_LoadModel: %s not found\n", mod->name);
 
        // no fatal errors occurred, so this model is ready to use.
        mod->loaded = true;
@@ -535,9 +565,9 @@ void Mod_ClearUsed(void)
 {
        int i;
        int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
-       dp_model_t *mod;
+       model_t *mod;
        for (i = 0;i < nummodels;i++)
-               if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0])
+               if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0])
                        mod->used = false;
 }
 
@@ -545,10 +575,10 @@ void Mod_PurgeUnused(void)
 {
        int i;
        int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
-       dp_model_t *mod;
+       model_t *mod;
        for (i = 0;i < nummodels;i++)
        {
-               if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && !mod->used)
+               if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && !mod->used)
                {
                        Mod_UnloadModel(mod);
                        Mem_ExpandableArray_FreeRecord(&models, mod);
@@ -562,18 +592,15 @@ Mod_FindName
 
 ==================
 */
-dp_model_t *Mod_FindName(const char *name, const char *parentname)
+model_t *Mod_FindName(const char *name, const char *parentname)
 {
        int i;
        int nummodels;
-       dp_model_t *mod;
+       model_t *mod;
 
        if (!parentname)
                parentname = "";
 
-       // if we're not dedicatd, the renderer calls will crash without video
-       Host_StartVideo();
-
        nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
 
        if (!name[0])
@@ -582,7 +609,7 @@ dp_model_t *Mod_FindName(const char *name, const char *parentname)
        // search the currently loaded models
        for (i = 0;i < nummodels;i++)
        {
-               if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && !strcmp(mod->name, name) && ((!mod->brush.parentmodel && !parentname[0]) || (mod->brush.parentmodel && parentname[0] && !strcmp(mod->brush.parentmodel->name, parentname))))
+               if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && !strcmp(mod->name, name) && ((!mod->brush.parentmodel && !parentname[0]) || (mod->brush.parentmodel && parentname[0] && !strcmp(mod->brush.parentmodel->name, parentname))))
                {
                        mod->used = true;
                        return mod;
@@ -590,7 +617,7 @@ dp_model_t *Mod_FindName(const char *name, const char *parentname)
        }
 
        // no match found, create a new one
-       mod = (dp_model_t *) Mem_ExpandableArray_AllocRecord(&models);
+       mod = (model_t *) Mem_ExpandableArray_AllocRecord(&models);
        strlcpy(mod->name, name, sizeof(mod->name));
        if (parentname[0])
                mod->brush.parentmodel = Mod_FindName(parentname, NULL);
@@ -601,6 +628,8 @@ dp_model_t *Mod_FindName(const char *name, const char *parentname)
        return mod;
 }
 
+extern qbool vid_opened;
+
 /*
 ==================
 Mod_ForName
@@ -608,9 +637,14 @@ Mod_ForName
 Loads in a model for the given name
 ==================
 */
-dp_model_t *Mod_ForName(const char *name, qboolean crash, qboolean checkdisk, const char *parentname)
+model_t *Mod_ForName(const char *name, qbool crash, qbool checkdisk, const char *parentname)
 {
-       dp_model_t *model;
+       model_t *model;
+
+       // FIXME: So we don't crash if a server is started early.
+       if(!vid_opened)
+               CL_StartVideo();
+
        model = Mod_FindName(name, parentname);
        if (!model->loaded || checkdisk)
                Mod_LoadModel(model, crash, checkdisk);
@@ -628,17 +662,17 @@ void Mod_Reload(void)
 {
        int i, count;
        int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
-       dp_model_t *mod;
+       model_t *mod;
 
-       SCR_PushLoadingScreen(false, "Reloading models", 1.0);
+       SCR_PushLoadingScreen("Reloading models", 1.0);
        count = 0;
        for (i = 0;i < nummodels;i++)
-               if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used)
+               if ((mod = (model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used)
                        ++count;
        for (i = 0;i < nummodels;i++)
-               if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used)
+               if ((mod = (model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used)
                {
-                       SCR_PushLoadingScreen(true, mod->name, 1.0 / count);
+                       SCR_PushLoadingScreen(mod->name, 1.0 / count);
                        Mod_LoadModel(mod, true, true);
                        SCR_PopLoadingScreen(false);
                }
@@ -655,16 +689,16 @@ unsigned char *mod_base;
 Mod_Print
 ================
 */
-static void Mod_Print(void)
+static void Mod_Print_f(cmd_state_t *cmd)
 {
        int i;
        int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
-       dp_model_t *mod;
+       model_t *mod;
 
        Con_Print("Loaded models:\n");
        for (i = 0;i < nummodels;i++)
        {
-               if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*')
+               if ((mod = (model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*')
                {
                        if (mod->brush.numsubmodels)
                                Con_Printf("%4iK %s (%i submodels)\n", mod->mempool ? (int)((mod->mempool->totalsize + 1023) / 1024) : 0, mod->name, mod->brush.numsubmodels);
@@ -679,10 +713,10 @@ static void Mod_Print(void)
 Mod_Precache
 ================
 */
-static void Mod_Precache(void)
+static void Mod_Precache_f(cmd_state_t *cmd)
 {
-       if (Cmd_Argc() == 2)
-               Mod_ForName(Cmd_Argv(1), false, true, Cmd_Argv(1)[0] == '*' ? cl.model_name[1] : NULL);
+       if (Cmd_Argc(cmd) == 2)
+               Mod_ForName(Cmd_Argv(cmd, 1), false, true, Cmd_Argv(cmd, 1)[0] == '*' ? cl.model_name[1] : NULL);
        else
                Con_Print("usage: modelprecache <filename>\n");
 }
@@ -701,7 +735,7 @@ int Mod_BuildVertexRemapTableFromElements(int numelements, const int *elements,
        return count;
 }
 
-qboolean Mod_ValidateElements(int *element3i, unsigned short *element3s, int numtriangles, int firstvertex, int numvertices, const char *filename, int fileline)
+qbool Mod_ValidateElements(int *element3i, unsigned short *element3s, int numtriangles, int firstvertex, int numvertices, const char *filename, int fileline)
 {
        int first = firstvertex, last = first + numvertices - 1, numelements = numtriangles * 3;
        int i;
@@ -743,10 +777,10 @@ qboolean Mod_ValidateElements(int *element3i, unsigned short *element3s, int num
        }
        if (invalidintcount || invalidshortcount || invalidmismatchcount)
        {
-               Con_Printf("Mod_ValidateElements(%i, %i, %i, %p, %p) called at %s:%d", numelements, first, last, element3i, element3s, filename, fileline);
+               Con_Printf("Mod_ValidateElements(%i, %i, %i, %p, %p) called at %s:%d", numelements, first, last, (void *)element3i, (void *)element3s, filename, fileline);
                Con_Printf(", %i elements are invalid in element3i (example: element3i[%i] == %i)", invalidintcount, invalidintexample, element3i ? element3i[invalidintexample] : 0);
                Con_Printf(", %i elements are invalid in element3s (example: element3s[%i] == %i)", invalidshortcount, invalidshortexample, element3s ? element3s[invalidshortexample] : 0);
-               Con_Printf(", %i elements mismatch between element3i and element3s (example: element3s[%i] is %i and element3i[i] is %i)", invalidmismatchcount, invalidmismatchexample, element3i ? element3i[invalidmismatchexample] : 0, invalidmismatchexample, element3s ? element3s[invalidmismatchexample] : 0);
+               Con_Printf(", %i elements mismatch between element3i and element3s (example: element3s[%i] is %i and element3i[%i] is %i)", invalidmismatchcount, invalidmismatchexample, element3s ? element3s[invalidmismatchexample] : 0, invalidmismatchexample, element3i ? element3i[invalidmismatchexample] : 0);
                Con_Print(".  Please debug the engine code - these elements have been modified to not crash, but nothing more.\n");
 
                // edit the elements to make them safer, as the driver will crash otherwise
@@ -769,7 +803,7 @@ qboolean Mod_ValidateElements(int *element3i, unsigned short *element3s, int num
 }
 
 // warning: this is an expensive function!
-void Mod_BuildNormals(int firstvertex, int numvertices, int numtriangles, const float *vertex3f, const int *elements, float *normal3f, qboolean areaweighting)
+void Mod_BuildNormals(int firstvertex, int numvertices, int numtriangles, const float *vertex3f, const int *elements, float *normal3f, qbool areaweighting)
 {
        int i, j;
        const int *element;
@@ -856,7 +890,7 @@ static void Mod_BuildBumpVectors(const float *v0, const float *v1, const float *
 #endif
 
 // warning: this is a very expensive function!
-void Mod_BuildTextureVectorsFromNormals(int firstvertex, int numvertices, int numtriangles, const float *vertex3f, const float *texcoord2f, const float *normal3f, const int *elements, float *svector3f, float *tvector3f, qboolean areaweighting)
+void Mod_BuildTextureVectorsFromNormals(int firstvertex, int numvertices, int numtriangles, const float *vertex3f, const float *texcoord2f, const float *normal3f, const int *elements, float *svector3f, float *tvector3f, qbool areaweighting)
 {
        int i, tnum;
        float sdir[3], tdir[3], normal[3], *svec, *tvec;
@@ -936,7 +970,7 @@ void Mod_BuildTextureVectorsFromNormals(int firstvertex, int numvertices, int nu
        }
 }
 
-void Mod_AllocSurfMesh(mempool_t *mempool, int numvertices, int numtriangles, qboolean lightmapoffsets, qboolean vertexcolors)
+void Mod_AllocSurfMesh(mempool_t *mempool, int numvertices, int numtriangles, qbool lightmapoffsets, qbool vertexcolors)
 {
        unsigned char *data;
        data = (unsigned char *)Mem_Alloc(mempool, numvertices * (3 + 3 + 3 + 3 + 2 + 2 + (vertexcolors ? 4 : 0)) * sizeof(float) + numvertices * (lightmapoffsets ? 1 : 0) * sizeof(int) + numtriangles * sizeof(int[3]) + (numvertices <= 65536 ? numtriangles * sizeof(unsigned short[3]) : 0));
@@ -963,25 +997,11 @@ void Mod_AllocSurfMesh(mempool_t *mempool, int numvertices, int numtriangles, qb
        }
 }
 
-shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts, int maxtriangles, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, int light, int expandable)
+shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts, int maxtriangles)
 {
        shadowmesh_t *newmesh;
-       unsigned char *data;
-       int size;
-       size = sizeof(shadowmesh_t);
-       size += maxverts * sizeof(float[3]);
-       if (light)
-               size += maxverts * sizeof(float[11]);
-       size += maxtriangles * sizeof(int[3]);
-       if (maxverts <= 65536)
-               size += maxtriangles * sizeof(unsigned short[3]);
-       if (expandable)
-               size += SHADOWMESHVERTEXHASH * sizeof(shadowmeshvertexhash_t *) + maxverts * sizeof(shadowmeshvertexhash_t);
-       data = (unsigned char *)Mem_Alloc(mempool, size);
-       newmesh = (shadowmesh_t *)data;data += sizeof(*newmesh);
-       newmesh->map_diffuse = map_diffuse;
-       newmesh->map_specular = map_specular;
-       newmesh->map_normal = map_normal;
+       newmesh = (shadowmesh_t *)Mem_Alloc(mempool, sizeof(shadowmesh_t));
+       newmesh->mempool = mempool;
        newmesh->maxverts = maxverts;
        newmesh->maxtriangles = maxtriangles;
        newmesh->numverts = 0;
@@ -989,152 +1009,60 @@ shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts, int maxtria
        memset(newmesh->sideoffsets, 0, sizeof(newmesh->sideoffsets));
        memset(newmesh->sidetotals, 0, sizeof(newmesh->sidetotals));
 
-       newmesh->vertex3f = (float *)data;data += maxverts * sizeof(float[3]);
-       if (light)
-       {
-               newmesh->svector3f = (float *)data;data += maxverts * sizeof(float[3]);
-               newmesh->tvector3f = (float *)data;data += maxverts * sizeof(float[3]);
-               newmesh->normal3f = (float *)data;data += maxverts * sizeof(float[3]);
-               newmesh->texcoord2f = (float *)data;data += maxverts * sizeof(float[2]);
-       }
-       newmesh->element3i = (int *)data;data += maxtriangles * sizeof(int[3]);
-       if (expandable)
-       {
-               newmesh->vertexhashtable = (shadowmeshvertexhash_t **)data;data += SHADOWMESHVERTEXHASH * sizeof(shadowmeshvertexhash_t *);
-               newmesh->vertexhashentries = (shadowmeshvertexhash_t *)data;data += maxverts * sizeof(shadowmeshvertexhash_t);
-       }
-       if (maxverts <= 65536)
-               newmesh->element3s = (unsigned short *)data;data += maxtriangles * sizeof(unsigned short[3]);
+       newmesh->vertex3f = (float *)Mem_Alloc(mempool, maxverts * sizeof(float[3]));
+       newmesh->element3i = (int *)Mem_Alloc(mempool, maxtriangles * sizeof(int[3]));
+       newmesh->vertexhashtable = (shadowmeshvertexhash_t **)Mem_Alloc(mempool, SHADOWMESHVERTEXHASH * sizeof(shadowmeshvertexhash_t *));
+       newmesh->vertexhashentries = (shadowmeshvertexhash_t *)Mem_Alloc(mempool, maxverts * sizeof(shadowmeshvertexhash_t));
        return newmesh;
 }
 
-shadowmesh_t *Mod_ShadowMesh_ReAlloc(mempool_t *mempool, shadowmesh_t *oldmesh, int light)
-{
-       shadowmesh_t *newmesh;
-       newmesh = Mod_ShadowMesh_Alloc(mempool, oldmesh->numverts, oldmesh->numtriangles, oldmesh->map_diffuse, oldmesh->map_specular, oldmesh->map_normal, light, false);
-       newmesh->numverts = oldmesh->numverts;
-       newmesh->numtriangles = oldmesh->numtriangles;
-       memcpy(newmesh->sideoffsets, oldmesh->sideoffsets, sizeof(oldmesh->sideoffsets));
-       memcpy(newmesh->sidetotals, oldmesh->sidetotals, sizeof(oldmesh->sidetotals));
-
-       memcpy(newmesh->vertex3f, oldmesh->vertex3f, oldmesh->numverts * sizeof(float[3]));
-       if (newmesh->svector3f && oldmesh->svector3f)
-       {
-               memcpy(newmesh->svector3f, oldmesh->svector3f, oldmesh->numverts * sizeof(float[3]));
-               memcpy(newmesh->tvector3f, oldmesh->tvector3f, oldmesh->numverts * sizeof(float[3]));
-               memcpy(newmesh->normal3f, oldmesh->normal3f, oldmesh->numverts * sizeof(float[3]));
-               memcpy(newmesh->texcoord2f, oldmesh->texcoord2f, oldmesh->numverts * sizeof(float[2]));
-       }
-       memcpy(newmesh->element3i, oldmesh->element3i, oldmesh->numtriangles * sizeof(int[3]));
-       return newmesh;
-}
-
-static int Mod_ShadowMesh_AddVertex(shadowmesh_t *mesh, float *vertex14f)
+int Mod_ShadowMesh_AddVertex(shadowmesh_t *mesh, const float *vertex3f)
 {
        int hashindex, vnum;
        shadowmeshvertexhash_t *hash;
        // this uses prime numbers intentionally
-       hashindex = (unsigned int) (vertex14f[0] * 2003 + vertex14f[1] * 4001 + vertex14f[2] * 7919) % SHADOWMESHVERTEXHASH;
+       hashindex = (unsigned int) (vertex3f[0] * 2003 + vertex3f[1] * 4001 + vertex3f[2] * 7919) % SHADOWMESHVERTEXHASH;
        for (hash = mesh->vertexhashtable[hashindex];hash;hash = hash->next)
        {
                vnum = (hash - mesh->vertexhashentries);
-               if ((mesh->vertex3f == NULL || (mesh->vertex3f[vnum * 3 + 0] == vertex14f[0] && mesh->vertex3f[vnum * 3 + 1] == vertex14f[1] && mesh->vertex3f[vnum * 3 + 2] == vertex14f[2]))
-                && (mesh->svector3f == NULL || (mesh->svector3f[vnum * 3 + 0] == vertex14f[3] && mesh->svector3f[vnum * 3 + 1] == vertex14f[4] && mesh->svector3f[vnum * 3 + 2] == vertex14f[5]))
-                && (mesh->tvector3f == NULL || (mesh->tvector3f[vnum * 3 + 0] == vertex14f[6] && mesh->tvector3f[vnum * 3 + 1] == vertex14f[7] && mesh->tvector3f[vnum * 3 + 2] == vertex14f[8]))
-                && (mesh->normal3f == NULL || (mesh->normal3f[vnum * 3 + 0] == vertex14f[9] && mesh->normal3f[vnum * 3 + 1] == vertex14f[10] && mesh->normal3f[vnum * 3 + 2] == vertex14f[11]))
-                && (mesh->texcoord2f == NULL || (mesh->texcoord2f[vnum * 2 + 0] == vertex14f[12] && mesh->texcoord2f[vnum * 2 + 1] == vertex14f[13])))
+               if (mesh->vertex3f[vnum * 3 + 0] == vertex3f[0] && mesh->vertex3f[vnum * 3 + 1] == vertex3f[1] && mesh->vertex3f[vnum * 3 + 2] == vertex3f[2])
                        return hash - mesh->vertexhashentries;
        }
        vnum = mesh->numverts++;
        hash = mesh->vertexhashentries + vnum;
        hash->next = mesh->vertexhashtable[hashindex];
        mesh->vertexhashtable[hashindex] = hash;
-       if (mesh->vertex3f) {mesh->vertex3f[vnum * 3 + 0] = vertex14f[0];mesh->vertex3f[vnum * 3 + 1] = vertex14f[1];mesh->vertex3f[vnum * 3 + 2] = vertex14f[2];}
-       if (mesh->svector3f) {mesh->svector3f[vnum * 3 + 0] = vertex14f[3];mesh->svector3f[vnum * 3 + 1] = vertex14f[4];mesh->svector3f[vnum * 3 + 2] = vertex14f[5];}
-       if (mesh->tvector3f) {mesh->tvector3f[vnum * 3 + 0] = vertex14f[6];mesh->tvector3f[vnum * 3 + 1] = vertex14f[7];mesh->tvector3f[vnum * 3 + 2] = vertex14f[8];}
-       if (mesh->normal3f) {mesh->normal3f[vnum * 3 + 0] = vertex14f[9];mesh->normal3f[vnum * 3 + 1] = vertex14f[10];mesh->normal3f[vnum * 3 + 2] = vertex14f[11];}
-       if (mesh->texcoord2f) {mesh->texcoord2f[vnum * 2 + 0] = vertex14f[12];mesh->texcoord2f[vnum * 2 + 1] = vertex14f[13];}
+       mesh->vertex3f[vnum * 3 + 0] = vertex3f[0];
+       mesh->vertex3f[vnum * 3 + 1] = vertex3f[1];
+       mesh->vertex3f[vnum * 3 + 2] = vertex3f[2];
        return vnum;
 }
 
-static void Mod_ShadowMesh_AddTriangle(mempool_t *mempool, shadowmesh_t *mesh, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, float *vertex14f)
+void Mod_ShadowMesh_AddMesh(shadowmesh_t *mesh, const float *vertex3f, int numtris, const int *element3i)
 {
-       if (mesh->numtriangles == 0)
-       {
-               // set the properties on this empty mesh to be more favorable...
-               // (note: this case only occurs for the first triangle added to a new mesh chain)
-               mesh->map_diffuse = map_diffuse;
-               mesh->map_specular = map_specular;
-               mesh->map_normal = map_normal;
-       }
-       while (mesh->map_diffuse != map_diffuse || mesh->map_specular != map_specular || mesh->map_normal != map_normal || mesh->numverts + 3 > mesh->maxverts || mesh->numtriangles + 1 > mesh->maxtriangles)
-       {
-               if (mesh->next == NULL)
-                       mesh->next = Mod_ShadowMesh_Alloc(mempool, max(mesh->maxverts, 300), max(mesh->maxtriangles, 100), map_diffuse, map_specular, map_normal, mesh->svector3f != NULL, true);
-               mesh = mesh->next;
-       }
-       mesh->element3i[mesh->numtriangles * 3 + 0] = Mod_ShadowMesh_AddVertex(mesh, vertex14f + 14 * 0);
-       mesh->element3i[mesh->numtriangles * 3 + 1] = Mod_ShadowMesh_AddVertex(mesh, vertex14f + 14 * 1);
-       mesh->element3i[mesh->numtriangles * 3 + 2] = Mod_ShadowMesh_AddVertex(mesh, vertex14f + 14 * 2);
-       mesh->numtriangles++;
-}
+       int i;
 
-void Mod_ShadowMesh_AddMesh(mempool_t *mempool, shadowmesh_t *mesh, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, int numtris, const int *element3i)
-{
-       int i, j, e;
-       float vbuf[3*14], *v;
-       memset(vbuf, 0, sizeof(vbuf));
        for (i = 0;i < numtris;i++)
        {
-               for (j = 0, v = vbuf;j < 3;j++, v += 14)
-               {
-                       e = *element3i++;
-                       if (vertex3f)
-                       {
-                               v[0] = vertex3f[e * 3 + 0];
-                               v[1] = vertex3f[e * 3 + 1];
-                               v[2] = vertex3f[e * 3 + 2];
-                       }
-                       if (svector3f)
-                       {
-                               v[3] = svector3f[e * 3 + 0];
-                               v[4] = svector3f[e * 3 + 1];
-                               v[5] = svector3f[e * 3 + 2];
-                       }
-                       if (tvector3f)
-                       {
-                               v[6] = tvector3f[e * 3 + 0];
-                               v[7] = tvector3f[e * 3 + 1];
-                               v[8] = tvector3f[e * 3 + 2];
-                       }
-                       if (normal3f)
-                       {
-                               v[9] = normal3f[e * 3 + 0];
-                               v[10] = normal3f[e * 3 + 1];
-                               v[11] = normal3f[e * 3 + 2];
-                       }
-                       if (texcoord2f)
-                       {
-                               v[12] = texcoord2f[e * 2 + 0];
-                               v[13] = texcoord2f[e * 2 + 1];
-                       }
-               }
-               Mod_ShadowMesh_AddTriangle(mempool, mesh, map_diffuse, map_specular, map_normal, vbuf);
+               mesh->element3i[mesh->numtriangles * 3 + 0] = Mod_ShadowMesh_AddVertex(mesh, vertex3f + 3 * element3i[i * 3 + 0]);
+               mesh->element3i[mesh->numtriangles * 3 + 1] = Mod_ShadowMesh_AddVertex(mesh, vertex3f + 3 * element3i[i * 3 + 1]);
+               mesh->element3i[mesh->numtriangles * 3 + 2] = Mod_ShadowMesh_AddVertex(mesh, vertex3f + 3 * element3i[i * 3 + 2]);
+               mesh->numtriangles++;
        }
 
        // the triangle calculation can take a while, so let's do a keepalive here
        CL_KeepaliveMessage(false);
 }
 
-shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int maxverts, int maxtriangles, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, int light, int expandable)
+shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int maxverts, int maxtriangles)
 {
        // the preparation before shadow mesh initialization can take a while, so let's do a keepalive here
        CL_KeepaliveMessage(false);
 
-       return Mod_ShadowMesh_Alloc(mempool, maxverts, maxtriangles, map_diffuse, map_specular, map_normal, light, expandable);
+       return Mod_ShadowMesh_Alloc(mempool, maxverts, maxtriangles);
 }
 
-static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh, mempool_t *mempool)
+static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh)
 {
        if (!mesh->numverts)
                return;
@@ -1142,24 +1070,6 @@ static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh, mempool_t *mempool)
        // make sure we don't crash inside the driver if something went wrong, as it's annoying to debug
        Mod_ValidateElements(mesh->element3i, mesh->element3s, mesh->numtriangles, 0, mesh->numverts, __FILE__, __LINE__);
 
-       // build r_vertexmesh_t array
-       // (compressed interleaved array for D3D)
-       if (!mesh->vertexmesh && mesh->texcoord2f && vid.useinterleavedarrays)
-       {
-               int vertexindex;
-               int numvertices = mesh->numverts;
-               r_vertexmesh_t *vertexmesh;
-               mesh->vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(mempool, numvertices * sizeof(*mesh->vertexmesh));
-               for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexmesh++)
-               {
-                       VectorCopy(mesh->vertex3f + 3*vertexindex, vertexmesh->vertex3f);
-                       VectorScale(mesh->svector3f + 3*vertexindex, 1.0f, vertexmesh->svector3f);
-                       VectorScale(mesh->tvector3f + 3*vertexindex, 1.0f, vertexmesh->tvector3f);
-                       VectorScale(mesh->normal3f + 3*vertexindex, 1.0f, vertexmesh->normal3f);
-                       Vector2Copy(mesh->texcoord2f + 2*vertexindex, vertexmesh->texcoordtexture2f);
-               }
-       }
-
        // upload short indices as a buffer
        if (mesh->element3s && !mesh->element3s_indexbuffer)
                mesh->element3s_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3s, mesh->numtriangles * sizeof(short[3]), "shadowmesh", true, false, false, true);
@@ -1173,96 +1083,77 @@ static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh, mempool_t *mempool)
        // is this wise?  the texcoordtexture2f array is used with dynamic
        // vertex/svector/tvector/normal when rendering animated models, on the
        // other hand animated models don't use a lot of vertices anyway...
-       if (!mesh->vbo_vertexbuffer && !vid.useinterleavedarrays)
+       if (!mesh->vbo_vertexbuffer)
        {
-               int size;
-               unsigned char *mem;
-               size = 0;
-               mesh->vbooffset_vertexmesh         = size;if (mesh->vertexmesh        ) size += mesh->numverts * sizeof(r_vertexmesh_t);
-               mesh->vbooffset_vertex3f           = size;if (mesh->vertex3f          ) size += mesh->numverts * sizeof(float[3]);
-               mesh->vbooffset_svector3f          = size;if (mesh->svector3f         ) size += mesh->numverts * sizeof(float[3]);
-               mesh->vbooffset_tvector3f          = size;if (mesh->tvector3f         ) size += mesh->numverts * sizeof(float[3]);
-               mesh->vbooffset_normal3f           = size;if (mesh->normal3f          ) size += mesh->numverts * sizeof(float[3]);
-               mesh->vbooffset_texcoord2f         = size;if (mesh->texcoord2f        ) size += mesh->numverts * sizeof(float[2]);
-               mem = (unsigned char *)Mem_Alloc(tempmempool, size);
-               if (mesh->vertexmesh        ) memcpy(mem + mesh->vbooffset_vertexmesh        , mesh->vertexmesh        , mesh->numverts * sizeof(r_vertexmesh_t));
-               if (mesh->vertex3f          ) memcpy(mem + mesh->vbooffset_vertex3f          , mesh->vertex3f          , mesh->numverts * sizeof(float[3]));
-               if (mesh->svector3f         ) memcpy(mem + mesh->vbooffset_svector3f         , mesh->svector3f         , mesh->numverts * sizeof(float[3]));
-               if (mesh->tvector3f         ) memcpy(mem + mesh->vbooffset_tvector3f         , mesh->tvector3f         , mesh->numverts * sizeof(float[3]));
-               if (mesh->normal3f          ) memcpy(mem + mesh->vbooffset_normal3f          , mesh->normal3f          , mesh->numverts * sizeof(float[3]));
-               if (mesh->texcoord2f        ) memcpy(mem + mesh->vbooffset_texcoord2f        , mesh->texcoord2f        , mesh->numverts * sizeof(float[2]));
-               mesh->vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, "shadowmesh", false, false, false, false);
-               Mem_Free(mem);
+               mesh->vbooffset_vertex3f = 0;
+               mesh->vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mesh->vertex3f, mesh->numverts * sizeof(float[3]), "shadowmesh", false, false, false, false);
        }
 }
 
-shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh, qboolean light, qboolean createvbo)
+shadowmesh_t *Mod_ShadowMesh_Finish(shadowmesh_t *mesh, qbool createvbo)
 {
-       shadowmesh_t *mesh, *newmesh, *nextmesh;
-       // reallocate meshs to conserve space
-       for (mesh = firstmesh, firstmesh = NULL;mesh;mesh = nextmesh)
+       if (mesh->numverts >= 3 && mesh->numtriangles >= 1)
        {
-               nextmesh = mesh->next;
-               if (mesh->numverts >= 3 && mesh->numtriangles >= 1)
+               if (mesh->vertexhashentries)
+                       Mem_Free(mesh->vertexhashentries);
+               mesh->vertexhashentries = NULL;
+               if (mesh->vertexhashtable)
+                       Mem_Free(mesh->vertexhashtable);
+               mesh->vertexhashtable = NULL;
+               if (mesh->maxverts > mesh->numverts)
                {
-                       newmesh = Mod_ShadowMesh_ReAlloc(mempool, mesh, light);
-                       newmesh->next = firstmesh;
-                       firstmesh = newmesh;
-                       if (newmesh->element3s)
-                       {
-                               int i;
-                               for (i = 0;i < newmesh->numtriangles*3;i++)
-                                       newmesh->element3s[i] = newmesh->element3i[i];
-                       }
-                       if (createvbo)
-                               Mod_ShadowMesh_CreateVBOs(newmesh, mempool);
+                       mesh->vertex3f = (float *)Mem_Realloc(mesh->mempool, mesh->vertex3f, mesh->numverts * sizeof(float[3]));
+                       mesh->maxverts = mesh->numverts;
+               }
+               if (mesh->maxtriangles > mesh->numtriangles)
+               {
+                       mesh->element3i = (int *)Mem_Realloc(mesh->mempool, mesh->element3i, mesh->numtriangles * sizeof(int[3]));
+                       mesh->maxtriangles = mesh->numtriangles;
+               }
+               if (mesh->numverts <= 65536)
+               {
+                       int i;
+                       mesh->element3s = (unsigned short *)Mem_Alloc(mesh->mempool, mesh->numtriangles * sizeof(unsigned short[3]));
+                       for (i = 0;i < mesh->numtriangles*3;i++)
+                               mesh->element3s[i] = mesh->element3i[i];
                }
-               Mem_Free(mesh);
+               if (createvbo)
+                       Mod_ShadowMesh_CreateVBOs(mesh);
        }
 
        // this can take a while, so let's do a keepalive here
        CL_KeepaliveMessage(false);
 
-       return firstmesh;
+       return mesh;
 }
 
-void Mod_ShadowMesh_CalcBBox(shadowmesh_t *firstmesh, vec3_t mins, vec3_t maxs, vec3_t center, float *radius)
+void Mod_ShadowMesh_CalcBBox(shadowmesh_t *mesh, vec3_t mins, vec3_t maxs, vec3_t center, float *radius)
 {
        int i;
-       shadowmesh_t *mesh;
        vec3_t nmins, nmaxs, ncenter, temp;
        float nradius2, dist2, *v;
        VectorClear(nmins);
        VectorClear(nmaxs);
        // calculate bbox
-       for (mesh = firstmesh;mesh;mesh = mesh->next)
+       VectorCopy(mesh->vertex3f, nmins);
+       VectorCopy(mesh->vertex3f, nmaxs);
+       for (i = 0, v = mesh->vertex3f;i < mesh->numverts;i++, v += 3)
        {
-               if (mesh == firstmesh)
-               {
-                       VectorCopy(mesh->vertex3f, nmins);
-                       VectorCopy(mesh->vertex3f, nmaxs);
-               }
-               for (i = 0, v = mesh->vertex3f;i < mesh->numverts;i++, v += 3)
-               {
-                       if (nmins[0] > v[0]) nmins[0] = v[0];if (nmaxs[0] < v[0]) nmaxs[0] = v[0];
-                       if (nmins[1] > v[1]) nmins[1] = v[1];if (nmaxs[1] < v[1]) nmaxs[1] = v[1];
-                       if (nmins[2] > v[2]) nmins[2] = v[2];if (nmaxs[2] < v[2]) nmaxs[2] = v[2];
-               }
+               if (nmins[0] > v[0]) { nmins[0] = v[0]; } if (nmaxs[0] < v[0]) { nmaxs[0] = v[0]; }
+               if (nmins[1] > v[1]) { nmins[1] = v[1]; } if (nmaxs[1] < v[1]) { nmaxs[1] = v[1]; }
+               if (nmins[2] > v[2]) { nmins[2] = v[2]; } if (nmaxs[2] < v[2]) { nmaxs[2] = v[2]; }
        }
        // calculate center and radius
        ncenter[0] = (nmins[0] + nmaxs[0]) * 0.5f;
        ncenter[1] = (nmins[1] + nmaxs[1]) * 0.5f;
        ncenter[2] = (nmins[2] + nmaxs[2]) * 0.5f;
        nradius2 = 0;
-       for (mesh = firstmesh;mesh;mesh = mesh->next)
+       for (i = 0, v = mesh->vertex3f;i < mesh->numverts;i++, v += 3)
        {
-               for (i = 0, v = mesh->vertex3f;i < mesh->numverts;i++, v += 3)
-               {
-                       VectorSubtract(v, ncenter, temp);
-                       dist2 = DotProduct(temp, temp);
-                       if (nradius2 < dist2)
-                               nradius2 = dist2;
-               }
+               VectorSubtract(v, ncenter, temp);
+               dist2 = DotProduct(temp, temp);
+               if (nradius2 < dist2)
+                       nradius2 = dist2;
        }
        // return data
        if (mins)
@@ -1277,18 +1168,64 @@ void Mod_ShadowMesh_CalcBBox(shadowmesh_t *firstmesh, vec3_t mins, vec3_t maxs,
 
 void Mod_ShadowMesh_Free(shadowmesh_t *mesh)
 {
-       shadowmesh_t *nextmesh;
-       for (;mesh;mesh = nextmesh)
+       if (mesh->element3i_indexbuffer)
+               R_Mesh_DestroyMeshBuffer(mesh->element3i_indexbuffer);
+       if (mesh->element3s_indexbuffer)
+               R_Mesh_DestroyMeshBuffer(mesh->element3s_indexbuffer);
+       if (mesh->vbo_vertexbuffer)
+               R_Mesh_DestroyMeshBuffer(mesh->vbo_vertexbuffer);
+       if (mesh->vertex3f)
+               Mem_Free(mesh->vertex3f);
+       if (mesh->element3i)
+               Mem_Free(mesh->element3i);
+       if (mesh->element3s)
+               Mem_Free(mesh->element3s);
+       if (mesh->vertexhashentries)
+               Mem_Free(mesh->vertexhashentries);
+       if (mesh->vertexhashtable)
+               Mem_Free(mesh->vertexhashtable);
+       Mem_Free(mesh);
+}
+
+void Mod_CreateCollisionMesh(model_t *mod)
+{
+       int k, numcollisionmeshtriangles;
+       qbool usesinglecollisionmesh = false;
+       const msurface_t *surface = NULL;
+
+       mempool_t *mempool = mod->mempool;
+       if (!mempool && mod->brush.parentmodel)
+               mempool = mod->brush.parentmodel->mempool;
+       // make a single combined collision mesh for physics engine use
+       // TODO rewrite this to use the collision brushes as source, to fix issues with e.g. common/caulk which creates no drawsurface
+       numcollisionmeshtriangles = 0;
+       for (k = mod->submodelsurfaces_start;k < mod->submodelsurfaces_end;k++)
+       {
+               surface = mod->data_surfaces + k;
+               if (!strcmp(surface->texture->name, "collision") || !strcmp(surface->texture->name, "collisionconvex")) // found collision mesh
+               {
+                       usesinglecollisionmesh = true;
+                       numcollisionmeshtriangles = surface->num_triangles;
+                       break;
+               }
+               if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID))
+                       continue;
+               numcollisionmeshtriangles += surface->num_triangles;
+       }
+       mod->brush.collisionmesh = Mod_ShadowMesh_Begin(mempool, numcollisionmeshtriangles * 3, numcollisionmeshtriangles);
+       if (usesinglecollisionmesh)
+               Mod_ShadowMesh_AddMesh(mod->brush.collisionmesh, mod->surfmesh.data_vertex3f, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
+       else
        {
-               if (mesh->element3i_indexbuffer)
-                       R_Mesh_DestroyMeshBuffer(mesh->element3i_indexbuffer);
-               if (mesh->element3s_indexbuffer)
-                       R_Mesh_DestroyMeshBuffer(mesh->element3s_indexbuffer);
-               if (mesh->vbo_vertexbuffer)
-                       R_Mesh_DestroyMeshBuffer(mesh->vbo_vertexbuffer);
-               nextmesh = mesh->next;
-               Mem_Free(mesh);
+               for (k = mod->submodelsurfaces_start; k < mod->submodelsurfaces_end; k++)
+               {
+                       surface = mod->data_surfaces + k;
+                       if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID))
+                               continue;
+                       Mod_ShadowMesh_AddMesh(mod->brush.collisionmesh, mod->surfmesh.data_vertex3f, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
+               }
        }
+       mod->brush.collisionmesh = Mod_ShadowMesh_Finish(mod->brush.collisionmesh, false);
 }
 
 #if 0
@@ -1356,7 +1293,7 @@ static void Mod_ConstructTerrainPatchFromBGRA(const unsigned char *imagepixels,
 #endif
 
 #if 0
-void Mod_Terrain_SurfaceRecurseChunk(dp_model_t *model, int stepsize, int x, int y)
+void Mod_Terrain_SurfaceRecurseChunk(model_t *model, int stepsize, int x, int y)
 {
        float mins[3];
        float maxs[3];
@@ -1427,7 +1364,7 @@ void Mod_Terrain_SurfaceRecurseChunk(dp_model_t *model, int stepsize, int x, int
        // TODO: emit skirt vertices
 }
 
-void Mod_Terrain_UpdateSurfacesForViewOrigin(dp_model_t *model)
+void Mod_Terrain_UpdateSurfacesForViewOrigin(model_t *model)
 {
        for (y = 0;y < model->terrain.size[1];y += model->terrain.
        Mod_Terrain_SurfaceRecurseChunk(model, model->terrain.maxstepsize, x, y);
@@ -1462,7 +1399,7 @@ void Mod_FreeQ3Shaders(void)
        Mem_FreePool(&q3shaders_mem);
 }
 
-static void Q3Shader_AddToHash (q3shaderinfo_t* shader)
+static void Q3Shader_AddToHash (shader_t* shader)
 {
        unsigned short hash = CRC_Block_CaseInsensitive ((const unsigned char *)shader->name, strlen (shader->name));
        q3shader_hash_entry_t* entry = q3shader_data->hash + (hash % Q3SHADER_HASH_SIZE);
@@ -1517,17 +1454,9 @@ static void Q3Shader_AddToHash (q3shaderinfo_t* shader)
                /* else: head of chain, in hash entry array */
                entry = lastEntry;
        }
-       memcpy (&entry->shader, shader, sizeof (q3shaderinfo_t));
+       memcpy (&entry->shader, shader, sizeof (shader_t));
 }
 
-extern cvar_t mod_noshader_default_offsetmapping;
-extern cvar_t mod_q3shader_default_offsetmapping;
-extern cvar_t mod_q3shader_default_offsetmapping_scale;
-extern cvar_t mod_q3shader_default_offsetmapping_bias;
-extern cvar_t mod_q3shader_default_polygonoffset;
-extern cvar_t mod_q3shader_default_polygonfactor;
-extern cvar_t mod_q3shader_force_addalpha;
-extern cvar_t mod_q3shader_force_terrain_alphaflag;
 void Mod_LoadQ3Shaders(void)
 {
        int j;
@@ -1535,14 +1464,14 @@ void Mod_LoadQ3Shaders(void)
        fssearch_t *search;
        char *f;
        const char *text;
-       q3shaderinfo_t shader;
+       shader_t shader;
        q3shaderinfo_layer_t *layer;
        int numparameters;
        char parameter[TEXTURE_MAXFRAMES + 4][Q3PATHLENGTH];
        char *custsurfaceparmnames[256]; // VorteX: q3map2 has 64 but well, someone will need more
        unsigned long custsurfaceflags[256]; 
        int numcustsurfaceflags;
-       qboolean dpshaderkill;
+       qbool dpshaderkill;
 
        Mod_FreeQ3Shaders();
 
@@ -1597,7 +1526,7 @@ void Mod_LoadQ3Shaders(void)
        }
 
        // parse shaders
-       search = FS_Search("scripts/*.shader", true, false);
+       search = FS_Search("scripts/*.shader", true, false, NULL);
        if (!search)
                return;
        for (fileindex = 0;fileindex < search->numfilenames;fileindex++)
@@ -2059,7 +1988,7 @@ void Mod_LoadQ3Shaders(void)
                                // this sets dpshaderkill to true if dpshaderkillifcvarzero was used, and to false if dpnoshaderkillifcvarzero was used
                                else if (((dpshaderkill = !strcasecmp(parameter[0], "dpshaderkillifcvarzero")) || !strcasecmp(parameter[0], "dpnoshaderkillifcvarzero")) && numparameters >= 2)
                                {
-                                       if (Cvar_VariableValue(parameter[1]) == 0.0f)
+                                       if (Cvar_VariableValue(&cvars_all, parameter[1], ~0) == 0.0f)
                                                shader.dpshaderkill = dpshaderkill;
                                }
                                // this sets dpshaderkill to true if dpshaderkillifcvar was used, and to false if dpnoshaderkillifcvar was used
@@ -2070,37 +1999,37 @@ void Mod_LoadQ3Shaders(void)
                                                op = parameter[2];
                                        if(!op)
                                        {
-                                               if (Cvar_VariableValue(parameter[1]) != 0.0f)
+                                               if (Cvar_VariableValue(&cvars_all, parameter[1], ~0) != 0.0f)
                                                        shader.dpshaderkill = dpshaderkill;
                                        }
                                        else if (numparameters >= 4 && !strcmp(op, "=="))
                                        {
-                                               if (Cvar_VariableValue(parameter[1]) == atof(parameter[3]))
+                                               if (Cvar_VariableValue(&cvars_all, parameter[1], ~0) == atof(parameter[3]))
                                                        shader.dpshaderkill = dpshaderkill;
                                        }
                                        else if (numparameters >= 4 && !strcmp(op, "!="))
                                        {
-                                               if (Cvar_VariableValue(parameter[1]) != atof(parameter[3]))
+                                               if (Cvar_VariableValue(&cvars_all, parameter[1], ~0) != atof(parameter[3]))
                                                        shader.dpshaderkill = dpshaderkill;
                                        }
                                        else if (numparameters >= 4 && !strcmp(op, ">"))
                                        {
-                                               if (Cvar_VariableValue(parameter[1]) > atof(parameter[3]))
+                                               if (Cvar_VariableValue(&cvars_all, parameter[1], ~0) > atof(parameter[3]))
                                                        shader.dpshaderkill = dpshaderkill;
                                        }
                                        else if (numparameters >= 4 && !strcmp(op, "<"))
                                        {
-                                               if (Cvar_VariableValue(parameter[1]) < atof(parameter[3]))
+                                               if (Cvar_VariableValue(&cvars_all, parameter[1], ~0) < atof(parameter[3]))
                                                        shader.dpshaderkill = dpshaderkill;
                                        }
                                        else if (numparameters >= 4 && !strcmp(op, ">="))
                                        {
-                                               if (Cvar_VariableValue(parameter[1]) >= atof(parameter[3]))
+                                               if (Cvar_VariableValue(&cvars_all, parameter[1], ~0) >= atof(parameter[3]))
                                                        shader.dpshaderkill = dpshaderkill;
                                        }
                                        else if (numparameters >= 4 && !strcmp(op, "<="))
                                        {
-                                               if (Cvar_VariableValue(parameter[1]) <= atof(parameter[3]))
+                                               if (Cvar_VariableValue(&cvars_all, parameter[1], ~0) <= atof(parameter[3]))
                                                        shader.dpshaderkill = dpshaderkill;
                                        }
                                        else
@@ -2281,7 +2210,7 @@ void Mod_LoadQ3Shaders(void)
                Mem_Free(custsurfaceparmnames[j]);
 }
 
-q3shaderinfo_t *Mod_LookupQ3Shader(const char *name)
+shader_t *Mod_LookupQ3Shader(const char *name)
 {
        unsigned short hash;
        q3shader_hash_entry_t* entry;
@@ -2332,11 +2261,11 @@ texture_shaderpass_t *Mod_CreateShaderPassFromQ3ShaderLayer(mempool_t *mempool,
        return shaderpass;
 }
 
-qboolean Mod_LoadTextureFromQ3Shader(mempool_t *mempool, const char *modelname, texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags, int defaultmaterialflags)
+qbool Mod_LoadTextureFromQ3Shader(mempool_t *mempool, const char *modelname, texture_t *texture, const char *name, qbool warnmissing, qbool fallback, int defaulttexflags, int defaultmaterialflags)
 {
        int texflagsmask, texflagsor;
-       qboolean success = true;
-       q3shaderinfo_t *shader;
+       qbool success = true;
+       shader_t *shader;
        if (!name)
                name = "";
        strlcpy(texture->name, name, sizeof(texture->name));
@@ -2501,7 +2430,7 @@ nothing                GL_ZERO GL_ONE
                                firstpostlayer = rgbgenvertexlayer + 1;
                                // special case for rgbgen vertex if MATERIALFLAG_VERTEXCOLOR is expected on this material
                                if (defaultmaterialflags & MATERIALFLAG_VERTEXCOLOR)
-                                       texture->basematerialflags |= MATERIALFLAG_VERTEXCOLOR;
+                                       texture->basematerialflags |= MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX;
                        }
                        else if (rgbgendiffuselayer >= 0)
                        {
@@ -2562,6 +2491,7 @@ nothing                GL_ZERO GL_ONE
                texture->specularscalemod = shader->specularscalemod;
                texture->specularpowermod = shader->specularpowermod;
                texture->rtlightambient = shader->rtlightambient;
+               texture->refractive_index = mod_q3shader_default_refractive_index.value;
                if (shader->dpreflectcube[0])
                        texture->reflectcubetexture = R_GetCubemap(shader->dpreflectcube);
 
@@ -2651,6 +2581,7 @@ nothing                GL_ZERO GL_ONE
        {
                if (developer_extra.integer)
                        Con_DPrintf("^1%s:^7 using fallback noshader material for ^3\"%s\"\n", modelname, name);
+               texture->basematerialflags = defaultmaterialflags;
                texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
        }
        else if (!strcmp(texture->name, "common/nodraw") || !strcmp(texture->name, "textures/common/nodraw"))
@@ -2745,9 +2676,9 @@ void Mod_LoadCustomMaterial(mempool_t *mempool, texture_t *texture, const char *
        texture->backgroundcurrentskinframe = NULL;
 }
 
-void Mod_UnloadCustomMaterial(texture_t *texture, qboolean purgeskins)
+void Mod_UnloadCustomMaterial(texture_t *texture, qbool purgeskins)
 {
-       int i, j;
+       long unsigned int i, j;
        for (i = 0; i < sizeof(texture->shaderpasses) / sizeof(texture->shaderpasses[0]); i++)
        {
                if (texture->shaderpasses[i])
@@ -2947,41 +2878,87 @@ void Mod_VertexRangeFromElements(int numelements, const int *elements, int *firs
                *lastvertexpointer = lastvertex;
 }
 
-void Mod_MakeSortedSurfaces(dp_model_t *mod)
+void Mod_SetDrawSkyAndWater(model_t* mod)
+{
+       int j;
+       uint64_t basematerialflags = 0;
+       // by default assume there is no sky or water used in this model
+       mod->DrawSky = NULL;
+       mod->DrawAddWaterPlanes = NULL;
+       // combine all basematerialflags observed in the submodelsurfaces range, then check for special flags
+       for (j = mod->submodelsurfaces_start; j < mod->submodelsurfaces_end; j++)
+               if (mod->data_surfaces[j].texture)
+                       basematerialflags |= mod->data_surfaces[j].texture->basematerialflags;
+       if (basematerialflags & MATERIALFLAG_SKY)
+               mod->DrawSky = R_Mod_DrawSky;
+       if (basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
+               mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
+}
+
+typedef struct Mod_MakeSortedSurfaces_qsortsurface_s
+{
+       int surfaceindex;
+       q3deffect_t* effect;
+       texture_t* texture;
+       rtexture_t* lightmaptexture;
+}
+Mod_MakeSortedSurfaces_qsortsurface_t;
+
+static int Mod_MakeSortedSurfaces_qsortfunc(const void *a, const void *b)
+{
+       const Mod_MakeSortedSurfaces_qsortsurface_t* l = (Mod_MakeSortedSurfaces_qsortsurface_t*)a;
+       const Mod_MakeSortedSurfaces_qsortsurface_t* r = (Mod_MakeSortedSurfaces_qsortsurface_t*)b;
+       if (l->effect < r->effect)
+               return -1;
+       if (l->effect > r->effect)
+               return 1;
+       if (l->texture < r->texture)
+               return -1;
+       if (l->texture > r->texture)
+               return 1;
+       if (l->lightmaptexture < r->lightmaptexture)
+               return -1;
+       if (l->lightmaptexture > r->lightmaptexture)
+               return 1;
+       if (l->surfaceindex < r->surfaceindex)
+               return -1;
+       if (l->surfaceindex > r->surfaceindex)
+               return 1;
+       return 0;
+}
+
+void Mod_MakeSortedSurfaces(model_t *mod)
 {
        // make an optimal set of texture-sorted batches to draw...
-       int j, t;
-       int *firstsurfacefortexture;
-       int *numsurfacesfortexture;
-       if (!mod->sortedmodelsurfaces)
-               mod->sortedmodelsurfaces = (int *) Mem_Alloc(loadmodel->mempool, mod->nummodelsurfaces * sizeof(*mod->sortedmodelsurfaces));
-       firstsurfacefortexture = (int *) Mem_Alloc(tempmempool, mod->num_textures * sizeof(*firstsurfacefortexture));
-       numsurfacesfortexture = (int *) Mem_Alloc(tempmempool, mod->num_textures * sizeof(*numsurfacesfortexture));
-       memset(numsurfacesfortexture, 0, mod->num_textures * sizeof(*numsurfacesfortexture));
-       for (j = 0;j < mod->nummodelsurfaces;j++)
-       {
-               const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface;
-               t = (int)(surface->texture - mod->data_textures);
-               numsurfacesfortexture[t]++;
-       }
-       j = 0;
-       for (t = 0;t < mod->num_textures;t++)
-       {
-               firstsurfacefortexture[t] = j;
-               j += numsurfacesfortexture[t];
-       }
-       for (j = 0;j < mod->nummodelsurfaces;j++)
+       int j, k;
+       Mod_MakeSortedSurfaces_qsortsurface_t *info;
+
+       if(cls.state == ca_dedicated)
+               return;
+
+       info = (Mod_MakeSortedSurfaces_qsortsurface_t*)R_FrameData_Alloc(mod->num_surfaces * sizeof(*info));
+       if (!mod->modelsurfaces_sorted)
+               mod->modelsurfaces_sorted = (int *) Mem_Alloc(loadmodel->mempool, mod->num_surfaces * sizeof(*mod->modelsurfaces_sorted));
+       // the goal is to sort by submodel (can't change which submodel a surface belongs to), and then by effects and textures
+       for (j = 0; j < mod->num_surfaces; j++)
        {
-               const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface;
-               t = (int)(surface->texture - mod->data_textures);
-               mod->sortedmodelsurfaces[firstsurfacefortexture[t]++] = j + mod->firstmodelsurface;
+               info[j].surfaceindex = j;
+               info[j].effect = mod->data_surfaces[j].effect;
+               info[j].texture = mod->data_surfaces[j].texture;
+               info[j].lightmaptexture = mod->data_surfaces[j].lightmaptexture;
        }
-       Mem_Free(firstsurfacefortexture);
-       Mem_Free(numsurfacesfortexture);
+       for (k = 0; k < mod->brush.numsubmodels; k++)
+               if (mod->brush.submodels[k]->submodelsurfaces_end > mod->brush.submodels[k]->submodelsurfaces_start + 1)
+                       qsort(info + mod->brush.submodels[k]->submodelsurfaces_start, (size_t)mod->brush.submodels[k]->submodelsurfaces_end - mod->brush.submodels[k]->submodelsurfaces_start, sizeof(*info), Mod_MakeSortedSurfaces_qsortfunc);
+       for (j = 0; j < mod->num_surfaces; j++)
+               mod->modelsurfaces_sorted[j] = info[j].surfaceindex;
 }
 
 void Mod_BuildVBOs(void)
 {
+       if(cls.state == ca_dedicated)
+               return;
+
        if (!loadmodel->surfmesh.num_vertices)
                return;
 
@@ -2998,32 +2975,6 @@ void Mod_BuildVBOs(void)
                }
        }
 
-       // build r_vertexmesh_t array
-       // (compressed interleaved array for D3D)
-       if (!loadmodel->surfmesh.data_vertexmesh && vid.useinterleavedarrays)
-       {
-               int vertexindex;
-               int numvertices = loadmodel->surfmesh.num_vertices;
-               r_vertexmesh_t *vertexmesh;
-               loadmodel->surfmesh.data_vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(r_vertexmesh_t));
-               for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexmesh++)
-               {
-                       VectorCopy(loadmodel->surfmesh.data_vertex3f + 3*vertexindex, vertexmesh->vertex3f);
-                       VectorScale(loadmodel->surfmesh.data_svector3f + 3*vertexindex, 1.0f, vertexmesh->svector3f);
-                       VectorScale(loadmodel->surfmesh.data_tvector3f + 3*vertexindex, 1.0f, vertexmesh->tvector3f);
-                       VectorScale(loadmodel->surfmesh.data_normal3f + 3*vertexindex, 1.0f, vertexmesh->normal3f);
-                       if (loadmodel->surfmesh.data_lightmapcolor4f)
-                               Vector4Copy(loadmodel->surfmesh.data_lightmapcolor4f + 4*vertexindex, vertexmesh->color4f);
-                       Vector2Copy(loadmodel->surfmesh.data_texcoordtexture2f + 2*vertexindex, vertexmesh->texcoordtexture2f);
-                       if (loadmodel->surfmesh.data_texcoordlightmap2f)
-                               Vector2Scale(loadmodel->surfmesh.data_texcoordlightmap2f + 2*vertexindex, 1.0f, vertexmesh->texcoordlightmap2f);
-                       if (loadmodel->surfmesh.data_skeletalindex4ub)
-                               Vector4Copy(loadmodel->surfmesh.data_skeletalindex4ub + 4*vertexindex, vertexmesh->skeletalindex4ub);
-                       if (loadmodel->surfmesh.data_skeletalweight4ub)
-                               Vector4Copy(loadmodel->surfmesh.data_skeletalweight4ub + 4*vertexindex, vertexmesh->skeletalweight4ub);
-               }
-       }
-
        // upload short indices as a buffer
        if (loadmodel->surfmesh.data_element3s && !loadmodel->surfmesh.data_element3s_indexbuffer)
                loadmodel->surfmesh.data_element3s_indexbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles * sizeof(short[3]), loadmodel->name, true, false, false, true);
@@ -3033,44 +2984,46 @@ void Mod_BuildVBOs(void)
                loadmodel->surfmesh.data_element3i_indexbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles * sizeof(int[3]), loadmodel->name, true, false, false, false);
 
        // only build a vbo if one has not already been created (this is important for brush models which load specially)
-       // vertex buffer is several arrays and we put them in the same buffer
-       //
-       // is this wise?  the texcoordtexture2f array is used with dynamic
-       // vertex/svector/tvector/normal when rendering animated models, on the
-       // other hand animated models don't use a lot of vertices anyway...
-       if (!loadmodel->surfmesh.vbo_vertexbuffer && !vid.useinterleavedarrays)
+       // we put several vertex data streams in the same buffer
+       if (!loadmodel->surfmesh.data_vertex3f_vertexbuffer)
        {
                int size;
                unsigned char *mem;
                size = 0;
-               loadmodel->surfmesh.vbooffset_vertexmesh         = size;if (loadmodel->surfmesh.data_vertexmesh        ) size += loadmodel->surfmesh.num_vertices * sizeof(r_vertexmesh_t);
-               loadmodel->surfmesh.vbooffset_vertex3f           = size;if (loadmodel->surfmesh.data_vertex3f          ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
-               loadmodel->surfmesh.vbooffset_svector3f          = size;if (loadmodel->surfmesh.data_svector3f         ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
-               loadmodel->surfmesh.vbooffset_tvector3f          = size;if (loadmodel->surfmesh.data_tvector3f         ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
-               loadmodel->surfmesh.vbooffset_normal3f           = size;if (loadmodel->surfmesh.data_normal3f          ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
-               loadmodel->surfmesh.vbooffset_texcoordtexture2f  = size;if (loadmodel->surfmesh.data_texcoordtexture2f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
-               loadmodel->surfmesh.vbooffset_texcoordlightmap2f = size;if (loadmodel->surfmesh.data_texcoordlightmap2f) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
-               loadmodel->surfmesh.vbooffset_lightmapcolor4f    = size;if (loadmodel->surfmesh.data_lightmapcolor4f   ) size += loadmodel->surfmesh.num_vertices * sizeof(float[4]);
-               loadmodel->surfmesh.vbooffset_skeletalindex4ub   = size;if (loadmodel->surfmesh.data_skeletalindex4ub  ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
-               loadmodel->surfmesh.vbooffset_skeletalweight4ub  = size;if (loadmodel->surfmesh.data_skeletalweight4ub ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
+               loadmodel->surfmesh.data_vertex3f_bufferoffset           = size;if (loadmodel->surfmesh.data_vertex3f          ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
+               loadmodel->surfmesh.data_svector3f_bufferoffset          = size;if (loadmodel->surfmesh.data_svector3f         ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
+               loadmodel->surfmesh.data_tvector3f_bufferoffset          = size;if (loadmodel->surfmesh.data_tvector3f         ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
+               loadmodel->surfmesh.data_normal3f_bufferoffset           = size;if (loadmodel->surfmesh.data_normal3f          ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
+               loadmodel->surfmesh.data_texcoordtexture2f_bufferoffset  = size;if (loadmodel->surfmesh.data_texcoordtexture2f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
+               loadmodel->surfmesh.data_texcoordlightmap2f_bufferoffset = size;if (loadmodel->surfmesh.data_texcoordlightmap2f) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
+               loadmodel->surfmesh.data_lightmapcolor4f_bufferoffset    = size;if (loadmodel->surfmesh.data_lightmapcolor4f   ) size += loadmodel->surfmesh.num_vertices * sizeof(float[4]);
+               loadmodel->surfmesh.data_skeletalindex4ub_bufferoffset   = size;if (loadmodel->surfmesh.data_skeletalindex4ub  ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
+               loadmodel->surfmesh.data_skeletalweight4ub_bufferoffset  = size;if (loadmodel->surfmesh.data_skeletalweight4ub ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
                mem = (unsigned char *)Mem_Alloc(tempmempool, size);
-               if (loadmodel->surfmesh.data_vertexmesh        ) memcpy(mem + loadmodel->surfmesh.vbooffset_vertexmesh        , loadmodel->surfmesh.data_vertexmesh        , loadmodel->surfmesh.num_vertices * sizeof(r_vertexmesh_t));
-               if (loadmodel->surfmesh.data_vertex3f          ) memcpy(mem + loadmodel->surfmesh.vbooffset_vertex3f          , loadmodel->surfmesh.data_vertex3f          , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
-               if (loadmodel->surfmesh.data_svector3f         ) memcpy(mem + loadmodel->surfmesh.vbooffset_svector3f         , loadmodel->surfmesh.data_svector3f         , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
-               if (loadmodel->surfmesh.data_tvector3f         ) memcpy(mem + loadmodel->surfmesh.vbooffset_tvector3f         , loadmodel->surfmesh.data_tvector3f         , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
-               if (loadmodel->surfmesh.data_normal3f          ) memcpy(mem + loadmodel->surfmesh.vbooffset_normal3f          , loadmodel->surfmesh.data_normal3f          , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
-               if (loadmodel->surfmesh.data_texcoordtexture2f ) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordtexture2f , loadmodel->surfmesh.data_texcoordtexture2f , loadmodel->surfmesh.num_vertices * sizeof(float[2]));
-               if (loadmodel->surfmesh.data_texcoordlightmap2f) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordlightmap2f, loadmodel->surfmesh.data_texcoordlightmap2f, loadmodel->surfmesh.num_vertices * sizeof(float[2]));
-               if (loadmodel->surfmesh.data_lightmapcolor4f   ) memcpy(mem + loadmodel->surfmesh.vbooffset_lightmapcolor4f   , loadmodel->surfmesh.data_lightmapcolor4f   , loadmodel->surfmesh.num_vertices * sizeof(float[4]));
-               if (loadmodel->surfmesh.data_skeletalindex4ub  ) memcpy(mem + loadmodel->surfmesh.vbooffset_skeletalindex4ub  , loadmodel->surfmesh.data_skeletalindex4ub  , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
-               if (loadmodel->surfmesh.data_skeletalweight4ub ) memcpy(mem + loadmodel->surfmesh.vbooffset_skeletalweight4ub , loadmodel->surfmesh.data_skeletalweight4ub , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
-               loadmodel->surfmesh.vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, loadmodel->name, false, false, false, false);
+               if (loadmodel->surfmesh.data_vertex3f          ) memcpy(mem + loadmodel->surfmesh.data_vertex3f_bufferoffset          , loadmodel->surfmesh.data_vertex3f          , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
+               if (loadmodel->surfmesh.data_svector3f         ) memcpy(mem + loadmodel->surfmesh.data_svector3f_bufferoffset         , loadmodel->surfmesh.data_svector3f         , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
+               if (loadmodel->surfmesh.data_tvector3f         ) memcpy(mem + loadmodel->surfmesh.data_tvector3f_bufferoffset         , loadmodel->surfmesh.data_tvector3f         , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
+               if (loadmodel->surfmesh.data_normal3f          ) memcpy(mem + loadmodel->surfmesh.data_normal3f_bufferoffset          , loadmodel->surfmesh.data_normal3f          , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
+               if (loadmodel->surfmesh.data_texcoordtexture2f ) memcpy(mem + loadmodel->surfmesh.data_texcoordtexture2f_bufferoffset , loadmodel->surfmesh.data_texcoordtexture2f , loadmodel->surfmesh.num_vertices * sizeof(float[2]));
+               if (loadmodel->surfmesh.data_texcoordlightmap2f) memcpy(mem + loadmodel->surfmesh.data_texcoordlightmap2f_bufferoffset, loadmodel->surfmesh.data_texcoordlightmap2f, loadmodel->surfmesh.num_vertices * sizeof(float[2]));
+               if (loadmodel->surfmesh.data_lightmapcolor4f   ) memcpy(mem + loadmodel->surfmesh.data_lightmapcolor4f_bufferoffset   , loadmodel->surfmesh.data_lightmapcolor4f   , loadmodel->surfmesh.num_vertices * sizeof(float[4]));
+               if (loadmodel->surfmesh.data_skeletalindex4ub  ) memcpy(mem + loadmodel->surfmesh.data_skeletalindex4ub_bufferoffset  , loadmodel->surfmesh.data_skeletalindex4ub  , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
+               if (loadmodel->surfmesh.data_skeletalweight4ub ) memcpy(mem + loadmodel->surfmesh.data_skeletalweight4ub_bufferoffset , loadmodel->surfmesh.data_skeletalweight4ub , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
+               loadmodel->surfmesh.data_vertex3f_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, loadmodel->name, false, false, false, false);
+               loadmodel->surfmesh.data_svector3f_vertexbuffer = loadmodel->surfmesh.data_svector3f ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
+               loadmodel->surfmesh.data_tvector3f_vertexbuffer = loadmodel->surfmesh.data_tvector3f ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
+               loadmodel->surfmesh.data_normal3f_vertexbuffer = loadmodel->surfmesh.data_normal3f ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
+               loadmodel->surfmesh.data_texcoordtexture2f_vertexbuffer = loadmodel->surfmesh.data_texcoordtexture2f ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
+               loadmodel->surfmesh.data_texcoordlightmap2f_vertexbuffer = loadmodel->surfmesh.data_texcoordlightmap2f ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
+               loadmodel->surfmesh.data_lightmapcolor4f_vertexbuffer = loadmodel->surfmesh.data_lightmapcolor4f ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
+               loadmodel->surfmesh.data_skeletalindex4ub_vertexbuffer = loadmodel->surfmesh.data_skeletalindex4ub ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
+               loadmodel->surfmesh.data_skeletalweight4ub_vertexbuffer = loadmodel->surfmesh.data_skeletalweight4ub ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
                Mem_Free(mem);
        }
 }
 
 extern cvar_t mod_obj_orientation;
-static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const char *mtlfilename, const char *originalfilename)
+static void Mod_Decompile_OBJ(model_t *model, const char *filename, const char *mtlfilename, const char *originalfilename)
 {
        int submodelindex, vertexindex, surfaceindex, triangleindex, textureindex, countvertices = 0, countsurfaces = 0, countfaces = 0, counttextures = 0;
        int a, b, c;
@@ -3084,7 +3037,7 @@ static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const cha
        const msurface_t *surface;
        const int maxtextures = 256;
        char *texturenames = (char *) Z_Malloc(maxtextures * MAX_QPATH);
-       dp_model_t *submodel;
+       model_t *submodel;
 
        // construct the mtllib file
        l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "# mtllib for %s exported by darkplaces engine\n", originalfilename);
@@ -3151,9 +3104,9 @@ static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const cha
                if (l > 0)
                        outbufferpos += l;
                submodel = model->brush.numsubmodels ? model->brush.submodels[submodelindex] : model;
-               for (surfaceindex = 0;surfaceindex < submodel->nummodelsurfaces;surfaceindex++)
+               for (surfaceindex = submodel->submodelsurfaces_start;surfaceindex < submodel->submodelsurfaces_end;surfaceindex++)
                {
-                       surface = model->data_surfaces + submodel->sortedmodelsurfaces[surfaceindex];
+                       surface = model->data_surfaces + surfaceindex;
                        l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "usemtl %s\n", (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default");
                        if (l > 0)
                                outbufferpos += l;
@@ -3191,7 +3144,7 @@ static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const cha
        Con_Printf("Wrote %s (%i bytes, %i vertices, %i faces, %i surfaces with %i distinct textures)\n", filename, (int)outbufferpos, countvertices, countfaces, countsurfaces, counttextures);
 }
 
-static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int firstpose, int numposes, qboolean writetriangles)
+static void Mod_Decompile_SMD(model_t *model, const char *filename, int firstpose, int numposes, qbool writetriangles)
 {
        int countnodes = 0, counttriangles = 0, countframes = 0;
        int surfaceindex;
@@ -3355,10 +3308,10 @@ Mod_Decompile_f
 decompiles a model to editable files
 ================
 */
-static void Mod_Decompile_f(void)
+static void Mod_Decompile_f(cmd_state_t *cmd)
 {
        int i, j, k, l, first, count;
-       dp_model_t *mod;
+       model_t *mod;
        char inname[MAX_QPATH];
        char outname[MAX_QPATH];
        char mtlname[MAX_QPATH];
@@ -3373,13 +3326,13 @@ static void Mod_Decompile_f(void)
        int framegroupstextsize = 0;
        char vabuf[1024];
 
-       if (Cmd_Argc() != 2)
+       if (Cmd_Argc(cmd) != 2)
        {
                Con_Print("usage: modeldecompile <filename>\n");
                return;
        }
 
-       strlcpy(inname, Cmd_Argv(1), sizeof(inname));
+       strlcpy(inname, Cmd_Argv(cmd, 1), sizeof(inname));
        FS_StripExtension(inname, basename, sizeof(basename));
 
        mod = Mod_ForName(inname, false, true, inname[0] == '*' ? cl.model_name[1] : NULL);
@@ -3519,7 +3472,7 @@ void Mod_AllocLightmap_Free(mod_alloclightmap_state_t *state)
        memset(state, 0, sizeof(*state));
 }
 
-qboolean Mod_AllocLightmap_Block(mod_alloclightmap_state_t *state, int blockwidth, int blockheight, int *outx, int *outy)
+qbool Mod_AllocLightmap_Block(mod_alloclightmap_state_t *state, int blockwidth, int blockheight, int *outx, int *outy)
 {
        mod_alloclightmap_row_t *row;
        int y;
@@ -3619,7 +3572,7 @@ static lightmaplight_t *mod_generatelightmaps_lightinfo;
 extern cvar_t r_shadow_lightattenuationdividebias;
 extern cvar_t r_shadow_lightattenuationlinearscale;
 
-static void Mod_GenerateLightmaps_LightPoint(dp_model_t *model, const vec3_t pos, vec3_t ambient, vec3_t diffuse, vec3_t lightdir)
+static void Mod_GenerateLightmaps_LightPoint(model_t *model, const vec3_t pos, vec3_t ambient, vec3_t diffuse, vec3_t lightdir)
 {
        int i;
        int index;
@@ -3688,7 +3641,7 @@ static void Mod_GenerateLightmaps_LightPoint(dp_model_t *model, const vec3_t pos
        VectorCopy(dir, lightdir);
 }
 
-static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const dp_model_t *model, svbsp_t *svbsp, const float *mins, const float *maxs)
+static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const model_t *model, svbsp_t *svbsp, const float *mins, const float *maxs)
 {
        int surfaceindex;
        int triangleindex;
@@ -3697,8 +3650,9 @@ static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const
        const int *element3i = model->surfmesh.data_element3i;
        const int *e;
        float v2[3][3];
-       for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->nummodelsurfaces;surfaceindex++, surface++)
+       for (surfaceindex = model->submodelsurfaces_start;surfaceindex < model->submodelsurfaces_end;surfaceindex++)
        {
+               surface = model->data_surfaces + surfaceindex;
                if (!BoxesOverlap(surface->mins, surface->maxs, mins, maxs))
                        continue;
                if (surface->texture->basematerialflags & MATERIALFLAG_NOSHADOW)
@@ -3713,7 +3667,7 @@ static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const
        }
 }
 
-static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(dp_model_t *model, lightmaplight_t *lightinfo)
+static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(model_t *model, lightmaplight_t *lightinfo)
 {
        int maxnodes = 1<<14;
        svbsp_node_t *nodes;
@@ -3752,7 +3706,7 @@ static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(dp_model_t *model, l
        Mem_Free(nodes);
 }
 
-static void Mod_GenerateLightmaps_CreateLights(dp_model_t *model)
+static void Mod_GenerateLightmaps_CreateLights(model_t *model)
 {
        int index;
        int result;
@@ -3791,7 +3745,7 @@ static void Mod_GenerateLightmaps_CreateLights(dp_model_t *model)
        }
 }
 
-static void Mod_GenerateLightmaps_DestroyLights(dp_model_t *model)
+static void Mod_GenerateLightmaps_DestroyLights(model_t *model)
 {
        int i;
        if (mod_generatelightmaps_lightinfo)
@@ -3805,7 +3759,7 @@ static void Mod_GenerateLightmaps_DestroyLights(dp_model_t *model)
        mod_generatelightmaps_numlights = 0;
 }
 
-static qboolean Mod_GenerateLightmaps_SamplePoint_SVBSP(const svbsp_t *svbsp, const float *pos)
+static qbool Mod_GenerateLightmaps_SamplePoint_SVBSP(const svbsp_t *svbsp, const float *pos)
 {
        const svbsp_node_t *node;
        const svbsp_node_t *nodes = svbsp->nodes;
@@ -3954,7 +3908,7 @@ static void Mod_GenerateLightmaps_GridSample(const float *pos, q3dlightgrid_t *s
        else {s->diffusepitch = (unsigned char)(acos(dir[2]) * (127.5f/M_PI));s->diffuseyaw = (unsigned char)(atan2(dir[1], dir[0]) * (127.5f/M_PI));}
 }
 
-static void Mod_GenerateLightmaps_InitSampleOffsets(dp_model_t *model)
+static void Mod_GenerateLightmaps_InitSampleOffsets(model_t *model)
 {
        float radius[3];
        float temp[3];
@@ -3976,7 +3930,7 @@ static void Mod_GenerateLightmaps_InitSampleOffsets(dp_model_t *model)
        }
 }
 
-static void Mod_GenerateLightmaps_DestroyLightmaps(dp_model_t *model)
+static void Mod_GenerateLightmaps_DestroyLightmaps(model_t *model)
 {
        msurface_t *surface;
        int surfaceindex;
@@ -4005,7 +3959,7 @@ static void Mod_GenerateLightmaps_DestroyLightmaps(dp_model_t *model)
        }
 }
 
-static void Mod_GenerateLightmaps_UnweldTriangles(dp_model_t *model)
+static void Mod_GenerateLightmaps_UnweldTriangles(model_t *model)
 {
        msurface_t *surface;
        int surfaceindex;
@@ -4038,15 +3992,23 @@ static void Mod_GenerateLightmaps_UnweldTriangles(dp_model_t *model)
        if (model->surfmesh.num_vertices > 65536)
                model->surfmesh.data_element3s = NULL;
 
-       if (model->surfmesh.data_element3i_indexbuffer)
+       if (model->surfmesh.data_element3i_indexbuffer && !model->surfmesh.data_element3i_indexbuffer->isdynamic)
                R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3i_indexbuffer);
        model->surfmesh.data_element3i_indexbuffer = NULL;
-       if (model->surfmesh.data_element3s_indexbuffer)
+       if (model->surfmesh.data_element3s_indexbuffer && !model->surfmesh.data_element3s_indexbuffer->isdynamic)
                R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3s_indexbuffer);
        model->surfmesh.data_element3s_indexbuffer = NULL;
-       if (model->surfmesh.vbo_vertexbuffer)
-               R_Mesh_DestroyMeshBuffer(model->surfmesh.vbo_vertexbuffer);
-       model->surfmesh.vbo_vertexbuffer = 0;
+       if (model->surfmesh.data_vertex3f_vertexbuffer && !model->surfmesh.data_vertex3f_vertexbuffer->isdynamic)
+               R_Mesh_DestroyMeshBuffer(model->surfmesh.data_vertex3f_vertexbuffer);
+       model->surfmesh.data_vertex3f_vertexbuffer = NULL;
+       model->surfmesh.data_svector3f_vertexbuffer = NULL;
+       model->surfmesh.data_tvector3f_vertexbuffer = NULL;
+       model->surfmesh.data_normal3f_vertexbuffer = NULL;
+       model->surfmesh.data_texcoordtexture2f_vertexbuffer = NULL;
+       model->surfmesh.data_texcoordlightmap2f_vertexbuffer = NULL;
+       model->surfmesh.data_lightmapcolor4f_vertexbuffer = NULL;
+       model->surfmesh.data_skeletalindex4ub_vertexbuffer = NULL;
+       model->surfmesh.data_skeletalweight4ub_vertexbuffer = NULL;
 
        // convert all triangles to unique vertex data
        outvertexindex = 0;
@@ -4100,7 +4062,7 @@ static void Mod_GenerateLightmaps_UnweldTriangles(dp_model_t *model)
                model->brush.submodels[i]->surfmesh = model->surfmesh;
 }
 
-static void Mod_GenerateLightmaps_CreateTriangleInformation(dp_model_t *model)
+static void Mod_GenerateLightmaps_CreateTriangleInformation(model_t *model)
 {
        msurface_t *surface;
        int surfaceindex;
@@ -4142,7 +4104,7 @@ static void Mod_GenerateLightmaps_CreateTriangleInformation(dp_model_t *model)
        }
 }
 
-static void Mod_GenerateLightmaps_DestroyTriangleInformation(dp_model_t *model)
+static void Mod_GenerateLightmaps_DestroyTriangleInformation(model_t *model)
 {
        if (mod_generatelightmaps_lightmaptriangles)
                Mem_Free(mod_generatelightmaps_lightmaptriangles);
@@ -4151,7 +4113,7 @@ static void Mod_GenerateLightmaps_DestroyTriangleInformation(dp_model_t *model)
 
 float lmaxis[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
 
-static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
+static void Mod_GenerateLightmaps_CreateLightmaps(model_t *model)
 {
        msurface_t *surface;
        int surfaceindex;
@@ -4405,14 +4367,14 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
        }
 }
 
-static void Mod_GenerateLightmaps_UpdateVertexColors(dp_model_t *model)
+static void Mod_GenerateLightmaps_UpdateVertexColors(model_t *model)
 {
        int i;
        for (i = 0;i < model->surfmesh.num_vertices;i++)
                Mod_GenerateLightmaps_VertexSample(model->surfmesh.data_vertex3f + 3*i, model->surfmesh.data_normal3f + 3*i, model->surfmesh.data_lightmapcolor4f + 4*i);
 }
 
-static void Mod_GenerateLightmaps_UpdateLightGrid(dp_model_t *model)
+static void Mod_GenerateLightmaps_UpdateLightGrid(model_t *model)
 {
        int x;
        int y;
@@ -4435,10 +4397,10 @@ static void Mod_GenerateLightmaps_UpdateLightGrid(dp_model_t *model)
 }
 
 extern cvar_t mod_q3bsp_nolightmaps;
-static void Mod_GenerateLightmaps(dp_model_t *model)
+static void Mod_GenerateLightmaps(model_t *model)
 {
        //lightmaptriangle_t *lightmaptriangles = Mem_Alloc(model->mempool, model->surfmesh.num_triangles * sizeof(lightmaptriangle_t));
-       dp_model_t *oldloadmodel = loadmodel;
+       model_t *oldloadmodel = loadmodel;
        loadmodel = model;
 
        Mod_GenerateLightmaps_InitSampleOffsets(model);
@@ -4456,9 +4418,9 @@ static void Mod_GenerateLightmaps(dp_model_t *model)
        loadmodel = oldloadmodel;
 }
 
-static void Mod_GenerateLightmaps_f(void)
+static void Mod_GenerateLightmaps_f(cmd_state_t *cmd)
 {
-       if (Cmd_Argc() != 1)
+       if (Cmd_Argc(cmd) != 1)
        {
                Con_Printf("usage: mod_generatelightmaps\n");
                return;
@@ -4471,29 +4433,29 @@ static void Mod_GenerateLightmaps_f(void)
        Mod_GenerateLightmaps(cl.worldmodel);
 }
 
-void Mod_Mesh_Create(dp_model_t *mod, const char *name)
+void Mod_Mesh_Create(model_t *mod, const char *name)
 {
        memset(mod, 0, sizeof(*mod));
        strlcpy(mod->name, name, sizeof(mod->name));
        mod->mempool = Mem_AllocPool(name, 0, NULL);
        mod->texturepool = R_AllocTexturePool();
-       mod->Draw = R_Q1BSP_Draw;
-       mod->DrawDepth = R_Q1BSP_DrawDepth;
-       mod->DrawDebug = R_Q1BSP_DrawDebug;
-       mod->DrawPrepass = R_Q1BSP_DrawPrepass;
-       mod->GetLightInfo = R_Q1BSP_GetLightInfo;
-       mod->DrawShadowMap = R_Q1BSP_DrawShadowMap;
-       mod->DrawLight = R_Q1BSP_DrawLight;
+       mod->Draw = R_Mod_Draw;
+       mod->DrawDepth = R_Mod_DrawDepth;
+       mod->DrawDebug = R_Mod_DrawDebug;
+       mod->DrawPrepass = R_Mod_DrawPrepass;
+       mod->GetLightInfo = R_Mod_GetLightInfo;
+       mod->DrawShadowMap = R_Mod_DrawShadowMap;
+       mod->DrawLight = R_Mod_DrawLight;
 }
 
-void Mod_Mesh_Destroy(dp_model_t *mod)
+void Mod_Mesh_Destroy(model_t *mod)
 {
        Mod_UnloadModel(mod);
 }
 
 // resets the mesh model to have no geometry to render, ready for a new frame -
 // the mesh will be prepared for rendering later using Mod_Mesh_Finalize
-void Mod_Mesh_Reset(dp_model_t *mod)
+void Mod_Mesh_Reset(model_t *mod)
 {
        mod->num_surfaces = 0;
        mod->surfmesh.num_vertices = 0;
@@ -4503,13 +4465,14 @@ void Mod_Mesh_Reset(dp_model_t *mod)
        mod->DrawAddWaterPlanes = NULL; // will be set if a texture needs it
 }
 
-texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name, int defaultdrawflags, int defaulttexflags, int defaultmaterialflags)
+texture_t *Mod_Mesh_GetTexture(model_t *mod, const char *name, int defaultdrawflags, int defaulttexflags, int defaultmaterialflags)
 {
        int i;
        texture_t *t;
-       for (i = 0; i < mod->num_textures; i++)
-               if (!strcmp(mod->data_textures[i].name, name))
-                       return mod->data_textures + i;
+       int drawflag = defaultdrawflags & DRAWFLAG_MASK;
+       for (i = 0, t = mod->data_textures; i < mod->num_textures; i++, t++)
+               if (!strcmp(t->name, name) && t->mesh_drawflag == drawflag && t->mesh_defaulttexflags == defaulttexflags && t->mesh_defaultmaterialflags == defaultmaterialflags)
+                       return t;
        if (mod->max_textures <= mod->num_textures)
        {
                texture_t *oldtextures = mod->data_textures;
@@ -4520,7 +4483,10 @@ texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name, int defaultdra
                        mod->data_surfaces[i].texture = mod->data_textures + (mod->data_surfaces[i].texture - oldtextures);
        }
        t = &mod->data_textures[mod->num_textures++];
-       Mod_LoadTextureFromQ3Shader(mod->mempool, mod->name, t, name, false, true, defaulttexflags, defaultmaterialflags);
+       Mod_LoadTextureFromQ3Shader(mod->mempool, mod->name, t, name, true, true, defaulttexflags, defaultmaterialflags);
+       t->mesh_drawflag = drawflag;
+       t->mesh_defaulttexflags = defaulttexflags;
+       t->mesh_defaultmaterialflags = defaultmaterialflags;
        switch (defaultdrawflags & DRAWFLAG_MASK)
        {
        case DRAWFLAG_ADDITIVE:
@@ -4551,7 +4517,7 @@ texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name, int defaultdra
        return t;
 }
 
-msurface_t *Mod_Mesh_AddSurface(dp_model_t *mod, texture_t *tex, qboolean batchwithprevioussurface)
+msurface_t *Mod_Mesh_AddSurface(model_t *mod, texture_t *tex, qbool batchwithprevioussurface)
 {
        msurface_t *surf;
        // batch if possible; primarily useful for UI rendering where bounding boxes don't matter
@@ -4562,7 +4528,7 @@ msurface_t *Mod_Mesh_AddSurface(dp_model_t *mod, texture_t *tex, qboolean batchw
        {
                mod->max_surfaces = 2 * max(mod->num_surfaces, 64);
                mod->data_surfaces = (msurface_t *)Mem_Realloc(mod->mempool, mod->data_surfaces, mod->max_surfaces * sizeof(*mod->data_surfaces));
-               mod->sortedmodelsurfaces = (int *)Mem_Realloc(mod->mempool, mod->sortedmodelsurfaces, mod->max_surfaces * sizeof(*mod->sortedmodelsurfaces));
+               mod->modelsurfaces_sorted = (int *)Mem_Realloc(mod->mempool, mod->modelsurfaces_sorted, mod->max_surfaces * sizeof(*mod->modelsurfaces_sorted));
        }
        surf = mod->data_surfaces + mod->num_surfaces;
        mod->num_surfaces++;
@@ -4571,13 +4537,13 @@ msurface_t *Mod_Mesh_AddSurface(dp_model_t *mod, texture_t *tex, qboolean batchw
        surf->num_firsttriangle = mod->surfmesh.num_triangles;
        surf->num_firstvertex = mod->surfmesh.num_vertices;
        if (tex->basematerialflags & (MATERIALFLAG_SKY))
-               mod->DrawSky = R_Q1BSP_DrawSky;
+               mod->DrawSky = R_Mod_DrawSky;
        if (tex->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
-               mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
+               mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
        return surf;
 }
 
-int Mod_Mesh_IndexForVertex(dp_model_t *mod, msurface_t *surf, float x, float y, float z, float nx, float ny, float nz, float s, float t, float u, float v, float r, float g, float b, float a)
+int Mod_Mesh_IndexForVertex(model_t *mod, msurface_t *surf, float x, float y, float z, float nx, float ny, float nz, float s, float t, float u, float v, float r, float g, float b, float a)
 {
        int hashindex, h, vnum, mask;
        surfmesh_t *mesh = &mod->surfmesh;
@@ -4656,7 +4622,7 @@ int Mod_Mesh_IndexForVertex(dp_model_t *mod, msurface_t *surf, float x, float y,
        return vnum;
 }
 
-void Mod_Mesh_AddTriangle(dp_model_t *mod, msurface_t *surf, int e0, int e1, int e2)
+void Mod_Mesh_AddTriangle(model_t *mod, msurface_t *surf, int e0, int e1, int e2)
 {
        surfmesh_t *mesh = &mod->surfmesh;
        if (mesh->max_triangles == mesh->num_triangles)
@@ -4675,39 +4641,36 @@ void Mod_Mesh_AddTriangle(dp_model_t *mod, msurface_t *surf, int e0, int e1, int
        surf->num_triangles++;
 }
 
-static void Mod_Mesh_MakeSortedSurfaces(dp_model_t *mod)
+static void Mod_Mesh_MakeSortedSurfaces(model_t *mod)
 {
        int i, j;
        texture_t *tex;
-       msurface_t *surf, *surf2;
+       unsigned char* included = (unsigned char *)R_FrameData_Alloc(mod->num_surfaces * sizeof(unsigned char));
 
        // build the sorted surfaces list properly to reduce material setup
        // this is easy because we're just sorting on texture and don't care about the order of textures
-       mod->nummodelsurfaces = 0;
+       mod->submodelsurfaces_start = 0;
+       mod->submodelsurfaces_end = 0;
        for (i = 0; i < mod->num_surfaces; i++)
-               mod->data_surfaces[i].included = false;
+               included[i] = 0;
        for (i = 0; i < mod->num_surfaces; i++)
        {
-               surf = mod->data_surfaces + i;
-               if (surf->included)
+               if (included[i])
                        continue;
-               tex = surf->texture;
+               tex = mod->data_surfaces[i].texture;
                // j = i is intentional
                for (j = i; j < mod->num_surfaces; j++)
                {
-                       surf2 = mod->data_surfaces + j;
-                       if (surf2->included)
-                               continue;
-                       if (surf2->texture == tex)
+                       if (!included[j] && mod->data_surfaces[j].texture == tex)
                        {
-                               surf2->included = true;
-                               mod->sortedmodelsurfaces[mod->nummodelsurfaces++] = j;
+                               included[j] = 1;
+                               mod->modelsurfaces_sorted[mod->submodelsurfaces_end++] = j;
                        }
                }
        }
 }
 
-void Mod_Mesh_ComputeBounds(dp_model_t *mod)
+static void Mod_Mesh_ComputeBounds(model_t *mod)
 {
        int i;
        vec_t x2a, x2b, y2a, y2b, z2a, z2b, x2, y2, z2, yawradius, rotatedradius;
@@ -4763,9 +4726,52 @@ void Mod_Mesh_ComputeBounds(dp_model_t *mod)
        }
 }
 
-void Mod_Mesh_Finalize(dp_model_t *mod)
+void Mod_Mesh_Validate(model_t *mod)
+{
+       int i;
+       qbool warned = false;
+       for (i = 0; i < mod->num_surfaces; i++)
+       {
+               msurface_t *surf = mod->data_surfaces + i;
+               int *e = mod->surfmesh.data_element3i + surf->num_firsttriangle * 3;
+               int first = surf->num_firstvertex;
+               int end = surf->num_firstvertex + surf->num_vertices;
+               int j;
+               for (j = 0;j < surf->num_triangles * 3;j++)
+               {
+                       if (e[j] < first || e[j] >= end)
+                       {
+                               if (!warned)
+                                       Con_DPrintf("Mod_Mesh_Validate: detected corrupt surface - debug me!\n");
+                               warned = true;
+                               e[j] = first;
+                       }
+               }
+       }
+}
+
+static void Mod_Mesh_UploadDynamicBuffers(model_t *mod)
+{
+       mod->surfmesh.data_element3s_indexbuffer = mod->surfmesh.data_element3s ? R_BufferData_Store(mod->surfmesh.num_triangles * sizeof(short[3]), mod->surfmesh.data_element3s, R_BUFFERDATA_INDEX16, &mod->surfmesh.data_element3s_bufferoffset) : NULL;
+       mod->surfmesh.data_element3i_indexbuffer = mod->surfmesh.data_element3i ? R_BufferData_Store(mod->surfmesh.num_triangles * sizeof(int[3]), mod->surfmesh.data_element3i, R_BUFFERDATA_INDEX32, &mod->surfmesh.data_element3i_bufferoffset) : NULL;
+       mod->surfmesh.data_vertex3f_vertexbuffer = mod->surfmesh.data_vertex3f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[3]), mod->surfmesh.data_vertex3f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_vertex3f_bufferoffset) : NULL;
+       mod->surfmesh.data_svector3f_vertexbuffer = mod->surfmesh.data_svector3f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[3]), mod->surfmesh.data_svector3f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_svector3f_bufferoffset) : NULL;
+       mod->surfmesh.data_tvector3f_vertexbuffer = mod->surfmesh.data_tvector3f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[3]), mod->surfmesh.data_tvector3f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_tvector3f_bufferoffset) : NULL;
+       mod->surfmesh.data_normal3f_vertexbuffer = mod->surfmesh.data_normal3f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[3]), mod->surfmesh.data_normal3f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_normal3f_bufferoffset) : NULL;
+       mod->surfmesh.data_texcoordtexture2f_vertexbuffer = mod->surfmesh.data_texcoordtexture2f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[2]), mod->surfmesh.data_texcoordtexture2f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_texcoordtexture2f_bufferoffset) : NULL;
+       mod->surfmesh.data_texcoordlightmap2f_vertexbuffer = mod->surfmesh.data_texcoordlightmap2f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[2]), mod->surfmesh.data_texcoordlightmap2f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_texcoordlightmap2f_bufferoffset) : NULL;
+       mod->surfmesh.data_lightmapcolor4f_vertexbuffer = mod->surfmesh.data_lightmapcolor4f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[4]), mod->surfmesh.data_lightmapcolor4f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_lightmapcolor4f_bufferoffset) : NULL;
+       mod->surfmesh.data_skeletalindex4ub_vertexbuffer = mod->surfmesh.data_skeletalindex4ub ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(unsigned char[4]), mod->surfmesh.data_skeletalindex4ub, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_skeletalindex4ub_bufferoffset) : NULL;
+       mod->surfmesh.data_skeletalweight4ub_vertexbuffer = mod->surfmesh.data_skeletalweight4ub ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(unsigned char[4]), mod->surfmesh.data_skeletalweight4ub, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_skeletalweight4ub_bufferoffset) : NULL;
+}
+
+void Mod_Mesh_Finalize(model_t *mod)
 {
+       if (gl_paranoid.integer)
+               Mod_Mesh_Validate(mod);
        Mod_Mesh_ComputeBounds(mod);
        Mod_Mesh_MakeSortedSurfaces(mod);
-       Mod_BuildTextureVectorsFromNormals(0, mod->surfmesh.num_vertices, mod->surfmesh.num_triangles, mod->surfmesh.data_vertex3f, mod->surfmesh.data_texcoordtexture2f, mod->surfmesh.data_normal3f, mod->surfmesh.data_element3i, mod->surfmesh.data_svector3f, mod->surfmesh.data_tvector3f, true);
+       if(!r_refdef.draw2dstage)
+               Mod_BuildTextureVectorsFromNormals(0, mod->surfmesh.num_vertices, mod->surfmesh.num_triangles, mod->surfmesh.data_vertex3f, mod->surfmesh.data_texcoordtexture2f, mod->surfmesh.data_normal3f, mod->surfmesh.data_element3i, mod->surfmesh.data_svector3f, mod->surfmesh.data_tvector3f, true);
+       Mod_Mesh_UploadDynamicBuffers(mod);
 }