]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_alias.c
added .dpm model support
[xonotic/darkplaces.git] / model_alias.c
index 8334f3ecdd1d50a7ce4fbc9f75eaefaeb0500976..572f038b7becc441de8f3a93e2d8ea3efd35f828 100644 (file)
@@ -70,6 +70,8 @@ void Mod_Alias_GetMesh_Vertex3f(const model_t *model, const frameblend_t *frameb
                float lerp1, lerp2, lerp3, lerp4;
                const float *vertsbase, *verts1, *verts2, *verts3, *verts4;
                // vertex morph
+               if (!mesh->data_morphvertex3f)
+                       Host_Error("model %s has no skeletal or vertex morph animation data\n", model->name);
                vertsbase = mesh->data_morphvertex3f;
                vertcount = mesh->num_vertices;
                verts1 = vertsbase + frameblend[0].frame * vertcount * 3;
@@ -175,17 +177,17 @@ static void Mod_Alias_Mesh_CompileFrameZero(surfmesh_t *mesh)
        mesh->data_tvector3f = mesh->data_vertex3f + mesh->num_vertices * 6;
        mesh->data_normal3f = mesh->data_vertex3f + mesh->num_vertices * 9;
        Mod_Alias_GetMesh_Vertex3f(loadmodel, frameblend, mesh, mesh->data_vertex3f);
-       Mod_BuildTextureVectorsAndNormals(0, mesh->num_vertices, mesh->num_triangles, mesh->data_vertex3f, mesh->data_texcoordtexture2f, mesh->data_element3i, mesh->data_svector3f, mesh->data_tvector3f, mesh->data_normal3f);
+       Mod_BuildTextureVectorsAndNormals(0, mesh->num_vertices, mesh->num_triangles, mesh->data_vertex3f, mesh->data_texcoordtexture2f, mesh->data_element3i, mesh->data_svector3f, mesh->data_tvector3f, mesh->data_normal3f, true);
 }
 
 static void Mod_MDLMD2MD3_TraceBox(model_t *model, int frame, trace_t *trace, const vec3_t boxstartmins, const vec3_t boxstartmaxs, const vec3_t boxendmins, const vec3_t boxendmaxs, int hitsupercontentsmask)
 {
-       int i, framenum, linetrace;
-       float *vertex3f;
+       int i, linetrace;
        float segmentmins[3], segmentmaxs[3];
+       frameblend_t frameblend[4];
        msurface_t *surface;
        surfmesh_t *mesh;
-       colbrushf_t *thisbrush_start, *thisbrush_end;
+       colbrushf_t *thisbrush_start = NULL, *thisbrush_end = NULL;
        matrix4x4_t startmatrix, endmatrix;
        memset(trace, 0, sizeof(*trace));
        trace->fraction = 1;
@@ -206,23 +208,17 @@ static void Mod_MDLMD2MD3_TraceBox(model_t *model, int frame, trace_t *trace, co
                thisbrush_start = Collision_BrushForBox(&startmatrix, boxstartmins, boxstartmaxs);
                thisbrush_end = Collision_BrushForBox(&endmatrix, boxendmins, boxendmaxs);
        }
+       memset(frameblend, 0, sizeof(frameblend));
+       frameblend[0].frame = frame;
+       frameblend[0].lerp = 1;
        for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
        {
                mesh = surface->groupmesh;
-               framenum = frame;
-               if (framenum < 0 || framenum > mesh->num_morphframes)
-                       framenum = 0;
-               if (mesh->data_morphvertex3f)
-                       vertex3f = mesh->data_morphvertex3f + framenum * mesh->num_vertices * 3;
-               else
-               {
-                       vertex3f = varray_vertex3f;
-                       continue; // FIXME!!!  this needs to handle skeletal!
-               }
+               Mod_Alias_GetMesh_Vertex3f(model, frameblend, mesh, varray_vertex3f);
                if (linetrace)
-                       Collision_TraceLineTriangleMeshFloat(trace, boxstartmins, boxendmins, mesh->num_triangles, mesh->data_element3i, vertex3f, SUPERCONTENTS_SOLID, segmentmins, segmentmaxs);
+                       Collision_TraceLineTriangleMeshFloat(trace, boxstartmins, boxendmins, mesh->num_triangles, mesh->data_element3i, varray_vertex3f, SUPERCONTENTS_SOLID, segmentmins, segmentmaxs);
                else
-                       Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, mesh->num_triangles, mesh->data_element3i, vertex3f, SUPERCONTENTS_SOLID, segmentmins, segmentmaxs);
+                       Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, mesh->num_triangles, mesh->data_element3i, varray_vertex3f, SUPERCONTENTS_SOLID, segmentmins, segmentmaxs);
        }
 }
 
@@ -361,6 +357,11 @@ static void Mod_BuildAliasSkinFromSkinFrame(texture_t *skin, skinframe_t *skinfr
        }
 
        skin->skin = *skinframe;
+       skin->currentframe = skin;
+       skin->basematerialflags = MATERIALFLAG_WALL;
+       if (skin->skin.fog)
+               skin->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT;
+       skin->currentmaterialflags = skin->basematerialflags;
 }
 
 static void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, char *meshname, char *shadername)
@@ -370,7 +371,8 @@ static void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfi
        skinframe_t tempskinframe;
        if (skinfile)
        {
-               for (i = 0;skinfile;skinfile = skinfile->next, i++, skin++)
+               // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
+               for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
                {
                        memset(skin, 0, sizeof(*skin));
                        for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
@@ -379,13 +381,13 @@ static void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfi
                                if (!strcmp(skinfileitem->name, meshname) && strcmp(skinfileitem->replacement, "common/nodraw") && strcmp(skinfileitem->replacement, "textures/common/nodraw"))
                                {
                                        memset(&tempskinframe, 0, sizeof(tempskinframe));
-                                       if (Mod_LoadSkinFrame(&tempskinframe, skinfileitem->replacement, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_CLAMP | TEXF_PRECACHE | TEXF_PICMIP, true, false, true))
+                                       if (Mod_LoadSkinFrame(&tempskinframe, skinfileitem->replacement, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, true, false, true))
                                                Mod_BuildAliasSkinFromSkinFrame(skin, &tempskinframe);
                                        else
                                        {
                                                if (cls.state != ca_dedicated)
                                                        Con_Printf("mesh \"%s\": failed to load skin #%i \"%s\", falling back to mesh's internal shader name \"%s\"\n", meshname, i, skinfileitem->replacement, shadername);
-                                               if (Mod_LoadSkinFrame(&tempskinframe, shadername, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_CLAMP | TEXF_PRECACHE | TEXF_PICMIP, true, false, true))
+                                               if (Mod_LoadSkinFrame(&tempskinframe, shadername, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, true, false, true))
                                                        Mod_BuildAliasSkinFromSkinFrame(skin, &tempskinframe);
                                                else
                                                {
@@ -401,7 +403,7 @@ static void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfi
        else
        {
                memset(&tempskinframe, 0, sizeof(tempskinframe));
-               if (Mod_LoadSkinFrame(&tempskinframe, shadername, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_CLAMP | TEXF_PRECACHE | TEXF_PICMIP, true, false, true))
+               if (Mod_LoadSkinFrame(&tempskinframe, shadername, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, true, false, true))
                        Mod_BuildAliasSkinFromSkinFrame(skin, &tempskinframe);
                else
                {
@@ -414,9 +416,9 @@ static void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfi
 
 #define BOUNDI(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%d exceeds %d - %d)\n", loadmodel->name, VALUE, MIN, MAX);
 #define BOUNDF(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%f exceeds %f - %f)\n", loadmodel->name, VALUE, MIN, MAX);
-extern void R_Model_Alias_Draw(entity_render_t *ent);
-extern void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs);
-extern void R_Model_Alias_DrawLight(entity_render_t *ent, float *lightcolor, int numsurfaces, const int *surfacelist);
+extern void R_Q1BSP_Draw(entity_render_t *ent);
+extern void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs);
+extern void R_Q1BSP_DrawLight(entity_render_t *ent, float *lightcolor, int numsurfaces, const int *surfacelist);
 void Mod_IDP0_Load(model_t *mod, void *buffer)
 {
        int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
@@ -451,18 +453,23 @@ void Mod_IDP0_Load(model_t *mod, void *buffer)
 
        loadmodel->type = mod_alias;
        loadmodel->DrawSky = NULL;
-       loadmodel->Draw = R_Model_Alias_Draw;
-       loadmodel->DrawShadowVolume = R_Model_Alias_DrawShadowVolume;
-       loadmodel->DrawLight = R_Model_Alias_DrawLight;
+       loadmodel->Draw = R_Q1BSP_Draw;
+       loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
+       loadmodel->DrawLight = R_Q1BSP_DrawLight;
        loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
 
        loadmodel->num_surfaces = 1;
+       loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
        loadmodel->nummeshes = loadmodel->num_surfaces;
-       data = Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->nummeshes * sizeof(surfmesh_t *) + loadmodel->nummeshes * sizeof(surfmesh_t));
+       data = Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->nummeshes * sizeof(surfmesh_t *) + loadmodel->nummeshes * sizeof(surfmesh_t));
        loadmodel->data_surfaces = (void *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
+       loadmodel->surfacelist = (void *)data;data += loadmodel->num_surfaces * sizeof(int);
        loadmodel->meshlist = (void *)data;data += loadmodel->num_surfaces * sizeof(surfmesh_t *);
        for (i = 0;i < loadmodel->num_surfaces;i++)
+       {
+               loadmodel->surfacelist[i] = i;
                loadmodel->meshlist[i] = (void *)data;data += sizeof(surfmesh_t);
+       }
 
        loadmodel->numskins = LittleLong(pinmodel->numskins);
        BOUNDI(loadmodel->numskins,0,65536);
@@ -616,13 +623,14 @@ void Mod_IDP0_Load(model_t *mod, void *buffer)
        Mem_Free(vertremap);
 
        // load the skins
-       if ((skinfiles = Mod_LoadSkinFiles()))
+       skinfiles = Mod_LoadSkinFiles();
+       loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
+       loadmodel->num_textures = loadmodel->num_surfaces;
+       loadmodel->data_textures = Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
+       if (skinfiles)
        {
-               loadmodel->meshlist[0]->num_skins = totalskins = loadmodel->numskins;
-               loadmodel->meshlist[0]->data_skins = Mem_Alloc(loadmodel->mempool, loadmodel->meshlist[0]->num_skins * sizeof(texture_t));
-               Mod_BuildAliasSkinsFromSkinFiles(loadmodel->meshlist[0]->data_skins, skinfiles, "default", "");
+               Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
                Mod_FreeSkinFiles(skinfiles);
-               loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
                for (i = 0;i < loadmodel->numskins;i++)
                {
                        loadmodel->skinscenes[i].firstframe = i;
@@ -633,9 +641,6 @@ void Mod_IDP0_Load(model_t *mod, void *buffer)
        }
        else
        {
-               loadmodel->meshlist[0]->num_skins = totalskins;
-               loadmodel->meshlist[0]->data_skins = Mem_Alloc(loadmodel->mempool, loadmodel->meshlist[0]->num_skins * sizeof(texture_t));
-               loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
                totalskins = 0;
                datapointer = startskins;
                for (i = 0;i < loadmodel->numskins;i++)
@@ -678,16 +683,16 @@ void Mod_IDP0_Load(model_t *mod, void *buffer)
                                        sprintf (name, "%s_%i_%i", loadmodel->name, i, j);
                                else
                                        sprintf (name, "%s_%i", loadmodel->name, i);
-                               if (!Mod_LoadSkinFrame(&tempskinframe, name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_CLAMP | TEXF_ALPHA | TEXF_PICMIP, true, false, true))
-                                       Mod_LoadSkinFrame_Internal(&tempskinframe, name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_CLAMP | TEXF_ALPHA | TEXF_PICMIP, true, false, r_fullbrights.integer, (qbyte *)datapointer, skinwidth, skinheight);
-                               Mod_BuildAliasSkinFromSkinFrame(loadmodel->meshlist[0]->data_skins + totalskins, &tempskinframe);
+                               if (!Mod_LoadSkinFrame(&tempskinframe, name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP, true, false, true))
+                                       Mod_LoadSkinFrame_Internal(&tempskinframe, name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP, true, false, r_fullbrights.integer, (qbyte *)datapointer, skinwidth, skinheight);
+                               Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, &tempskinframe);
                                datapointer += skinwidth * skinheight;
                                totalskins++;
                        }
                }
                // check for skins that don't exist in the model, but do exist as external images
                // (this was added because yummyluv kept pestering me about support for it)
-               while (Mod_LoadSkinFrame(&tempskinframe, va("%s_%i", loadmodel->name, loadmodel->numskins), (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_CLAMP | TEXF_ALPHA | TEXF_PICMIP, true, false, true))
+               while (Mod_LoadSkinFrame(&tempskinframe, va("%s_%i", loadmodel->name, loadmodel->numskins), (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP, true, false, true))
                {
                        // expand the arrays to make room
                        tempskinscenes = loadmodel->skinscenes;
@@ -695,13 +700,13 @@ void Mod_IDP0_Load(model_t *mod, void *buffer)
                        memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
                        Mem_Free(tempskinscenes);
 
-                       tempaliasskins = loadmodel->meshlist[0]->data_skins;
-                       loadmodel->meshlist[0]->data_skins = Mem_Alloc(loadmodel->mempool, (totalskins + 1) * sizeof(texture_t));
-                       memcpy(loadmodel->meshlist[0]->data_skins, tempaliasskins, totalskins * sizeof(texture_t));
+                       tempaliasskins = loadmodel->data_textures;
+                       loadmodel->data_textures = Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
+                       memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
                        Mem_Free(tempaliasskins);
 
                        // store the info about the new skin
-                       Mod_BuildAliasSkinFromSkinFrame(loadmodel->meshlist[0]->data_skins + totalskins, &tempskinframe);
+                       Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, &tempskinframe);
                        strcpy(loadmodel->skinscenes[loadmodel->numskins].name, name);
                        loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
                        loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
@@ -709,16 +714,14 @@ void Mod_IDP0_Load(model_t *mod, void *buffer)
                        loadmodel->skinscenes[loadmodel->numskins].loop = true;
 
                        //increase skin counts
-                       loadmodel->meshlist[0]->num_skins++;
                        loadmodel->numskins++;
                        totalskins++;
                }
        }
 
        surface = loadmodel->data_surfaces;
+       surface->texture = loadmodel->data_textures;
        surface->groupmesh = loadmodel->meshlist[0];
-       // FIXME: need to store data_skins in msurface_t, not surfmesh_t
-       surface->texture = surface->groupmesh->data_skins;
        surface->num_firsttriangle = 0;
        surface->num_triangles = surface->groupmesh->num_triangles;
        surface->num_firstvertex = 0;
@@ -770,9 +773,9 @@ void Mod_IDP2_Load(model_t *mod, void *buffer)
 
        loadmodel->type = mod_alias;
        loadmodel->DrawSky = NULL;
-       loadmodel->Draw = R_Model_Alias_Draw;
-       loadmodel->DrawShadowVolume = R_Model_Alias_DrawShadowVolume;
-       loadmodel->DrawLight = R_Model_Alias_DrawLight;
+       loadmodel->Draw = R_Q1BSP_Draw;
+       loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
+       loadmodel->DrawLight = R_Q1BSP_DrawLight;
        loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
 
        if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
@@ -797,12 +800,17 @@ void Mod_IDP2_Load(model_t *mod, void *buffer)
                Host_Error ("%s is not a valid model", loadmodel->name);
 
        loadmodel->num_surfaces = 1;
+       loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
        loadmodel->nummeshes = loadmodel->num_surfaces;
-       data = Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->nummeshes * sizeof(surfmesh_t *) + loadmodel->nummeshes * sizeof(surfmesh_t));
+       data = Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->nummeshes * sizeof(surfmesh_t *) + loadmodel->nummeshes * sizeof(surfmesh_t));
        loadmodel->data_surfaces = (void *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
+       loadmodel->surfacelist = (void *)data;data += loadmodel->num_surfaces * sizeof(int);
        loadmodel->meshlist = (void *)data;data += loadmodel->num_surfaces * sizeof(surfmesh_t *);
        for (i = 0;i < loadmodel->num_surfaces;i++)
+       {
+               loadmodel->surfacelist[i] = i;
                loadmodel->meshlist[i] = (void *)data;data += sizeof(surfmesh_t);
+       }
 
        loadmodel->numskins = LittleLong(pinmodel->num_skins);
        numxyz = LittleLong(pinmodel->num_xyz);
@@ -817,26 +825,27 @@ void Mod_IDP2_Load(model_t *mod, void *buffer)
 
        // load the skins
        inskin = (void*)(base + LittleLong(pinmodel->ofs_skins));
-       if ((skinfiles = Mod_LoadSkinFiles()))
+       skinfiles = Mod_LoadSkinFiles();
+       if (skinfiles)
        {
-               loadmodel->meshlist[0]->num_skins = loadmodel->numskins;
-               loadmodel->meshlist[0]->data_skins = Mem_Alloc(loadmodel->mempool, loadmodel->meshlist[0]->num_skins * sizeof(texture_t));
-               Mod_BuildAliasSkinsFromSkinFiles(loadmodel->meshlist[0]->data_skins, skinfiles, "default", "");
+               loadmodel->num_textures = loadmodel->num_surfaces;
+               loadmodel->data_textures = Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
+               Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
                Mod_FreeSkinFiles(skinfiles);
        }
        else if (loadmodel->numskins)
        {
                // skins found (most likely not a player model)
-               loadmodel->meshlist[0]->num_skins = loadmodel->numskins;
-               loadmodel->meshlist[0]->data_skins = Mem_Alloc(loadmodel->mempool, loadmodel->meshlist[0]->num_skins * sizeof(texture_t));
+               loadmodel->num_textures = loadmodel->num_surfaces;
+               loadmodel->data_textures = Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
                for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
                {
-                       if (Mod_LoadSkinFrame(&tempskinframe, inskin, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_CLAMP | TEXF_PRECACHE | TEXF_PICMIP, true, false, true))
-                               Mod_BuildAliasSkinFromSkinFrame(loadmodel->meshlist[0]->data_skins + i, &tempskinframe);
+                       if (Mod_LoadSkinFrame(&tempskinframe, inskin, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, true, false, true))
+                               Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + i * loadmodel->num_surfaces, &tempskinframe);
                        else
                        {
                                Con_Printf("%s is missing skin \"%s\"\n", loadmodel->name, inskin);
-                               Mod_BuildAliasSkinFromSkinFrame(loadmodel->meshlist[0]->data_skins + i, NULL);
+                               Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + i * loadmodel->num_surfaces, NULL);
                        }
                }
        }
@@ -844,9 +853,9 @@ void Mod_IDP2_Load(model_t *mod, void *buffer)
        {
                // no skins (most likely a player model)
                loadmodel->numskins = 1;
-               loadmodel->meshlist[0]->num_skins = loadmodel->numskins;
-               loadmodel->meshlist[0]->data_skins = Mem_Alloc(loadmodel->mempool, loadmodel->meshlist[0]->num_skins * sizeof(texture_t));
-               Mod_BuildAliasSkinFromSkinFrame(loadmodel->meshlist[0]->data_skins, NULL);
+               loadmodel->num_textures = loadmodel->num_surfaces;
+               loadmodel->data_textures = Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
+               Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL);
        }
 
        loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
@@ -969,8 +978,7 @@ void Mod_IDP2_Load(model_t *mod, void *buffer)
 
        surface = loadmodel->data_surfaces;
        surface->groupmesh = loadmodel->meshlist[0];
-       // FIXME: need to store data_skins in msurface_t, not surfmesh_t
-       surface->texture = surface->groupmesh->data_skins;
+       surface->texture = loadmodel->data_textures;
        surface->num_firsttriangle = 0;
        surface->num_triangles = surface->groupmesh->num_triangles;
        surface->num_firstvertex = 0;
@@ -1004,9 +1012,9 @@ void Mod_IDP3_Load(model_t *mod, void *buffer)
 
        loadmodel->type = mod_alias;
        loadmodel->DrawSky = NULL;
-       loadmodel->Draw = R_Model_Alias_Draw;
-       loadmodel->DrawShadowVolume = R_Model_Alias_DrawShadowVolume;
-       loadmodel->DrawLight = R_Model_Alias_DrawLight;
+       loadmodel->Draw = R_Q1BSP_Draw;
+       loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
+       loadmodel->DrawLight = R_Q1BSP_DrawLight;
        loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
        loadmodel->flags = LittleLong(pinmodel->flags);
        loadmodel->synctype = ST_RAND;
@@ -1054,22 +1062,27 @@ void Mod_IDP3_Load(model_t *mod, void *buffer)
        }
 
        // load meshes
+       loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
        loadmodel->nummeshes = loadmodel->num_surfaces;
-       data = Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->nummeshes * sizeof(surfmesh_t *) + loadmodel->nummeshes * sizeof(surfmesh_t));
+       loadmodel->num_textures = loadmodel->num_surfaces;
+       data = Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->nummeshes * sizeof(surfmesh_t *) + loadmodel->nummeshes * sizeof(surfmesh_t) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
        loadmodel->data_surfaces = (void *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
+       loadmodel->surfacelist = (void *)data;data += loadmodel->num_surfaces * sizeof(int);
        loadmodel->meshlist = (void *)data;data += loadmodel->num_surfaces * sizeof(surfmesh_t *);
+       loadmodel->data_textures = (void *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
        for (i = 0;i < loadmodel->num_surfaces;i++)
-               mesh = loadmodel->meshlist[i] = (void *)data;data += sizeof(surfmesh_t);
+       {
+               loadmodel->surfacelist[i] = i;
+               loadmodel->meshlist[i] = (void *)data;data += sizeof(surfmesh_t);
+       }
        for (i = 0, pinmesh = (md3mesh_t *)((qbyte *)pinmodel + LittleLong(pinmodel->lump_meshes));i < loadmodel->num_surfaces;i++, pinmesh = (md3mesh_t *)((qbyte *)pinmesh + LittleLong(pinmesh->lump_end)))
        {
                if (memcmp(pinmesh->identifier, "IDP3", 4))
                        Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)\n");
                mesh = loadmodel->meshlist[i];
-               mesh->num_skins = loadmodel->numskins;
                mesh->num_morphframes = LittleLong(pinmesh->num_frames);
                mesh->num_vertices = LittleLong(pinmesh->num_vertices);
                mesh->num_triangles = LittleLong(pinmesh->num_triangles);
-               mesh->data_skins = Mem_Alloc(loadmodel->mempool, mesh->num_skins * sizeof(texture_t));
                mesh->data_element3i = Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
                mesh->data_neighbor3i = Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
                mesh->data_texcoordtexture2f = Mem_Alloc(loadmodel->mempool, mesh->num_vertices * sizeof(float[2]));
@@ -1093,15 +1106,14 @@ void Mod_IDP3_Load(model_t *mod, void *buffer)
                Mod_Alias_Mesh_CompileFrameZero(mesh);
 
                if (LittleLong(pinmesh->num_shaders) >= 1)
-                       Mod_BuildAliasSkinsFromSkinFiles(mesh->data_skins, skinfiles, pinmesh->name, ((md3shader_t *)((qbyte *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name);
+                       Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, ((md3shader_t *)((qbyte *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name);
                else
-                       for (j = 0;j < mesh->num_skins;j++)
-                               Mod_BuildAliasSkinFromSkinFrame(mesh->data_skins + j, NULL);
+                       for (j = 0;j < loadmodel->numskins;j++)
+                               Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + i + j * loadmodel->num_surfaces, NULL);
 
                surface = loadmodel->data_surfaces + i;
                surface->groupmesh = mesh;
-               // FIXME: need to store data_skins in msurface_t, not surfmesh_t
-               surface->texture = mesh->data_skins;
+               surface->texture = loadmodel->data_textures + i;
                surface->num_firsttriangle = 0;
                surface->num_triangles = mesh->num_triangles;
                surface->num_firstvertex = 0;
@@ -1135,10 +1147,10 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer)
 
        loadmodel->type = mod_alias;
        loadmodel->DrawSky = NULL;
-       loadmodel->Draw = R_Model_Alias_Draw;
-       loadmodel->DrawShadowVolume = R_Model_Alias_DrawShadowVolume;
-       loadmodel->DrawLight = R_Model_Alias_DrawLight;
-       //loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox; // FIXME: implement collisions
+       loadmodel->Draw = R_Q1BSP_Draw;
+       loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
+       loadmodel->DrawLight = R_Q1BSP_DrawLight;
+       loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
        loadmodel->flags = 0; // there are no flags on zym models
        loadmodel->synctype = ST_RAND;
 
@@ -1291,12 +1303,19 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer)
        //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
        //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
 
+       loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
        loadmodel->nummeshes = loadmodel->num_surfaces;
-       data = Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->nummeshes * sizeof(surfmesh_t *) + loadmodel->nummeshes * sizeof(surfmesh_t));
+       loadmodel->num_textures = loadmodel->num_surfaces;
+       data = Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->nummeshes * sizeof(surfmesh_t *) + loadmodel->nummeshes * sizeof(surfmesh_t) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
        loadmodel->data_surfaces = (void *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
+       loadmodel->surfacelist = (void *)data;data += loadmodel->num_surfaces * sizeof(int);
        loadmodel->meshlist = (void *)data;data += loadmodel->num_surfaces * sizeof(surfmesh_t *);
+       loadmodel->data_textures = (void *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
        for (i = 0;i < loadmodel->num_surfaces;i++)
-               mesh = loadmodel->meshlist[i] = (void *)data;data += sizeof(surfmesh_t);
+       {
+               loadmodel->surfacelist[i] = i;
+               loadmodel->meshlist[i] = (void *)data;data += sizeof(surfmesh_t);
+       }
 
        //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
        //zymlump_t lump_render; // int renderlist[rendersize]; // sorted by shader with run lengths (int count), shaders are sequentially used, each run can be used with glDrawElements (each triangle is 3 int indices)
@@ -1314,9 +1333,7 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer)
                if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
                        Host_Error("%s corrupt renderlist (wrong size)\n", loadmodel->name);
                mesh = loadmodel->meshlist[i];
-               mesh->num_skins = loadmodel->numskins;
                mesh->num_triangles = count;
-               mesh->data_skins = Mem_Alloc(loadmodel->mempool, mesh->num_skins * sizeof(texture_t));
                mesh->data_element3i = Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
                mesh->data_neighbor3i = Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
                outelements = mesh->data_element3i;
@@ -1329,6 +1346,8 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer)
                         || (unsigned int)outelements[1] >= (unsigned int)pheader->numverts
                         || (unsigned int)outelements[2] >= (unsigned int)pheader->numverts)
                                Host_Error("%s corrupt renderlist (out of bounds index)\n", loadmodel->name);
+                       if (vertbonecounts[outelements[0]] == 0 || vertbonecounts[outelements[1]] == 0 || vertbonecounts[outelements[2]] == 0)
+                               Host_Error("%s corrupt renderlist (references vertex with no bone weights\n", loadmodel->name);
                        renderlist += 3;
                        outelements += 3;
                }
@@ -1336,7 +1355,6 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer)
                mesh->num_vertices = Mod_BuildVertexRemapTableFromElements(mesh->num_triangles * 3, mesh->data_element3i, pheader->numverts, remapvertices);
                for (j = 0;j < mesh->num_triangles * 3;j++)
                        mesh->data_element3i[j] = remapvertices[mesh->data_element3i[j]];
-               Mod_BuildTriangleNeighbors(mesh->data_neighbor3i, mesh->data_element3i, mesh->num_triangles);
                mesh->data_texcoordtexture2f = Mem_Alloc(loadmodel->mempool, mesh->num_vertices * sizeof(float[2]));
                for (j = 0;j < pheader->numverts;j++)
                {
@@ -1347,14 +1365,14 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer)
                        }
                }
                mesh->num_vertexboneweights = 0;
-               for (j = 0;j < mesh->num_vertices;j++)
+               for (j = 0;j < pheader->numverts;j++)
                        if (remapvertices[j] >= 0)
                                mesh->num_vertexboneweights += vertbonecounts[remapvertices[j]];
                mesh->data_vertexboneweights = Mem_Alloc(loadmodel->mempool, mesh->num_vertexboneweights * sizeof(surfmeshvertexboneweight_t));
                mesh->num_vertexboneweights = 0;
                // note this vertexboneweight ordering requires that the remapvertices array is sequential numbers (separated by -1 values for omitted vertices)
                l = 0;
-               for (j = 0;j < mesh->num_vertices;j++)
+               for (j = 0;j < pheader->numverts;j++)
                {
                        if (remapvertices[j] < 0)
                        {
@@ -1374,24 +1392,22 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer)
                                l++;
                        }
                }
-
-               Mod_ValidateElements(mesh->data_element3i, mesh->num_triangles, mesh->num_vertices, __FILE__, __LINE__);
-               Mod_BuildTriangleNeighbors(mesh->data_neighbor3i, mesh->data_element3i, mesh->num_triangles);
-               Mod_Alias_Mesh_CompileFrameZero(mesh);
-
+               shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
                // since zym models do not have named sections, reuse their shader
                // name as the section name
-               shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
                if (shadername[0])
-                       Mod_BuildAliasSkinsFromSkinFiles(mesh->data_skins, skinfiles, shadername, shadername);
+                       Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
                else
-                       for (j = 0;j < mesh->num_skins;j++)
-                               Mod_BuildAliasSkinFromSkinFrame(mesh->data_skins + j, NULL);
+                       for (j = 0;j < loadmodel->numskins;j++)
+                               Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + i + j * loadmodel->num_surfaces, NULL);
+
+               Mod_ValidateElements(mesh->data_element3i, mesh->num_triangles, mesh->num_vertices, __FILE__, __LINE__);
+               Mod_BuildTriangleNeighbors(mesh->data_neighbor3i, mesh->data_element3i, mesh->num_triangles);
+               Mod_Alias_Mesh_CompileFrameZero(mesh);
 
                surface = loadmodel->data_surfaces + i;
                surface->groupmesh = mesh;
-               // FIXME: need to store data_skins in msurface_t, not surfmesh_t
-               surface->texture = mesh->data_skins;
+               surface->texture = loadmodel->data_textures + i;
                surface->num_firsttriangle = 0;
                surface->num_triangles = mesh->num_triangles;
                surface->num_firstvertex = 0;
@@ -1403,3 +1419,215 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer)
        Mem_Free(outtexcoord2f);
 }
 
+void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer)
+{
+       dpmheader_t *pheader;
+       dpmframe_t *frame;
+       dpmbone_t *bone;
+       dpmmesh_t *dpmmesh;
+       qbyte *pbase;
+       int i, j, k;
+       skinfile_t *skinfiles;
+       qbyte *data;
+
+       pheader = (void *)buffer;
+       pbase = buffer;
+       if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
+               Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a zymotic model\n");
+       if (BigLong(pheader->type) != 2)
+               Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)\n", loadmodel->name);
+
+       loadmodel->type = mod_alias;
+       loadmodel->DrawSky = NULL;
+       loadmodel->Draw = R_Q1BSP_Draw;
+       loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
+       loadmodel->DrawLight = R_Q1BSP_DrawLight;
+       loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
+       loadmodel->flags = 0; // there are no flags on zym models
+       loadmodel->synctype = ST_RAND;
+
+       // byteswap header
+       pheader->type = BigLong(pheader->type);
+       pheader->filesize = BigLong(pheader->filesize);
+       pheader->mins[0] = BigFloat(pheader->mins[0]);
+       pheader->mins[1] = BigFloat(pheader->mins[1]);
+       pheader->mins[2] = BigFloat(pheader->mins[2]);
+       pheader->maxs[0] = BigFloat(pheader->maxs[0]);
+       pheader->maxs[1] = BigFloat(pheader->maxs[1]);
+       pheader->maxs[2] = BigFloat(pheader->maxs[2]);
+       pheader->yawradius = BigFloat(pheader->yawradius);
+       pheader->allradius = BigFloat(pheader->allradius);
+       pheader->num_bones = BigLong(pheader->num_bones);
+       pheader->num_meshs = BigLong(pheader->num_meshs);
+       pheader->num_frames = BigLong(pheader->num_frames);
+       pheader->ofs_bones = BigLong(pheader->ofs_bones);
+       pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
+       pheader->ofs_frames = BigLong(pheader->ofs_frames);
+
+       // model bbox
+       for (i = 0;i < 3;i++)
+       {
+               loadmodel->normalmins[i] = pheader->mins[i];
+               loadmodel->normalmaxs[i] = pheader->maxs[i];
+               loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
+               loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
+               loadmodel->rotatedmins[i] = -pheader->allradius;
+               loadmodel->rotatedmaxs[i] = pheader->allradius;
+       }
+       loadmodel->radius = pheader->allradius;
+       loadmodel->radius2 = pheader->allradius * pheader->allradius;
+
+       // load external .skin files if present
+       skinfiles = Mod_LoadSkinFiles();
+       if (loadmodel->numskins < 1)
+               loadmodel->numskins = 1;
+
+       loadmodel->numframes = pheader->num_frames;
+       loadmodel->num_bones = pheader->num_bones;
+       loadmodel->num_poses = loadmodel->num_bones * loadmodel->numframes;
+       loadmodel->num_textures = loadmodel->nummeshes = loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
+
+       // do most allocations as one merged chunk
+       data = Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->nummeshes * sizeof(surfmesh_t *) + loadmodel->nummeshes * sizeof(surfmesh_t) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->num_poses * sizeof(float[12]) + loadmodel->numframes * sizeof(animscene_t));
+       loadmodel->data_surfaces = (void *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
+       loadmodel->surfacelist = (void *)data;data += loadmodel->num_surfaces * sizeof(int);
+       loadmodel->meshlist = (void *)data;data += loadmodel->num_surfaces * sizeof(surfmesh_t *);
+       loadmodel->data_textures = (void *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
+       loadmodel->skinscenes = (void *)data;data += loadmodel->numskins * sizeof(animscene_t);
+       loadmodel->data_bones = (void *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
+       loadmodel->data_poses = (void *)data;data += loadmodel->num_poses * sizeof(float[12]);
+       loadmodel->animscenes = (void *)data;data += loadmodel->numframes * sizeof(animscene_t);
+       for (i = 0;i < loadmodel->numskins;i++)
+       {
+               loadmodel->skinscenes[i].firstframe = i;
+               loadmodel->skinscenes[i].framecount = 1;
+               loadmodel->skinscenes[i].loop = true;
+               loadmodel->skinscenes[i].framerate = 10;
+       }
+       for (i = 0;i < loadmodel->num_surfaces;i++)
+       {
+               loadmodel->surfacelist[i] = i;
+               loadmodel->meshlist[i] = (void *)data;data += sizeof(surfmesh_t);
+       }
+
+       // load the bone info
+       bone = (void *) (pbase + pheader->ofs_bones);
+       for (i = 0;i < loadmodel->num_bones;i++)
+       {
+               memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
+               loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
+               loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
+               if (loadmodel->data_bones[i].parent >= i)
+                       Host_Error("%s bone[%i].parent >= %i\n", loadmodel->name, i, i);
+       }
+
+       // load the frames
+       frame = (void *) (pbase + pheader->ofs_frames);
+       for (i = 0;i < loadmodel->numframes;i++)
+       {
+               const float *poses;
+               memcpy(loadmodel->animscenes[i].name, frame->name, sizeof(frame->name));
+               loadmodel->animscenes[i].firstframe = i;
+               loadmodel->animscenes[i].framecount = 1;
+               loadmodel->animscenes[i].loop = true;
+               loadmodel->animscenes[i].framerate = 10;
+               // load the bone poses for this frame
+               poses = (void *) (pbase + BigLong(frame->ofs_bonepositions));
+               for (j = 0;j < loadmodel->num_bones*12;j++)
+                       loadmodel->data_poses[i * loadmodel->num_bones*12 + j] = BigFloat(poses[j]);
+               // stuff not processed here: mins, maxs, yawradius, allradius
+               frame++;
+       }
+
+       // load the meshes now
+       dpmmesh = (void *) (pbase + pheader->ofs_meshs);
+       for (i = 0;i < loadmodel->num_surfaces;i++)
+       {
+               const int *inelements;
+               int *outelements;
+               const float *intexcoord;
+               surfmesh_t *mesh;
+               msurface_t *surface;
+
+               mesh = loadmodel->meshlist[i];
+               mesh->num_triangles = BigLong(dpmmesh->num_tris);
+               mesh->num_vertices = BigLong(dpmmesh->num_verts);
+
+               // to find out how many weights exist we two a two-stage load...
+               mesh->num_vertexboneweights = 0;
+               data = (void *) (pbase + BigLong(dpmmesh->ofs_verts));
+               for (j = 0;j < mesh->num_vertices;j++)
+               {
+                       int numweights = BigLong(((dpmvertex_t *)data)->numbones);
+                       mesh->num_vertexboneweights += numweights;
+                       data += sizeof(dpmvertex_t);
+                       data += numweights * sizeof(dpmbonevert_t);
+               }
+
+               // allocate things now that we know how many
+               mesh->data_vertexboneweights = Mem_Alloc(loadmodel->mempool, mesh->num_vertexboneweights * sizeof(surfmeshvertexboneweight_t));
+               mesh->data_element3i = Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
+               mesh->data_neighbor3i = Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
+               mesh->data_texcoordtexture2f = Mem_Alloc(loadmodel->mempool, mesh->num_vertices * sizeof(float[2]));
+
+               inelements = (void *) (pbase + BigLong(dpmmesh->ofs_indices));
+               outelements = mesh->data_element3i;
+               for (j = 0;j < mesh->num_triangles;j++)
+               {
+                       // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
+                       outelements[0] = BigLong(inelements[2]);
+                       outelements[1] = BigLong(inelements[1]);
+                       outelements[2] = BigLong(inelements[0]);
+                       inelements += 3;
+                       outelements += 3;
+               }
+
+               intexcoord = (void *) (pbase + BigLong(dpmmesh->ofs_texcoords));
+               for (j = 0;j < mesh->num_vertices*2;j++)
+                       mesh->data_texcoordtexture2f[j] = BigFloat(intexcoord[j]);
+
+               // now load them for real
+               mesh->num_vertexboneweights = 0;
+               data = (void *) (pbase + BigLong(dpmmesh->ofs_verts));
+               for (j = 0;j < mesh->num_vertices;j++)
+               {
+                       int numweights = BigLong(((dpmvertex_t *)data)->numbones);
+                       data += sizeof(dpmvertex_t);
+                       for (k = 0;k < numweights;k++)
+                       {
+                               const dpmbonevert_t *vert = (void *) data;
+                               // stuff not processed here: normal
+                               mesh->data_vertexboneweights[mesh->num_vertexboneweights].vertexindex = j;
+                               mesh->data_vertexboneweights[mesh->num_vertexboneweights].boneindex = BigLong(vert->bonenum);
+                               mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin[0] = BigFloat(vert->origin[0]);
+                               mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin[1] = BigFloat(vert->origin[1]);
+                               mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin[2] = BigFloat(vert->origin[2]);
+                               mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin[3] = BigFloat(vert->influence);
+                               mesh->num_vertexboneweights++;
+                               data += sizeof(dpmbonevert_t);
+                       }
+               }
+
+               // since dpm models do not have named sections, reuse their shader name as the section name
+               if (dpmmesh->shadername[0])
+                       Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
+               else
+                       for (j = 0;j < loadmodel->numskins;j++)
+                               Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + i + j * loadmodel->num_surfaces, NULL);
+
+               Mod_ValidateElements(mesh->data_element3i, mesh->num_triangles, mesh->num_vertices, __FILE__, __LINE__);
+               Mod_BuildTriangleNeighbors(mesh->data_neighbor3i, mesh->data_element3i, mesh->num_triangles);
+               Mod_Alias_Mesh_CompileFrameZero(mesh);
+
+               surface = loadmodel->data_surfaces + i;
+               surface->groupmesh = mesh;
+               surface->texture = loadmodel->data_textures + i;
+               surface->num_firsttriangle = 0;
+               surface->num_triangles = mesh->num_triangles;
+               surface->num_firstvertex = 0;
+               surface->num_vertices = mesh->num_vertices;
+
+               dpmmesh++;
+       }
+}
+