]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_alias.c
eliminated model->meshlist, replaced with an embedded model->surfmesh to cut down...
[xonotic/darkplaces.git] / model_alias.c
index def79235d555ae8701dca6e99b37816ce24c31ee..b5d29195f93690dcb2e199c42ea6a9f872d5248c 100644 (file)
@@ -39,9 +39,9 @@ void Mod_AliasInit (void)
        Cvar_RegisterVariable(&r_skeletal_debugtranslatez);
 }
 
-void Mod_Alias_GetMesh_Vertex3f(const model_t *model, const frameblend_t *frameblend, const surfmesh_t *mesh, float *out3f)
+void Mod_Alias_GetMesh_Vertex3f(const model_t *model, const frameblend_t *frameblend, float *out3f)
 {
-       if (mesh->num_vertexboneweights)
+       if (model->surfmesh.num_vertexboneweights)
        {
                int i, k, blends;
                surfmeshvertexboneweight_t *v;
@@ -70,9 +70,9 @@ void Mod_Alias_GetMesh_Vertex3f(const model_t *model, const frameblend_t *frameb
                                        bonepose[i][k] = m[k];
                }
                // blend the vertex bone weights
-               memset(out3f, 0, mesh->num_vertices * sizeof(float[3]));
-               v = mesh->data_vertexboneweights;
-               for (i = 0;i < mesh->num_vertexboneweights;i++, v++)
+               memset(out3f, 0, model->surfmesh.num_vertices * sizeof(float[3]));
+               v = model->surfmesh.data_vertexboneweights;
+               for (i = 0;i < model->surfmesh.num_vertexboneweights;i++, v++)
                {
                        out = out3f + v->vertexindex * 3;
                        matrix = bonepose[v->boneindex];
@@ -88,10 +88,10 @@ 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)
+               if (!model->surfmesh.data_morphvertex3f)
                        Host_Error("model %s has no skeletal or vertex morph animation data", model->name);
-               vertsbase = mesh->data_morphvertex3f;
-               vertcount = mesh->num_vertices;
+               vertsbase = model->surfmesh.data_morphvertex3f;
+               vertcount = model->surfmesh.num_vertices;
                verts1 = vertsbase + frameblend[0].frame * vertcount * 3;
                lerp1 = frameblend[0].lerp;
                if (frameblend[1].lerp)
@@ -187,87 +187,109 @@ int Mod_Alias_GetTagIndexForName(const model_t *model, unsigned int skin, const
        return 0;
 }
 
-static void Mod_Alias_Mesh_CompileFrameZero(surfmesh_t *mesh)
+static void Mod_Alias_Mesh_CompileFrameZero(void)
 {
        frameblend_t frameblend[4] = {{0, 1}, {0, 0}, {0, 0}, {0, 0}};
-       mesh->data_vertex3f = (float *)Mem_Alloc(loadmodel->mempool, mesh->num_vertices * sizeof(float[3][4]));
-       mesh->data_svector3f = mesh->data_vertex3f + mesh->num_vertices * 3;
-       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, true);
+       loadmodel->surfmesh.data_vertex3f = (float *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3][4]));
+       loadmodel->surfmesh.data_svector3f = loadmodel->surfmesh.data_vertex3f + loadmodel->surfmesh.num_vertices * 3;
+       loadmodel->surfmesh.data_tvector3f = loadmodel->surfmesh.data_vertex3f + loadmodel->surfmesh.num_vertices * 6;
+       loadmodel->surfmesh.data_normal3f = loadmodel->surfmesh.data_vertex3f + loadmodel->surfmesh.num_vertices * 9;
+       Mod_Alias_GetMesh_Vertex3f(loadmodel, frameblend, loadmodel->surfmesh.data_vertex3f);
+       Mod_BuildTextureVectorsAndNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, loadmodel->surfmesh.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)
+static void Mod_MDLMD2MD3_TraceBox(model_t *model, int frame, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask)
 {
-       int i, linetrace;
+       int i;
        float segmentmins[3], segmentmaxs[3];
        frameblend_t frameblend[4];
        msurface_t *surface;
-       surfmesh_t *mesh;
-       colbrushf_t *thisbrush_start = NULL, *thisbrush_end = NULL;
-       matrix4x4_t startmatrix, endmatrix;
+       static int maxvertices = 0;
+       static float *vertex3f = NULL;
        memset(trace, 0, sizeof(*trace));
        trace->fraction = 1;
        trace->realfraction = 1;
        trace->hitsupercontentsmask = hitsupercontentsmask;
-       segmentmins[0] = min(boxstartmins[0], boxendmins[0]);
-       segmentmins[1] = min(boxstartmins[1], boxendmins[1]);
-       segmentmins[2] = min(boxstartmins[2], boxendmins[2]);
-       segmentmaxs[0] = max(boxstartmaxs[0], boxendmaxs[0]);
-       segmentmaxs[1] = max(boxstartmaxs[1], boxendmaxs[1]);
-       segmentmaxs[2] = max(boxstartmaxs[2], boxendmaxs[2]);
-       linetrace = VectorCompare(boxstartmins, boxstartmaxs) && VectorCompare(boxendmins, boxendmaxs);
-       if (!linetrace)
-       {
-               // box trace, performed as brush trace
-               startmatrix = identitymatrix;
-               endmatrix = identitymatrix;
-               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++)
+       if (maxvertices < model->surfmesh.num_vertices)
+       {
+               if (vertex3f)
+                       Z_Free(vertex3f);
+               maxvertices = (model->surfmesh.num_vertices + 255) & ~255;
+               vertex3f = Z_Malloc(maxvertices * sizeof(float[3]));
+       }
+       if (VectorLength2(boxmins) + VectorLength2(boxmaxs) == 0)
+       {
+               // line trace
+               segmentmins[0] = min(start[0], end[0]) - 1;
+               segmentmins[1] = min(start[1], end[1]) - 1;
+               segmentmins[2] = min(start[2], end[2]) - 1;
+               segmentmaxs[0] = max(start[0], end[0]) + 1;
+               segmentmaxs[1] = max(start[1], end[1]) + 1;
+               segmentmaxs[2] = max(start[2], end[2]) + 1;
+               for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
+               {
+                       Mod_Alias_GetMesh_Vertex3f(model, frameblend, vertex3f);
+                       Collision_TraceLineTriangleMeshFloat(trace, start, end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, SUPERCONTENTS_SOLID, 0, surface->texture, segmentmins, segmentmaxs);
+               }
+       }
+       else
        {
-               mesh = surface->groupmesh;
-               Mod_Alias_GetMesh_Vertex3f(model, frameblend, mesh, varray_vertex3f);
-               if (linetrace)
-                       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, varray_vertex3f, SUPERCONTENTS_SOLID, segmentmins, segmentmaxs);
+               // box trace, performed as brush trace
+               colbrushf_t *thisbrush_start, *thisbrush_end;
+               vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
+               segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1;
+               segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1;
+               segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1;
+               segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1;
+               segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1;
+               segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1;
+               VectorAdd(start, boxmins, boxstartmins);
+               VectorAdd(start, boxmaxs, boxstartmaxs);
+               VectorAdd(end, boxmins, boxendmins);
+               VectorAdd(end, boxmaxs, boxendmaxs);
+               thisbrush_start = Collision_BrushForBox(&identitymatrix, boxstartmins, boxstartmaxs, 0, 0, NULL);
+               thisbrush_end = Collision_BrushForBox(&identitymatrix, boxendmins, boxendmaxs, 0, 0, NULL);
+               for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
+               {
+                       if (maxvertices < model->surfmesh.num_vertices)
+                       {
+                               if (vertex3f)
+                                       Z_Free(vertex3f);
+                               maxvertices = (model->surfmesh.num_vertices + 255) & ~255;
+                               vertex3f = Z_Malloc(maxvertices * sizeof(float[3]));
+                       }
+                       Mod_Alias_GetMesh_Vertex3f(model, frameblend, vertex3f);
+                       Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, SUPERCONTENTS_SOLID, 0, surface->texture, segmentmins, segmentmaxs);
+               }
        }
 }
 
 static void Mod_CalcAliasModelBBoxes (void)
 {
-       int vnum, meshnum;
+       int vnum;
        float dist, yawradius, radius;
-       surfmesh_t *mesh;
        float *v;
        VectorClear(loadmodel->normalmins);
        VectorClear(loadmodel->normalmaxs);
        yawradius = 0;
        radius = 0;
-       for (meshnum = 0;meshnum < loadmodel->num_surfaces;meshnum++)
-       {
-               mesh = loadmodel->meshlist[meshnum];
-               for (vnum = 0, v = mesh->data_morphvertex3f;vnum < mesh->num_vertices * mesh->num_morphframes;vnum++, v += 3)
-               {
-                       if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
-                       if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
-                       if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
-                       if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
-                       if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
-                       if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
-                       dist = v[0] * v[0] + v[1] * v[1];
-                       if (yawradius < dist)
-                               yawradius = dist;
-                       dist += v[2] * v[2];
-                       if (radius < dist)
-                               radius = dist;
-               }
+       for (vnum = 0, v = loadmodel->surfmesh.data_morphvertex3f;vnum < loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes;vnum++, v += 3)
+       {
+               if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
+               if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
+               if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
+               if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
+               if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
+               if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
+               dist = v[0] * v[0] + v[1] * v[1];
+               if (yawradius < dist)
+                       yawradius = dist;
+               dist += v[2] * v[2];
+               if (radius < dist)
+                       radius = dist;
        }
        radius = sqrt(radius);
        yawradius = sqrt(yawradius);
@@ -356,7 +378,7 @@ static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, vec3_t
                {
                        pinframe = (daliasframe_t *)datapointer;
                        datapointer += sizeof(daliasframe_t);
-                       Mod_ConvertAliasVerts(inverts, scale, translate, (trivertx_t *)datapointer, loadmodel->meshlist[0]->data_morphvertex3f + pose * loadmodel->meshlist[0]->num_vertices * 3, vertremap);
+                       Mod_ConvertAliasVerts(inverts, scale, translate, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphvertex3f + pose * loadmodel->surfmesh.num_vertices * 3, vertremap);
                        datapointer += sizeof(trivertx_t) * inverts;
                        pose++;
                }
@@ -476,16 +498,10 @@ void Mod_IDP0_Load(model_t *mod, void *buffer, void *bufferend)
 
        loadmodel->num_surfaces = 1;
        loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
-       loadmodel->nummeshes = loadmodel->num_surfaces;
-       data = (unsigned char *)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));
+       data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
        loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
        loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
-       loadmodel->meshlist = (surfmesh_t **)data;data += loadmodel->num_surfaces * sizeof(surfmesh_t *);
-       for (i = 0;i < loadmodel->num_surfaces;i++)
-       {
-               loadmodel->surfacelist[i] = i;
-               loadmodel->meshlist[i] = (surfmesh_t *)data;data += sizeof(surfmesh_t);
-       }
+       loadmodel->surfacelist[0] = 0;
 
        loadmodel->numskins = LittleLong(pinmodel->numskins);
        BOUNDI(loadmodel->numskins,0,65536);
@@ -495,8 +511,8 @@ void Mod_IDP0_Load(model_t *mod, void *buffer, void *bufferend)
        BOUNDI(skinheight,0,65536);
        numverts = LittleLong(pinmodel->numverts);
        BOUNDI(numverts,0,65536);
-       loadmodel->meshlist[0]->num_triangles = LittleLong(pinmodel->numtris);
-       BOUNDI(loadmodel->meshlist[0]->num_triangles,0,65536);
+       loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
+       BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
        loadmodel->numframes = LittleLong(pinmodel->numframes);
        BOUNDI(loadmodel->numframes,0,65536);
        loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
@@ -536,10 +552,10 @@ void Mod_IDP0_Load(model_t *mod, void *buffer, void *bufferend)
        datapointer += sizeof(stvert_t) * numverts;
 
        pintriangles = (dtriangle_t *)datapointer;
-       datapointer += sizeof(dtriangle_t) * loadmodel->meshlist[0]->num_triangles;
+       datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
 
        startframes = datapointer;
-       loadmodel->meshlist[0]->num_morphframes = 0;
+       loadmodel->surfmesh.num_morphframes = 0;
        for (i = 0;i < loadmodel->numframes;i++)
        {
                pinframetype = (daliasframetype_t *)datapointer;
@@ -558,7 +574,7 @@ void Mod_IDP0_Load(model_t *mod, void *buffer, void *bufferend)
                {
                        datapointer += sizeof(daliasframe_t);
                        datapointer += sizeof(trivertx_t) * numverts;
-                       loadmodel->meshlist[0]->num_morphframes++;
+                       loadmodel->surfmesh.num_morphframes++;
                }
        }
 
@@ -580,60 +596,60 @@ void Mod_IDP0_Load(model_t *mod, void *buffer, void *bufferend)
        }
 
 // load triangle data
-       loadmodel->meshlist[0]->data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->meshlist[0]->num_triangles);
+       loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
 
        // read the triangle elements
-       for (i = 0;i < loadmodel->meshlist[0]->num_triangles;i++)
+       for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
                for (j = 0;j < 3;j++)
-                       loadmodel->meshlist[0]->data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
+                       loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
        // validate (note numverts is used because this is the original data)
-       Mod_ValidateElements(loadmodel->meshlist[0]->data_element3i, loadmodel->meshlist[0]->num_triangles, numverts, __FILE__, __LINE__);
+       Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
        // now butcher the elements according to vertonseam and tri->facesfront
        // and then compact the vertex set to remove duplicates
-       for (i = 0;i < loadmodel->meshlist[0]->num_triangles;i++)
+       for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
                if (!LittleLong(pintriangles[i].facesfront)) // backface
                        for (j = 0;j < 3;j++)
-                               if (vertonseam[loadmodel->meshlist[0]->data_element3i[i*3+j]])
-                                       loadmodel->meshlist[0]->data_element3i[i*3+j] += numverts;
+                               if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
+                                       loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
        // count the usage
        // (this uses vertremap to count usage to save some memory)
        for (i = 0;i < numverts*2;i++)
                vertremap[i] = 0;
-       for (i = 0;i < loadmodel->meshlist[0]->num_triangles*3;i++)
-               vertremap[loadmodel->meshlist[0]->data_element3i[i]]++;
+       for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
+               vertremap[loadmodel->surfmesh.data_element3i[i]]++;
        // build remapping table and compact array
-       loadmodel->meshlist[0]->num_vertices = 0;
+       loadmodel->surfmesh.num_vertices = 0;
        for (i = 0;i < numverts*2;i++)
        {
                if (vertremap[i])
                {
-                       vertremap[i] = loadmodel->meshlist[0]->num_vertices;
-                       vertst[loadmodel->meshlist[0]->num_vertices*2+0] = vertst[i*2+0];
-                       vertst[loadmodel->meshlist[0]->num_vertices*2+1] = vertst[i*2+1];
-                       loadmodel->meshlist[0]->num_vertices++;
+                       vertremap[i] = loadmodel->surfmesh.num_vertices;
+                       vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
+                       vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
+                       loadmodel->surfmesh.num_vertices++;
                }
                else
                        vertremap[i] = -1; // not used at all
        }
        // remap the elements to the new vertex set
-       for (i = 0;i < loadmodel->meshlist[0]->num_triangles * 3;i++)
-               loadmodel->meshlist[0]->data_element3i[i] = vertremap[loadmodel->meshlist[0]->data_element3i[i]];
+       for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
+               loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
        // store the texture coordinates
-       loadmodel->meshlist[0]->data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->meshlist[0]->num_vertices);
-       for (i = 0;i < loadmodel->meshlist[0]->num_vertices;i++)
+       loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
+       for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
        {
-               loadmodel->meshlist[0]->data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
-               loadmodel->meshlist[0]->data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
+               loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
+               loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
        }
 
 // load the frames
        loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
-       loadmodel->meshlist[0]->data_morphvertex3f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * loadmodel->meshlist[0]->num_morphframes * loadmodel->meshlist[0]->num_vertices);
-       loadmodel->meshlist[0]->data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->meshlist[0]->num_triangles * sizeof(int[3]));
+       loadmodel->surfmesh.data_morphvertex3f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
+       loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
        Mod_MDL_LoadFrames (startframes, numverts, scale, translate, vertremap);
-       Mod_BuildTriangleNeighbors(loadmodel->meshlist[0]->data_neighbor3i, loadmodel->meshlist[0]->data_element3i, loadmodel->meshlist[0]->num_triangles);
+       Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
        Mod_CalcAliasModelBBoxes();
-       Mod_Alias_Mesh_CompileFrameZero(loadmodel->meshlist[0]);
+       Mod_Alias_Mesh_CompileFrameZero();
 
        Mem_Free(vertst);
        Mem_Free(vertremap);
@@ -737,11 +753,10 @@ void Mod_IDP0_Load(model_t *mod, void *buffer, void *bufferend)
 
        surface = loadmodel->data_surfaces;
        surface->texture = loadmodel->data_textures;
-       surface->groupmesh = loadmodel->meshlist[0];
        surface->num_firsttriangle = 0;
-       surface->num_triangles = surface->groupmesh->num_triangles;
+       surface->num_triangles = loadmodel->surfmesh.num_triangles;
        surface->num_firstvertex = 0;
-       surface->num_vertices = surface->groupmesh->num_vertices;
+       surface->num_vertices = loadmodel->surfmesh.num_vertices;
 }
 
 static void Mod_MD2_ConvertVerts (vec3_t scale, vec3_t translate, trivertx_t *v, float *out3f, int numverts, int *vertremap)
@@ -818,23 +833,17 @@ void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend)
 
        loadmodel->num_surfaces = 1;
        loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
-       loadmodel->nummeshes = loadmodel->num_surfaces;
-       data = (unsigned char *)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));
+       data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
        loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
        loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
-       loadmodel->meshlist = (surfmesh_t **)data;data += loadmodel->num_surfaces * sizeof(surfmesh_t *);
-       for (i = 0;i < loadmodel->num_surfaces;i++)
-       {
-               loadmodel->surfacelist[i] = i;
-               loadmodel->meshlist[i] = (surfmesh_t *)data;data += sizeof(surfmesh_t);
-       }
+       loadmodel->surfacelist[0] = 0;
 
        loadmodel->numskins = LittleLong(pinmodel->num_skins);
        numxyz = LittleLong(pinmodel->num_xyz);
        numst = LittleLong(pinmodel->num_st);
-       loadmodel->meshlist[0]->num_triangles = LittleLong(pinmodel->num_tris);
+       loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
        loadmodel->numframes = LittleLong(pinmodel->num_frames);
-       loadmodel->meshlist[0]->num_morphframes = loadmodel->numframes;
+       loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
        loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
 
        loadmodel->flags = 0; // there are no MD2 flags
@@ -908,11 +917,11 @@ void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend)
        }
 
        md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 256 * sizeof(hash));
-       md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->meshlist[0]->num_triangles * 3 * sizeof(*hash));
+       md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
        // swap the triangle list
        num = 0;
-       loadmodel->meshlist[0]->data_element3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->meshlist[0]->num_triangles * sizeof(int[3]));
-       for (i = 0;i < loadmodel->meshlist[0]->num_triangles;i++)
+       loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
+       for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
        {
                for (j = 0;j < 3;j++)
                {
@@ -943,22 +952,22 @@ void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend)
                                hash->next = md2verthash[hashindex];
                                md2verthash[hashindex] = hash;
                        }
-                       loadmodel->meshlist[0]->data_element3i[i*3+j] = (hash - md2verthashdata);
+                       loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
                }
        }
 
        Mem_Free(stverts);
 
        numverts = num;
-       loadmodel->meshlist[0]->num_vertices = numverts;
+       loadmodel->surfmesh.num_vertices = numverts;
        vertremap = (int *)Mem_Alloc(loadmodel->mempool, num * sizeof(int));
-       loadmodel->meshlist[0]->data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, num * sizeof(float[2]));
+       loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, num * sizeof(float[2]));
        for (i = 0;i < num;i++)
        {
                hash = md2verthashdata + i;
                vertremap[i] = hash->xyz;
-               loadmodel->meshlist[0]->data_texcoordtexture2f[i*2+0] = hash->st[0];
-               loadmodel->meshlist[0]->data_texcoordtexture2f[i*2+1] = hash->st[1];
+               loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = hash->st[0];
+               loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = hash->st[1];
        }
 
        Mem_Free(md2verthash);
@@ -966,8 +975,8 @@ void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend)
 
        // load the frames
        datapointer = (base + LittleLong(pinmodel->ofs_frames));
-       loadmodel->meshlist[0]->data_morphvertex3f = (float *)Mem_Alloc(loadmodel->mempool, numverts * loadmodel->meshlist[0]->num_morphframes * sizeof(float[3]));
-       for (i = 0;i < loadmodel->meshlist[0]->num_morphframes;i++)
+       loadmodel->surfmesh.data_morphvertex3f = (float *)Mem_Alloc(loadmodel->mempool, numverts * loadmodel->surfmesh.num_morphframes * sizeof(float[3]));
+       for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
        {
                pinframe = (md2frame_t *)datapointer;
                datapointer += sizeof(md2frame_t);
@@ -976,7 +985,7 @@ void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend)
                        scale[j] = LittleFloat(pinframe->scale[j]);
                        translate[j] = LittleFloat(pinframe->translate[j]);
                }
-               Mod_MD2_ConvertVerts(scale, translate, (trivertx_t *)datapointer, loadmodel->meshlist[0]->data_morphvertex3f + i * numverts * 3, numverts, vertremap);
+               Mod_MD2_ConvertVerts(scale, translate, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphvertex3f + i * numverts * 3, numverts, vertremap);
                datapointer += numxyz * sizeof(trivertx_t);
 
                strcpy(loadmodel->animscenes[i].name, pinframe->name);
@@ -988,26 +997,24 @@ void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend)
 
        Mem_Free(vertremap);
 
-       loadmodel->meshlist[0]->data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->meshlist[0]->num_triangles * sizeof(int[3]));
-       Mod_BuildTriangleNeighbors(loadmodel->meshlist[0]->data_neighbor3i, loadmodel->meshlist[0]->data_element3i, loadmodel->meshlist[0]->num_triangles);
+       loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
+       Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
        Mod_CalcAliasModelBBoxes();
-       Mod_Alias_Mesh_CompileFrameZero(loadmodel->meshlist[0]);
+       Mod_Alias_Mesh_CompileFrameZero();
 
        surface = loadmodel->data_surfaces;
-       surface->groupmesh = loadmodel->meshlist[0];
        surface->texture = loadmodel->data_textures;
        surface->num_firsttriangle = 0;
-       surface->num_triangles = surface->groupmesh->num_triangles;
+       surface->num_triangles = loadmodel->surfmesh.num_triangles;
        surface->num_firstvertex = 0;
-       surface->num_vertices = surface->groupmesh->num_vertices;
+       surface->num_vertices = loadmodel->surfmesh.num_vertices;
 }
 
 void Mod_IDP3_Load(model_t *mod, void *buffer, void *bufferend)
 {
-       int i, j, k, version;
+       int i, j, k, version, meshvertices, meshtriangles;
        unsigned char *data;
        msurface_t *surface;
-       surfmesh_t *mesh;
        md3modelheader_t *pinmodel;
        md3frameinfo_t *pinframe;
        md3mesh_t *pinmesh;
@@ -1080,63 +1087,72 @@ void Mod_IDP3_Load(model_t *mod, void *buffer, void *bufferend)
        }
 
        // load meshes
+       meshvertices = 0;
+       meshtriangles = 0;
+       for (i = 0, pinmesh = (md3mesh_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_meshes));i < loadmodel->num_surfaces;i++, pinmesh = (md3mesh_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_end)))
+       {
+               if (memcmp(pinmesh->identifier, "IDP3", 4))
+                       Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
+               if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
+                       Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
+               meshvertices += LittleLong(pinmesh->num_vertices);
+               meshtriangles += LittleLong(pinmesh->num_triangles);
+       }
+
        loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
-       loadmodel->nummeshes = loadmodel->num_surfaces;
        loadmodel->num_textures = loadmodel->num_surfaces;
-       data = (unsigned char *)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));
+       data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + meshtriangles * sizeof(int[3]) + meshvertices * sizeof(float[2]) + meshvertices * loadmodel->numframes * sizeof(float[3]));
        loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
        loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
-       loadmodel->meshlist = (surfmesh_t **)data;data += loadmodel->num_surfaces * sizeof(surfmesh_t *);
        loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
-       for (i = 0;i < loadmodel->num_surfaces;i++)
-       {
-               loadmodel->surfacelist[i] = i;
-               loadmodel->meshlist[i] = (surfmesh_t *)data;data += sizeof(surfmesh_t);
-       }
+       loadmodel->surfmesh.num_vertices = meshvertices;
+       loadmodel->surfmesh.num_triangles = meshtriangles;
+       loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
+       loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
+       loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
+       loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
+       loadmodel->surfmesh.data_morphvertex3f = (float *)data;data += meshvertices * loadmodel->numframes * sizeof(float[3]);
+
+       meshvertices = 0;
+       meshtriangles = 0;
        for (i = 0, pinmesh = (md3mesh_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_meshes));i < loadmodel->num_surfaces;i++, pinmesh = (md3mesh_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_end)))
        {
                if (memcmp(pinmesh->identifier, "IDP3", 4))
                        Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
-               mesh = loadmodel->meshlist[i];
-               mesh->num_morphframes = LittleLong(pinmesh->num_frames);
-               mesh->num_vertices = LittleLong(pinmesh->num_vertices);
-               mesh->num_triangles = LittleLong(pinmesh->num_triangles);
-               mesh->data_element3i = (int *)Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
-               mesh->data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
-               mesh->data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, mesh->num_vertices * sizeof(float[2]));
-               mesh->data_morphvertex3f = (float *)Mem_Alloc(loadmodel->mempool, mesh->num_vertices * mesh->num_morphframes * sizeof(float[3]));
-               for (j = 0;j < mesh->num_triangles * 3;j++)
-                       mesh->data_element3i[j] = LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
-               for (j = 0;j < mesh->num_vertices;j++)
+               loadmodel->surfacelist[i] = i;
+               surface = loadmodel->data_surfaces + i;
+               surface->texture = loadmodel->data_textures + i;
+               surface->num_firsttriangle = meshtriangles;
+               surface->num_triangles = LittleLong(pinmesh->num_triangles);
+               surface->num_firstvertex = meshvertices;
+               surface->num_vertices = LittleLong(pinmesh->num_vertices);
+               meshvertices += surface->num_vertices;
+               meshtriangles += surface->num_triangles;
+
+               for (j = 0;j < surface->num_triangles * 3;j++)
+                       loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
+               for (j = 0;j < surface->num_vertices;j++)
                {
-                       mesh->data_texcoordtexture2f[j * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
-                       mesh->data_texcoordtexture2f[j * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
+                       loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
+                       loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
                }
-               for (j = 0;j < mesh->num_vertices * mesh->num_morphframes;j++)
+               for (j = 0;j < surface->num_vertices * loadmodel->numframes;j++)
                {
-                       mesh->data_morphvertex3f[j * 3 + 0] = LittleShort(((short *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)))[j * 4 + 0]) * (1.0f / 64.0f);
-                       mesh->data_morphvertex3f[j * 3 + 1] = LittleShort(((short *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)))[j * 4 + 1]) * (1.0f / 64.0f);
-                       mesh->data_morphvertex3f[j * 3 + 2] = LittleShort(((short *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)))[j * 4 + 2]) * (1.0f / 64.0f);
+                       loadmodel->surfmesh.data_morphvertex3f[(j + surface->num_firstvertex) * 3 + 0] = LittleShort(((short *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)))[j * 4 + 0]) * (1.0f / 64.0f);
+                       loadmodel->surfmesh.data_morphvertex3f[(j + surface->num_firstvertex) * 3 + 1] = LittleShort(((short *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)))[j * 4 + 1]) * (1.0f / 64.0f);
+                       loadmodel->surfmesh.data_morphvertex3f[(j + surface->num_firstvertex) * 3 + 2] = LittleShort(((short *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)))[j * 4 + 2]) * (1.0f / 64.0f);
                }
 
-               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);
-
                if (LittleLong(pinmesh->num_shaders) >= 1)
                        Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name);
                else
                        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;
-               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;
+               Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
        }
+       Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
+       Mod_Alias_Mesh_CompileFrameZero();
        Mod_CalcAliasModelBBoxes();
        Mod_FreeSkinFiles(skinfiles);
 }
@@ -1145,7 +1161,7 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend)
 {
        zymtype1header_t *pinmodel, *pheader;
        unsigned char *pbase;
-       int i, j, k, l, numposes, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements, *remapvertices;
+       int i, j, k, l, numposes, meshvertices, meshtriangles, numvertexboneweights, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
        float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f;
        zymvertex_t *verts, *vertdata;
        zymscene_t *scene;
@@ -1154,7 +1170,6 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend)
        skinfile_t *skinfiles;
        unsigned char *data;
        msurface_t *surface;
-       surfmesh_t *mesh;
 
        pinmodel = (zymtype1header_t *)buffer;
        pbase = (unsigned char *)buffer;
@@ -1279,13 +1294,6 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend)
                scene++;
        }
 
-       //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
-       loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]);
-       loadmodel->data_poses = (float *)Mem_Alloc(loadmodel->mempool, pheader->lump_poses.length);
-       poses = (float *) (pheader->lump_poses.start + pbase);
-       for (i = 0;i < pheader->lump_poses.length / 4;i++)
-               loadmodel->data_poses[i] = BigFloat(poses[i]);
-
        //zymlump_t lump_bones; // zymbone_t bone[numbones];
        loadmodel->num_bones = pheader->numbones;
        loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, pheader->numbones * sizeof(aliasbone_t));
@@ -1309,19 +1317,53 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend)
                        Host_Error("%s bonecount[%i] < 1", loadmodel->name, i);
        }
 
+       loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]);
+
+       meshvertices = pheader->numverts;
+       meshtriangles = pheader->numtris;
+       numvertexboneweights = pheader->lump_verts.length / sizeof(zymvertex_t);
+
+       loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
+       loadmodel->num_textures = loadmodel->num_surfaces;
+       data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + meshtriangles * sizeof(int[3]) + meshvertices * sizeof(float[2]) + numvertexboneweights * sizeof(surfmeshvertexboneweight_t) + loadmodel->num_poses * sizeof(float[3][4]));
+       loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
+       loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
+       loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
+       loadmodel->surfmesh.num_vertices = meshvertices;
+       loadmodel->surfmesh.num_triangles = meshtriangles;
+       loadmodel->surfmesh.num_vertexboneweights = numvertexboneweights;
+       loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
+       loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
+       loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
+       loadmodel->surfmesh.data_vertexboneweights = (surfmeshvertexboneweight_t *)data;data += numvertexboneweights * sizeof(surfmeshvertexboneweight_t);
+       loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[3][4]);
+
+       //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
+       poses = (float *) (pheader->lump_poses.start + pbase);
+       for (i = 0;i < pheader->lump_poses.length / 4;i++)
+               loadmodel->data_poses[i] = BigFloat(poses[i]);
+
        //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
        verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
        vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
-       for (i = 0;i < pheader->lump_verts.length / (int) sizeof(zymvertex_t);i++)
+       l = 0;
+       for (j = 0;j < pheader->numverts;j++)
        {
-               verts[i].bonenum = BigLong(vertdata[i].bonenum);
-               verts[i].origin[0] = BigFloat(vertdata[i].origin[0]);
-               verts[i].origin[1] = BigFloat(vertdata[i].origin[1]);
-               verts[i].origin[2] = BigFloat(vertdata[i].origin[2]);
+               for (k = 0;k < vertbonecounts[j];k++, l++)
+               {
+                       // this format really should have had a per vertexweight weight value...
+                       float influence = 1.0f / vertbonecounts[j];
+                       loadmodel->surfmesh.data_vertexboneweights[l].vertexindex = j;
+                       loadmodel->surfmesh.data_vertexboneweights[l].boneindex = BigLong(vertdata[l].bonenum);
+                       loadmodel->surfmesh.data_vertexboneweights[l].origin[0] = BigFloat(vertdata[l].origin[0]) * influence;
+                       loadmodel->surfmesh.data_vertexboneweights[l].origin[1] = BigFloat(vertdata[l].origin[1]) * influence;
+                       loadmodel->surfmesh.data_vertexboneweights[l].origin[2] = BigFloat(vertdata[l].origin[2]) * influence;
+                       loadmodel->surfmesh.data_vertexboneweights[l].origin[3] = influence;
+               }
        }
 
        //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
-       outtexcoord2f = (float *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(float[2]));
+       outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
        intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
        for (i = 0;i < pheader->numverts;i++)
        {
@@ -1334,20 +1376,6 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend)
        //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;
-       loadmodel->num_textures = loadmodel->num_surfaces;
-       data = (unsigned char *)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 = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
-       loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
-       loadmodel->meshlist = (surfmesh_t **)data;data += loadmodel->num_surfaces * sizeof(surfmesh_t *);
-       loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
-       for (i = 0;i < loadmodel->num_surfaces;i++)
-       {
-               loadmodel->surfacelist[i] = i;
-               loadmodel->meshlist[i] = (surfmesh_t *)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)
        // byteswap, validate, and swap winding order of tris
@@ -1356,19 +1384,28 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend)
                Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
        renderlist = (int *) (pheader->lump_render.start + pbase);
        renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
+       meshtriangles = 0;
        for (i = 0;i < loadmodel->num_surfaces;i++)
        {
+               int lastvertex;
                if (renderlist >= renderlistend)
                        Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
                count = BigLong(*renderlist);renderlist++;
                if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
                        Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
-               mesh = loadmodel->meshlist[i];
-               mesh->num_triangles = count;
-               mesh->data_element3i = (int *)Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
-               mesh->data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
-               outelements = mesh->data_element3i;
-               for (j = 0;j < mesh->num_triangles;j++)
+
+               loadmodel->surfacelist[i] = i;
+               surface = loadmodel->data_surfaces + i;
+               surface->texture = loadmodel->data_textures + i;
+               surface->num_firsttriangle = meshtriangles;
+               surface->num_triangles = count;
+               surface->num_firstvertex = meshvertices;
+               surface->num_vertices = meshvertices;
+
+               // load the elements and find the used vertex range
+               lastvertex = 0;
+               outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
+               for (j = 0;j < surface->num_triangles;j++)
                {
                        outelements[2] = BigLong(renderlist[0]);
                        outelements[1] = BigLong(renderlist[1]);
@@ -1379,75 +1416,33 @@ void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend)
                                Host_Error("%s corrupt renderlist (out of bounds index)", 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", loadmodel->name);
+                       surface->num_firstvertex = min(surface->num_firstvertex, outelements[0]);
+                       surface->num_firstvertex = min(surface->num_firstvertex, outelements[1]);
+                       surface->num_firstvertex = min(surface->num_firstvertex, outelements[2]);
+                       lastvertex = max(lastvertex, outelements[0]);
+                       lastvertex = max(lastvertex, outelements[1]);
+                       lastvertex = max(lastvertex, outelements[2]);
                        renderlist += 3;
                        outelements += 3;
                }
-               remapvertices = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
-               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]];
-               mesh->data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, mesh->num_vertices * sizeof(float[2]));
-               for (j = 0;j < pheader->numverts;j++)
-               {
-                       if (remapvertices[j] >= 0)
-                       {
-                               mesh->data_texcoordtexture2f[remapvertices[j]*2+0] = outtexcoord2f[j*2+0];
-                               mesh->data_texcoordtexture2f[remapvertices[j]*2+1] = outtexcoord2f[j*2+1];
-                       }
-               }
-               mesh->num_vertexboneweights = 0;
-               for (j = 0;j < pheader->numverts;j++)
-                       if (remapvertices[j] >= 0)
-                               mesh->num_vertexboneweights += vertbonecounts[remapvertices[j]];
-               mesh->data_vertexboneweights = (surfmeshvertexboneweight_t *)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 < pheader->numverts;j++)
-               {
-                       if (remapvertices[j] < 0)
-                       {
-                               l += vertbonecounts[j];
-                               continue;
-                       }
-                       for (k = 0;k < vertbonecounts[j];k++)
-                       {
-                               // this format really should have had a per vertexweight weight value...
-                               mesh->data_vertexboneweights[mesh->num_vertexboneweights].vertexindex = remapvertices[j];
-                               mesh->data_vertexboneweights[mesh->num_vertexboneweights].boneindex = verts[l].bonenum;
-                               mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin[3] = 1.0f / vertbonecounts[j];
-                               mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin[0] = verts[l].origin[0] * mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin[3];
-                               mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin[1] = verts[l].origin[1] * mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin[3];
-                               mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin[2] = verts[l].origin[2] * mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin[3];
-                               mesh->num_vertexboneweights++;
-                               l++;
-                       }
-               }
-               shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
+               surface->num_vertices = lastvertex + 1 - surface->num_firstvertex;
+
                // 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(loadmodel->data_textures + i, skinfiles, shadername, 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;
+               Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
        }
-
+       Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
+       Mod_Alias_Mesh_CompileFrameZero();
+       Mod_FreeSkinFiles(skinfiles);
        Mem_Free(vertbonecounts);
        Mem_Free(verts);
-       Mem_Free(outtexcoord2f);
 }
 
 void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend)
@@ -1457,7 +1452,7 @@ void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend)
        dpmbone_t *bone;
        dpmmesh_t *dpmmesh;
        unsigned char *pbase;
-       int i, j, k;
+       int i, j, k, meshvertices, meshtriangles, numvertexboneweights;
        skinfile_t *skinfiles;
        unsigned char *data;
 
@@ -1526,21 +1521,51 @@ void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend)
        if (loadmodel->numskins < 1)
                loadmodel->numskins = 1;
 
+       meshvertices = 0;
+       meshtriangles = 0;
+       numvertexboneweights = 0;
+
+       // load the meshes now
+       dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
+       for (i = 0;i < loadmodel->num_surfaces;i++)
+       {
+               int numverts = BigLong(dpmmesh->num_verts);
+               meshvertices += numverts;;
+               meshtriangles += BigLong(dpmmesh->num_tris);
+
+               // to find out how many weights exist we two a two-stage load...
+               data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
+               for (j = 0;j < numverts;j++)
+               {
+                       int numweights = BigLong(((dpmvertex_t *)data)->numbones);
+                       numvertexboneweights += numweights;
+                       data += sizeof(dpmvertex_t);
+                       data += numweights * sizeof(dpmbonevert_t);
+               }
+               dpmmesh++;
+       }
+
        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;
-
+       loadmodel->num_textures = loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
        // do most allocations as one merged chunk
-       data = (unsigned char *)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));
+       data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + meshtriangles * sizeof(int[3]) + meshvertices * sizeof(float[2]) + numvertexboneweights * sizeof(surfmeshvertexboneweight_t) + loadmodel->num_poses * sizeof(float[3][4]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t));
        loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
        loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
-       loadmodel->meshlist = (surfmesh_t **)data;data += loadmodel->num_surfaces * sizeof(surfmesh_t *);
        loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
+       loadmodel->surfmesh.num_vertices = meshvertices;
+       loadmodel->surfmesh.num_triangles = meshtriangles;
+       loadmodel->surfmesh.num_vertexboneweights = numvertexboneweights;
+       loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
+       loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
+       loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
+       loadmodel->surfmesh.data_vertexboneweights = (surfmeshvertexboneweight_t *)data;data += numvertexboneweights * sizeof(surfmeshvertexboneweight_t);
+       loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[3][4]);
        loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
        loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
-       loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[12]);
        loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
+
        for (i = 0;i < loadmodel->numskins;i++)
        {
                loadmodel->skinscenes[i].firstframe = i;
@@ -1548,11 +1573,6 @@ void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend)
                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] = (surfmesh_t *)data;data += sizeof(surfmesh_t);
-       }
 
        // load the bone info
        bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
@@ -1585,55 +1605,44 @@ void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend)
 
        // load the meshes now
        dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
-       for (i = 0;i < loadmodel->num_surfaces;i++)
+       meshvertices = 0;
+       meshtriangles = 0;
+       numvertexboneweights = 0;
+       for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
        {
                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 = (unsigned char *) (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 = (surfmeshvertexboneweight_t *)Mem_Alloc(loadmodel->mempool, mesh->num_vertexboneweights * sizeof(surfmeshvertexboneweight_t));
-               mesh->data_element3i = (int *)Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
-               mesh->data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
-               mesh->data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, mesh->num_vertices * sizeof(float[2]));
+               loadmodel->surfacelist[i] = i;
+               surface = loadmodel->data_surfaces + i;
+               surface->texture = loadmodel->data_textures + i;
+               surface->num_firsttriangle = meshtriangles;
+               surface->num_triangles = BigLong(dpmmesh->num_tris);
+               surface->num_firstvertex = meshvertices;
+               surface->num_vertices = BigLong(dpmmesh->num_verts);
+               meshvertices += surface->num_vertices;
+               meshtriangles += surface->num_triangles;
 
                inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
-               outelements = mesh->data_element3i;
-               for (j = 0;j < mesh->num_triangles;j++)
+               outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
+               for (j = 0;j < surface->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]);
+                       outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
+                       outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
+                       outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
                        inelements += 3;
                        outelements += 3;
                }
 
                intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
-               for (j = 0;j < mesh->num_vertices*2;j++)
-                       mesh->data_texcoordtexture2f[j] = BigFloat(intexcoord[j]);
+               for (j = 0;j < surface->num_vertices*2;j++)
+                       loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
 
-               // now load them for real
-               mesh->num_vertexboneweights = 0;
                data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
-               for (j = 0;j < mesh->num_vertices;j++)
+               for (j = 0;j < surface->num_vertices;j++)
                {
                        int numweights = BigLong(((dpmvertex_t *)data)->numbones);
                        data += sizeof(dpmvertex_t);
@@ -1641,13 +1650,13 @@ void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend)
                        {
                                const dpmbonevert_t *vert = (dpmbonevert_t *) 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++;
+                               loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].vertexindex = j;
+                               loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].boneindex = BigLong(vert->bonenum);
+                               loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].origin[0] = BigFloat(vert->origin[0]);
+                               loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].origin[1] = BigFloat(vert->origin[1]);
+                               loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].origin[2] = BigFloat(vert->origin[2]);
+                               loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].origin[3] = BigFloat(vert->influence);
+                               numvertexboneweights++;
                                data += sizeof(dpmbonevert_t);
                        }
                }
@@ -1659,20 +1668,11 @@ void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend)
                        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++;
+               Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
        }
+       Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
+       Mod_Alias_Mesh_CompileFrameZero();
+       Mod_FreeSkinFiles(skinfiles);
 }
 
 static void Mod_PSKMODEL_AnimKeyToMatrix(float *origin, float *quat, matrix4x4_t *m)
@@ -1688,7 +1688,7 @@ static void Mod_PSKMODEL_AnimKeyToMatrix(float *origin, float *quat, matrix4x4_t
 #define PSKQUATNEGATIONS
 void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
 {
-       int i, j, index, version, recordsize, numrecords;
+       int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles, numvertexboneweights;
        int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
        fs_offset_t filesize;
        pskpnts_t *pnts;
@@ -1701,8 +1701,8 @@ void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
        pskaniminfo_t *anims;
        pskanimkeys_t *animkeys;
        void *animfilebuffer, *animbuffer, *animbufferend;
+       unsigned char *data;
        pskchunk_t *pchunk;
-       surfmesh_t *mesh;
        skinfile_t *skinfiles;
        char animname[MAX_QPATH];
 
@@ -1720,19 +1720,6 @@ void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
        loadmodel->flags = 0; // there are no flags on zym models
        loadmodel->synctype = ST_RAND;
 
-       // load external .skin files if present
-       skinfiles = Mod_LoadSkinFiles();
-       if (loadmodel->numskins < 1)
-               loadmodel->numskins = 1;
-       loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * 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;
-       }
-
        FS_StripExtension(loadmodel->name, animname, sizeof(animname));
        strlcat(animname, ".psa", sizeof(animname));
        animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
@@ -1764,10 +1751,10 @@ void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
                version = LittleLong(pchunk->version);
                recordsize = LittleLong(pchunk->recordsize);
                numrecords = LittleLong(pchunk->numrecords);
-               if (developer.integer)
+               if (developer.integer >= 100)
                        Con_Printf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
-               if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e)
-                       Con_Printf ("%s: chunk %s has unknown version %x (0x1e83b9, 0x1e9179 and 0x2e are currently supported), trying to load anyway!\n", loadmodel->name, pchunk->id, version);
+               if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
+                       Con_Printf ("%s: chunk %s has unknown version %x (0x1e83b9, 0x1e9179, 0x2e, 0x12f2bc, 0x12f2f0 are currently supported), trying to load anyway!\n", loadmodel->name, pchunk->id, version);
                if (!strcmp(pchunk->id, "ACTRHEAD"))
                {
                        // nothing to do
@@ -1934,10 +1921,10 @@ void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
                version = LittleLong(pchunk->version);
                recordsize = LittleLong(pchunk->recordsize);
                numrecords = LittleLong(pchunk->numrecords);
-               if (developer.integer)
+               if (developer.integer >= 100)
                        Con_Printf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
-               if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e)
-                       Con_Printf ("%s: chunk %s has unknown version %x (0x1e83b9, 0x1e9179 and 0x2e are currently supported), trying to load anyway!\n", animname, pchunk->id, version);
+               if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
+                       Con_Printf ("%s: chunk %s has unknown version %x (0x1e83b9, 0x1e9179, 0x2e, 0x12f2bc, 0x12f2f0 are currently supported), trying to load anyway!\n", animname, pchunk->id, version);
                if (!strcmp(pchunk->id, "ANIMHEAD"))
                {
                        // nothing to do
@@ -2078,27 +2065,48 @@ void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
        for (index = 0;index < numanims;index++)
                loadmodel->numframes += anims[index].numframes;
 
+       if (numanimkeys != numbones * loadmodel->numframes)
+               Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
+
+       meshvertices = numvtxw;
+       meshtriangles = numfaces;
+       numvertexboneweights = 0;
+       for (index = 0;index < numvtxw;index++)
+               for (j = 0;j < numrawweights;j++)
+                       if (rawweights[j].pntsindex == vtxw[index].pntsindex)
+                               numvertexboneweights++;
+
+       // load external .skin files if present
+       skinfiles = Mod_LoadSkinFiles();
+       if (loadmodel->numskins < 1)
+               loadmodel->numskins = 1;
        loadmodel->num_bones = numbones;
        loadmodel->num_poses = loadmodel->num_bones * loadmodel->numframes;
-       loadmodel->num_textures = loadmodel->nummeshes = loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
-
-       if (numanimkeys != loadmodel->num_bones * loadmodel->numframes)
-               Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
+       loadmodel->num_textures = loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
+       // do most allocations as one merged chunk
+       data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + meshtriangles * sizeof(int[3]) + meshvertices * sizeof(float[2]) + numvertexboneweights * sizeof(surfmeshvertexboneweight_t) + loadmodel->num_poses * sizeof(float[3][4]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t));
+       loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
+       loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
+       loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
+       loadmodel->surfmesh.num_vertices = meshvertices;
+       loadmodel->surfmesh.num_triangles = meshtriangles;
+       loadmodel->surfmesh.num_vertexboneweights = numvertexboneweights;
+       loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
+       loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
+       loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
+       loadmodel->surfmesh.data_vertexboneweights = (surfmeshvertexboneweight_t *)data;data += numvertexboneweights * sizeof(surfmeshvertexboneweight_t);
+       loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[3][4]);
+       loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
+       loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
+       loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
 
-       loadmodel->data_poses = (float *)Mem_Alloc(loadmodel->mempool, loadmodel->num_poses * sizeof(float[12]));
-       loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
-       loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
-       loadmodel->data_surfaces = (msurface_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t));
-       loadmodel->surfacelist = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(int));
-       loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
-
-       loadmodel->meshlist = (surfmesh_t **)Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t *));
-       mesh = loadmodel->meshlist[0] = (surfmesh_t *)Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t));
-       mesh->num_vertices = numvtxw;
-       mesh->num_triangles = numfaces;
-       mesh->data_element3i = (int *)Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
-       mesh->data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
-       mesh->data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, mesh->num_vertices * sizeof(float[2]));
+       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;
+       }
 
        // create surfaces
        for (index = 0, i = 0;index < nummatts;index++)
@@ -2110,17 +2118,16 @@ void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
                        for (j = 0;j < loadmodel->numskins;j++)
                                Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + index + j * loadmodel->num_surfaces, NULL);
                loadmodel->surfacelist[index] = index;
-               loadmodel->data_surfaces[index].groupmesh = loadmodel->meshlist[0];
                loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
                loadmodel->data_surfaces[index].num_firstvertex = 0;
-               loadmodel->data_surfaces[index].num_vertices = loadmodel->meshlist[0]->num_vertices;
+               loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
        }
 
        // copy over the texcoords
        for (index = 0;index < numvtxw;index++)
        {
-               mesh->data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
-               mesh->data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
+               loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
+               loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
        }
 
        // loading the faces is complicated because we need to sort them into surfaces by mattindex
@@ -2135,9 +2142,9 @@ void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
        for (index = 0;index < numfaces;index++)
        {
                i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
-               mesh->data_element3i[i+0] = faces[index].vtxwindex[0];
-               mesh->data_element3i[i+1] = faces[index].vtxwindex[1];
-               mesh->data_element3i[i+2] = faces[index].vtxwindex[2];
+               loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
+               loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
+               loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
        }
 
        // copy over the bones
@@ -2150,13 +2157,7 @@ void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
        }
 
        // build bone-relative vertex weights from the psk point weights
-       mesh->num_vertexboneweights = 0;
-       for (index = 0;index < numvtxw;index++)
-               for (j = 0;j < numrawweights;j++)
-                       if (rawweights[j].pntsindex == vtxw[index].pntsindex)
-                               mesh->num_vertexboneweights++;
-       mesh->data_vertexboneweights = (surfmeshvertexboneweight_t *)Mem_Alloc(loadmodel->mempool, mesh->num_vertexboneweights * sizeof(surfmeshvertexboneweight_t));
-       mesh->num_vertexboneweights = 0;
+       numvertexboneweights = 0;
        for (index = 0;index < numvtxw;index++)
        {
                for (j = 0;j < numrawweights;j++)
@@ -2164,9 +2165,9 @@ void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
                        if (rawweights[j].pntsindex == vtxw[index].pntsindex)
                        {
                                matrix4x4_t matrix, inversematrix;
-                               mesh->data_vertexboneweights[mesh->num_vertexboneweights].vertexindex = index;
-                               mesh->data_vertexboneweights[mesh->num_vertexboneweights].boneindex = rawweights[j].boneindex;
-                               mesh->data_vertexboneweights[mesh->num_vertexboneweights].weight = rawweights[j].weight;
+                               loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].vertexindex = index;
+                               loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].boneindex = rawweights[j].boneindex;
+                               loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].weight = rawweights[j].weight;
                                matrix = identitymatrix;
                                for (i = rawweights[j].boneindex;i >= 0;i = loadmodel->data_bones[i].parent)
                                {
@@ -2176,9 +2177,9 @@ void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
                                        Matrix4x4_Concat(&matrix, &tempmatrix, &childmatrix);
                                }
                                Matrix4x4_Invert_Simple(&inversematrix, &matrix);
-                               Matrix4x4_Transform(&inversematrix, pnts[rawweights[j].pntsindex].origin, mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin);
-                               VectorScale(mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin, mesh->data_vertexboneweights[mesh->num_vertexboneweights].weight, mesh->data_vertexboneweights[mesh->num_vertexboneweights].origin);
-                               mesh->num_vertexboneweights++;
+                               Matrix4x4_Transform(&inversematrix, pnts[rawweights[j].pntsindex].origin, loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].origin);
+                               VectorScale(loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].origin, loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].weight, loadmodel->surfmesh.data_vertexboneweights[numvertexboneweights].origin);
+                               numvertexboneweights++;
                        }
                }
        }
@@ -2216,9 +2217,10 @@ void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
        }
 
        // compile extra data we want
-       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);
+       Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
+       Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
+       Mod_Alias_Mesh_CompileFrameZero();
+       Mod_FreeSkinFiles(skinfiles);
 
        Mem_Free(animfilebuffer);
 }