]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_alias.c
network CSQC and network entities separately (should prevent bugs when an entity...
[xonotic/darkplaces.git] / model_alias.c
index 80c894808f24d9fa843ffc31169803f4c2956ea5..c25eb73d5b25c6ea72be8660ff7fbd2e06394066 100644 (file)
@@ -28,6 +28,7 @@ cvar_t r_skeletal_debugbonevalue = {0, "r_skeletal_debugbonevalue", "100", "deve
 cvar_t r_skeletal_debugtranslatex = {0, "r_skeletal_debugtranslatex", "1", "development cvar for testing skeletal model code"};
 cvar_t r_skeletal_debugtranslatey = {0, "r_skeletal_debugtranslatey", "1", "development cvar for testing skeletal model code"};
 cvar_t r_skeletal_debugtranslatez = {0, "r_skeletal_debugtranslatez", "1", "development cvar for testing skeletal model code"};
+cvar_t mod_alias_supporttagscale = {0, "mod_alias_supporttagscale", "1", "support scaling factors in bone/tag attachment matrices as supported by MD3"};
 
 float mod_md3_sin[320];
 
@@ -40,6 +41,7 @@ void Mod_AliasInit (void)
        Cvar_RegisterVariable(&r_skeletal_debugtranslatex);
        Cvar_RegisterVariable(&r_skeletal_debugtranslatey);
        Cvar_RegisterVariable(&r_skeletal_debugtranslatez);
+       Cvar_RegisterVariable(&mod_alias_supporttagscale);
        for (i = 0;i < 320;i++)
                mod_md3_sin[i] = sin(i * M_PI * 2.0f / 256.0);
 }
@@ -50,27 +52,31 @@ void Mod_Skeletal_AnimateVertices(const dp_model_t *model, const frameblend_t *f
        // vertex weighted skeletal
        int i, k;
        int blends;
+       float desiredscale[3];
        float boneposerelative[MAX_BONES][12];
        float *matrix, m[12], bonepose[MAX_BONES][12];
-       size_t size;
-
-       size = model->num_surfaces * sizeof(msurface_t) + model->num_surfaces * sizeof(int) + model->num_surfaces * model->numskins * sizeof(texture_t) + model->surfmesh.num_triangles * sizeof(int[3]) + model->surfmesh.num_triangles * sizeof(int[3]) + model->surfmesh.num_vertices * sizeof(float[3]) + model->surfmesh.num_vertices * sizeof(float[3]) + model->surfmesh.num_vertices * sizeof(float[3]) + model->surfmesh.num_vertices * sizeof(float[3]) + model->surfmesh.num_vertices * sizeof(float[2]) + model->surfmesh.num_vertices * sizeof(int[4]) + model->surfmesh.num_vertices * sizeof(float[4]) + model->num_poses * sizeof(float[12]) + model->num_bones * sizeof(float[12]) + model->numskins * sizeof(animscene_t) + model->num_bones * sizeof(aliasbone_t) + model->numframes * sizeof(animscene_t) + ((model->surfmesh.num_vertices <= 65536) ? (model->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0);
-       if (size > ((memheader_t *)model->data_surfaces)[-1].size)
-               Con_Printf("%s:%i for %s: %i > %i\n", __FILE__, __LINE__, model->name, (int)size, (int)((memheader_t *)model->data_surfaces)[-1].size);
-       else if(size < ((memheader_t *)model->data_surfaces)[-1].size)
-               Con_DPrintf("%s:%i for %s: %i < %i\n", __FILE__, __LINE__, model->name, (int)size, (int)((memheader_t *)model->data_surfaces)[-1].size);
 
        // interpolate matrices and concatenate them to their parents
        for (i = 0;i < model->num_bones;i++)
        {
                for (k = 0;k < 12;k++)
                        m[k] = 0;
-               for (blends = 0;blends < 4 && frameblend[blends].lerp > 0;blends++)
+               VectorClear(desiredscale);
+               for (blends = 0;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
                {
-                       matrix = model->data_poses + (frameblend[blends].frame * model->num_bones + i) * 12;
+                       matrix = model->data_poses + (frameblend[blends].subframe * model->num_bones + i) * 12;
                        for (k = 0;k < 12;k++)
                                m[k] += matrix[k] * frameblend[blends].lerp;
+                       desiredscale[0] += frameblend[blends].lerp * VectorLength(matrix    );
+                       desiredscale[1] += frameblend[blends].lerp * VectorLength(matrix + 4);
+                       desiredscale[2] += frameblend[blends].lerp * VectorLength(matrix + 8);
                }
+               VectorNormalize(m    );
+               VectorNormalize(m + 4);
+               VectorNormalize(m + 8);
+               VectorScale(m    , desiredscale[0], m    );
+               VectorScale(m + 4, desiredscale[1], m + 4);
+               VectorScale(m + 8, desiredscale[2], m + 8);
                if (i == r_skeletal_debugbone.integer)
                        m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value;
                m[3] *= r_skeletal_debugtranslatex.value;
@@ -88,6 +94,7 @@ void Mod_Skeletal_AnimateVertices(const dp_model_t *model, const frameblend_t *f
        // blend the vertex bone weights
        // special case for the extremely common wf[0] == 1 because it saves 3 multiplies per array when compared to the other case (w[0] is always 1 if only one bone controls this vertex, artists only use multiple bones for certain special cases)
        // special case for the first bone because it avoids the need to memset the arrays before filling
+       if (vertex3f)
        {
                const float *v = model->surfmesh.data_vertex3f;
                const int *wi = model->surfmesh.data_vertexweightindex4i;
@@ -227,7 +234,7 @@ void Mod_MD3_AnimateVertices(const dp_model_t *model, const frameblend_t *frameb
        int i, numblends, blendnum;
        int numverts = model->surfmesh.num_vertices;
        numblends = 0;
-       for (blendnum = 0;blendnum < 4;blendnum++)
+       for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
        {
                //VectorMA(translate, model->surfmesh.num_morphmdlframetranslate, frameblend[blendnum].lerp, translate);
                if (frameblend[blendnum].lerp > 0)
@@ -236,24 +243,27 @@ void Mod_MD3_AnimateVertices(const dp_model_t *model, const frameblend_t *frameb
        // special case for the first blend because it avoids some adds and the need to memset the arrays first
        for (blendnum = 0;blendnum < numblends;blendnum++)
        {
-               const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].frame;
-               float scale = frameblend[blendnum].lerp * (1.0f / 64.0f);
-               if (blendnum == 0)
+               const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].subframe;
+               if (vertex3f)
                {
-                       for (i = 0;i < numverts;i++)
+                       float scale = frameblend[blendnum].lerp * (1.0f / 64.0f);
+                       if (blendnum == 0)
                        {
-                               vertex3f[i * 3 + 0] = verts[i].origin[0] * scale;
-                               vertex3f[i * 3 + 1] = verts[i].origin[1] * scale;
-                               vertex3f[i * 3 + 2] = verts[i].origin[2] * scale;
+                               for (i = 0;i < numverts;i++)
+                               {
+                                       vertex3f[i * 3 + 0] = verts[i].origin[0] * scale;
+                                       vertex3f[i * 3 + 1] = verts[i].origin[1] * scale;
+                                       vertex3f[i * 3 + 2] = verts[i].origin[2] * scale;
+                               }
                        }
-               }
-               else
-               {
-                       for (i = 0;i < numverts;i++)
+                       else
                        {
-                               vertex3f[i * 3 + 0] += verts[i].origin[0] * scale;
-                               vertex3f[i * 3 + 1] += verts[i].origin[1] * scale;
-                               vertex3f[i * 3 + 2] += verts[i].origin[2] * scale;
+                               for (i = 0;i < numverts;i++)
+                               {
+                                       vertex3f[i * 3 + 0] += verts[i].origin[0] * scale;
+                                       vertex3f[i * 3 + 1] += verts[i].origin[1] * scale;
+                                       vertex3f[i * 3 + 2] += verts[i].origin[2] * scale;
+                               }
                        }
                }
                // the yaw and pitch stored in md3 models are 8bit quantized angles
@@ -285,7 +295,7 @@ void Mod_MD3_AnimateVertices(const dp_model_t *model, const frameblend_t *frameb
                }
                if (svector3f)
                {
-                       const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].frame;
+                       const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
                        float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
                        if (blendnum == 0)
                        {
@@ -317,10 +327,10 @@ void Mod_MDL_AnimateVertices(const dp_model_t *model, const frameblend_t *frameb
        numblends = 0;
        // blend the frame translates to avoid redundantly doing so on each vertex
        // (a bit of a brain twister but it works)
-       for (blendnum = 0;blendnum < 4;blendnum++)
+       for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
        {
                if (model->surfmesh.data_morphmd2framesize6f)
-                       VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].frame * 6 + 3, translate);
+                       VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6 + 3, translate);
                else
                        VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.num_morphmdlframetranslate, translate);
                if (frameblend[blendnum].lerp > 0)
@@ -329,28 +339,31 @@ void Mod_MDL_AnimateVertices(const dp_model_t *model, const frameblend_t *frameb
        // special case for the first blend because it avoids some adds and the need to memset the arrays first
        for (blendnum = 0;blendnum < numblends;blendnum++)
        {
-               const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].frame;
-               float scale[3];
-               if (model->surfmesh.data_morphmd2framesize6f)
-                       VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].frame * 6, frameblend[blendnum].lerp, scale);
-               else
-                       VectorScale(model->surfmesh.num_morphmdlframescale, frameblend[blendnum].lerp, scale);
-               if (blendnum == 0)
+               const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].subframe;
+               if (vertex3f)
                {
-                       for (i = 0;i < numverts;i++)
+                       float scale[3];
+                       if (model->surfmesh.data_morphmd2framesize6f)
+                               VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6, frameblend[blendnum].lerp, scale);
+                       else
+                               VectorScale(model->surfmesh.num_morphmdlframescale, frameblend[blendnum].lerp, scale);
+                       if (blendnum == 0)
                        {
-                               vertex3f[i * 3 + 0] = translate[0] + verts[i].v[0] * scale[0];
-                               vertex3f[i * 3 + 1] = translate[1] + verts[i].v[1] * scale[1];
-                               vertex3f[i * 3 + 2] = translate[2] + verts[i].v[2] * scale[2];
+                               for (i = 0;i < numverts;i++)
+                               {
+                                       vertex3f[i * 3 + 0] = translate[0] + verts[i].v[0] * scale[0];
+                                       vertex3f[i * 3 + 1] = translate[1] + verts[i].v[1] * scale[1];
+                                       vertex3f[i * 3 + 2] = translate[2] + verts[i].v[2] * scale[2];
+                               }
                        }
-               }
-               else
-               {
-                       for (i = 0;i < numverts;i++)
+                       else
                        {
-                               vertex3f[i * 3 + 0] += verts[i].v[0] * scale[0];
-                               vertex3f[i * 3 + 1] += verts[i].v[1] * scale[1];
-                               vertex3f[i * 3 + 2] += verts[i].v[2] * scale[2];
+                               for (i = 0;i < numverts;i++)
+                               {
+                                       vertex3f[i * 3 + 0] += verts[i].v[0] * scale[0];
+                                       vertex3f[i * 3 + 1] += verts[i].v[1] * scale[1];
+                                       vertex3f[i * 3 + 2] += verts[i].v[2] * scale[2];
+                               }
                        }
                }
                // the vertex normals in mdl models are an index into a table of
@@ -379,7 +392,7 @@ void Mod_MDL_AnimateVertices(const dp_model_t *model, const frameblend_t *frameb
                }
                if (svector3f)
                {
-                       const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].frame;
+                       const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
                        float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
                        if (blendnum == 0)
                        {
@@ -430,9 +443,48 @@ int Mod_Alias_GetTagMatrix(const dp_model_t *model, int poseframe, int tagindex,
                        return 6;
                Matrix4x4_FromArray12FloatGL(outmatrix, model->data_tags[poseframe * model->num_tags + tagindex].matrixgl);
        }
+
+       if(!mod_alias_supporttagscale.integer)
+               Matrix4x4_Normalize3(outmatrix, outmatrix);
+
        return 0;
 }
 
+int Mod_Alias_GetExtendedTagInfoForIndex(const dp_model_t *model, unsigned int skin, int poseframe, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
+{
+       const float *boneframe;
+
+       if(skin >= (unsigned int)model->numskins)
+               skin = 0;
+
+       if (model->num_bones)
+       {
+               if(tagindex >= model->num_bones || tagindex < 0)
+                       return 1;
+               if (poseframe >= model->num_poses)
+                       return 2;
+
+               boneframe = model->data_poses + poseframe * model->num_bones * 12;
+               *parentindex = model->data_bones[tagindex].parent;
+               *tagname = model->data_bones[tagindex].name;
+               Matrix4x4_FromArray12FloatD3D(tag_localmatrix, boneframe + tagindex * 12);
+               return 0;
+       }
+
+       if (model->num_tags)
+       {
+               if(tagindex >= model->num_tags || tagindex < 0)
+                       return 1;
+               if (poseframe >= model->num_tagframes)
+                       return 2;
+               *tagname = model->data_tags[tagindex].name;
+               Matrix4x4_FromArray12FloatGL(tag_localmatrix, model->data_tags[poseframe * model->num_tags + tagindex].matrixgl);
+               return 0;
+       }
+
+       return 2;
+}
+
 int Mod_Alias_GetTagIndexForName(const dp_model_t *model, unsigned int skin, const char *tagname)
 {
        int i;
@@ -453,10 +505,13 @@ static void Mod_BuildBaseBonePoses(void)
 {
        int i, k;
        double scale;
-       float *basebonepose = Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(float[12]));
+       float *basebonepose;
        float *in12f = loadmodel->data_poses;
-       float *out12f = basebonepose;
+       float *out12f;
        float *outinv12f = loadmodel->data_baseboneposeinverse;
+       if (!loadmodel->num_bones)
+               return;
+       out12f = basebonepose = (float *) Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(float[12]));
        for (i = 0;i < loadmodel->num_bones;i++, in12f += 12, out12f += 12, outinv12f += 12)
        {
                if (loadmodel->data_bones[i].parent >= 0)
@@ -500,15 +555,15 @@ static void Mod_Alias_CalculateBoundingBox(void)
        float dist, yawradius, radius;
        float *v;
        float *vertex3f;
-       frameblend_t frameblend[4];
+       frameblend_t frameblend[MAX_FRAMEBLENDS];
        memset(frameblend, 0, sizeof(frameblend));
        frameblend[0].lerp = 1;
-       vertex3f = Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
+       vertex3f = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
        VectorClear(loadmodel->normalmins);
        VectorClear(loadmodel->normalmaxs);
        yawradius = 0;
        radius = 0;
-       for (frameblend[0].frame = 0;frameblend[0].frame < loadmodel->num_poses;frameblend[0].frame++)
+       for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++)
        {
                loadmodel->AnimateVertices(loadmodel, frameblend, vertex3f, NULL, NULL, NULL);
                for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
@@ -536,7 +591,8 @@ static void Mod_Alias_CalculateBoundingBox(void)
                                radius = dist;
                }
        }
-       Mem_Free(vertex3f);
+       if (vertex3f)
+               Mem_Free(vertex3f);
        radius = sqrt(radius);
        yawradius = sqrt(yawradius);
        loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius;
@@ -552,8 +608,10 @@ static void Mod_Alias_CalculateBoundingBox(void)
 static void Mod_Alias_MorphMesh_CompileFrames(void)
 {
        int i, j;
-       frameblend_t frameblend[4] = {{0, 1}, {0, 0}, {0, 0}, {0, 0}};
+       frameblend_t frameblend[MAX_FRAMEBLENDS];
        unsigned char *datapointer;
+       memset(frameblend, 0, sizeof(frameblend));
+       frameblend[0].lerp = 1;
        datapointer = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * (sizeof(float[3]) * 4 + loadmodel->surfmesh.num_morphframes * sizeof(texvecvertex_t)));
        loadmodel->surfmesh.data_vertex3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
        loadmodel->surfmesh.data_svector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
@@ -563,14 +621,14 @@ static void Mod_Alias_MorphMesh_CompileFrames(void)
        // this counts down from the last frame to the first so that the final data in surfmesh is for frame zero (which is what the renderer expects to be there)
        for (i = loadmodel->surfmesh.num_morphframes-1;i >= 0;i--)
        {
-               frameblend[0].frame = i;
+               frameblend[0].subframe = i;
                loadmodel->AnimateVertices(loadmodel, frameblend, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_normal3f, NULL, NULL);
-               Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer);
+               Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
                // encode the svector and tvector in 3 byte format for permanent storage
                for (j = 0;j < loadmodel->surfmesh.num_vertices;j++)
                {
-                       VectorScale(loadmodel->surfmesh.data_svector3f + j * 3, 127.0f, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].svec);
-                       VectorScale(loadmodel->surfmesh.data_tvector3f + j * 3, 127.0f, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].tvec);
+                       VectorScaleCast(loadmodel->surfmesh.data_svector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].svec);
+                       VectorScaleCast(loadmodel->surfmesh.data_tvector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].tvec);
                }
        }
 }
@@ -578,8 +636,9 @@ static void Mod_Alias_MorphMesh_CompileFrames(void)
 static void Mod_MDLMD2MD3_TraceBox(dp_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;
+       vec3_t shiftstart, shiftend;
        float segmentmins[3], segmentmaxs[3];
-       frameblend_t frameblend[4];
+       frameblend_t frameblend[MAX_FRAMEBLENDS];
        msurface_t *surface;
        static int maxvertices = 0;
        static float *vertex3f = NULL;
@@ -588,7 +647,7 @@ static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, int frame, trace_t *trace,
        trace->realfraction = 1;
        trace->hitsupercontentsmask = hitsupercontentsmask;
        memset(frameblend, 0, sizeof(frameblend));
-       frameblend[0].frame = frame;
+       frameblend[0].subframe = frame;
        frameblend[0].lerp = 1;
        if (maxvertices < model->surfmesh.num_vertices)
        {
@@ -597,19 +656,21 @@ static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, int frame, trace_t *trace,
                maxvertices = (model->surfmesh.num_vertices + 255) & ~255;
                vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3]));
        }
-       if (VectorLength2(boxmins) + VectorLength2(boxmaxs) == 0)
+       if (VectorCompare(boxmins, boxmaxs))
        {
                // 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;
+               VectorAdd(start, boxmins, shiftstart);
+               VectorAdd(end, boxmins, shiftend);
+               segmentmins[0] = min(shiftstart[0], shiftend[0]) - 1;
+               segmentmins[1] = min(shiftstart[1], shiftend[1]) - 1;
+               segmentmins[2] = min(shiftstart[2], shiftend[2]) - 1;
+               segmentmaxs[0] = max(shiftstart[0], shiftend[0]) + 1;
+               segmentmaxs[1] = max(shiftstart[1], shiftend[1]) + 1;
+               segmentmaxs[2] = max(shiftstart[2], shiftend[2]) + 1;
                for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
                {
                        model->AnimateVertices(model, frameblend, vertex3f, NULL, NULL, NULL);
-                       Collision_TraceLineTriangleMeshFloat(trace, start, end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, SUPERCONTENTS_SOLID, 0, surface->texture, segmentmins, segmentmaxs);
+                       Collision_TraceLineTriangleMeshFloat(trace, shiftstart, shiftend, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
                }
        }
        else
@@ -639,7 +700,7 @@ static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, int frame, trace_t *trace,
                                vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3]));
                        }
                        model->AnimateVertices(model, frameblend, vertex3f, NULL, NULL, NULL);
-                       Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, SUPERCONTENTS_SOLID, 0, surface->texture, segmentmins, segmentmaxs);
+                       Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
                }
        }
 }
@@ -750,7 +811,7 @@ static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *ski
        texture->currentmaterialflags = texture->basematerialflags;
 }
 
-static void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, char *meshname, char *shadername)
+static void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
 {
        int i;
        skinfileitem_t *skinfileitem;
@@ -774,7 +835,7 @@ static void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfi
                        {
                                // don't render unmentioned meshes
                                Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
-                               skin->basematerialflags = skin->currentmaterialflags = 0;
+                               skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW;
                        }
                }
        }
@@ -825,6 +886,7 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->Draw = R_Q1BSP_Draw;
        loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
        loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+       loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
        loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
        loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
        loadmodel->DrawLight = R_Q1BSP_DrawLight;
@@ -835,8 +897,8 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
        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->surfacelist[0] = 0;
+       loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
+       loadmodel->sortedmodelsurfaces[0] = 0;
 
        loadmodel->numskins = LittleLong(pinmodel->numskins);
        BOUNDI(loadmodel->numskins,0,65536);
@@ -1002,12 +1064,12 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
 
        // load the skins
        skinfiles = Mod_LoadSkinFiles();
-       loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
-       loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
-       loadmodel->num_texturesperskin = loadmodel->num_surfaces;
-       loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
        if (skinfiles)
        {
+               loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
+               loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
+               loadmodel->num_texturesperskin = loadmodel->num_surfaces;
+               loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
                Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
                Mod_FreeSkinFiles(skinfiles);
                for (i = 0;i < loadmodel->numskins;i++)
@@ -1020,6 +1082,10 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
        }
        else
        {
+               loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
+               loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
+               loadmodel->num_texturesperskin = loadmodel->num_surfaces;
+               loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
                totalskins = 0;
                datapointer = startskins;
                for (i = 0;i < loadmodel->numskins;i++)
@@ -1151,6 +1217,7 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->Draw = R_Q1BSP_Draw;
        loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
        loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+       loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
        loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
        loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
        loadmodel->DrawLight = R_Q1BSP_DrawLight;
@@ -1194,8 +1261,8 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
        data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->numframes * sizeof(animscene_t) + loadmodel->numframes * sizeof(float[6]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_triangles * sizeof(int[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->surfacelist[0] = 0;
+       loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
+       loadmodel->sortedmodelsurfaces[0] = 0;
        loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
        loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
        loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
@@ -1391,6 +1458,7 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->Draw = R_Q1BSP_Draw;
        loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
        loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+       loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
        loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
        loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
        loadmodel->DrawLight = R_Q1BSP_DrawLight;
@@ -1458,7 +1526,7 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->num_texturesperskin = 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 <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * sizeof(float[2]) + meshvertices * loadmodel->numframes * sizeof(md3vertex_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->sortedmodelsurfaces = (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;
@@ -1481,7 +1549,7 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
        {
                if (memcmp(pinmesh->identifier, "IDP3", 4))
                        Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
-               loadmodel->surfacelist[i] = i;
+               loadmodel->sortedmodelsurfaces[i] = i;
                surface = loadmodel->data_surfaces + i;
                surface->texture = loadmodel->data_textures + i;
                surface->num_firsttriangle = meshtriangles;
@@ -1520,6 +1588,7 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
        Mod_Alias_MorphMesh_CompileFrames();
        Mod_Alias_CalculateBoundingBox();
        Mod_FreeSkinFiles(skinfiles);
+       Mod_MakeSortedSurfaces(loadmodel);
 
        loadmodel->surfmesh.isanimated = loadmodel->numframes > 1
             || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
@@ -1603,6 +1672,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->Draw = R_Q1BSP_Draw;
        loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
        loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+       loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
        loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
        loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
        loadmodel->DrawLight = R_Q1BSP_DrawLight;
@@ -1670,7 +1740,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
 
        //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));
+       loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
        bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
        for (i = 0;i < pheader->numbones;i++)
        {
@@ -1691,7 +1761,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                        Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
        }
 
-       loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]);
+       loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
 
        meshvertices = pheader->numverts;
        meshtriangles = pheader->numtris;
@@ -1699,9 +1769,9 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
        loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
        loadmodel->num_texturesperskin = 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 <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * sizeof(float[14]) + meshvertices * sizeof(int[4]) + meshvertices * sizeof(float[4]) + loadmodel->num_poses * sizeof(float[12]) + loadmodel->num_bones * sizeof(float[12]));
+       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 <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * sizeof(float[14]) + meshvertices * sizeof(int[4]) + meshvertices * sizeof(float[4]) + loadmodel->num_poses * loadmodel->num_bones * sizeof(float[12]) + loadmodel->num_bones * sizeof(float[12]));
        loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
-       loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
+       loadmodel->sortedmodelsurfaces = (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;
@@ -1714,7 +1784,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
        loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += meshvertices * sizeof(int[4]);
        loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += meshvertices * sizeof(float[4]);
-       loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[12]);
+       loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(float[12]);
        loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
        if (loadmodel->surfmesh.num_vertices <= 65536)
        {
@@ -1798,7 +1868,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
                        Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
 
-               loadmodel->surfacelist[i] = i;
+               loadmodel->sortedmodelsurfaces[i] = i;
                surface = loadmodel->data_surfaces + i;
                surface->texture = loadmodel->data_textures + i;
                surface->num_firsttriangle = meshtriangles;
@@ -1834,6 +1904,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        Mod_FreeSkinFiles(skinfiles);
        Mem_Free(vertbonecounts);
        Mem_Free(verts);
+       Mod_MakeSortedSurfaces(loadmodel);
 
        // compute all the mesh information that was not loaded from the file
        Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
@@ -1904,6 +1975,7 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->Draw = R_Q1BSP_Draw;
        loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
        loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+       loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
        loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
        loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
        loadmodel->DrawLight = R_Q1BSP_DrawLight;
@@ -1936,21 +2008,21 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        for (i = 0;i < (int)pheader->num_meshs;i++)
        {
                int numverts = BigLong(dpmmesh->num_verts);
-               meshvertices += numverts;;
+               meshvertices += numverts;
                meshtriangles += BigLong(dpmmesh->num_tris);
                dpmmesh++;
        }
 
        loadmodel->numframes = pheader->num_frames;
        loadmodel->num_bones = pheader->num_bones;
-       loadmodel->num_poses = loadmodel->num_bones * loadmodel->numframes;
+       loadmodel->num_poses = loadmodel->numframes;
        loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
        loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
        loadmodel->num_texturesperskin = loadmodel->num_surfaces;
        // 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]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshtriangles * sizeof(int[3]) + meshvertices * (sizeof(float[14]) + sizeof(int[4]) + sizeof(float[4])) + loadmodel->num_poses * sizeof(float[12]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + 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]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshtriangles * sizeof(int[3]) + meshvertices * (sizeof(float[14]) + sizeof(int[4]) + sizeof(float[4])) + loadmodel->num_poses * loadmodel->num_bones * sizeof(float[12]) + loadmodel->num_bones * sizeof(float[12]) + 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->sortedmodelsurfaces = (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;
@@ -1963,7 +2035,7 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
        loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += meshvertices * sizeof(int[4]);
        loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += meshvertices * sizeof(float[4]);
-       loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[12]);
+       loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(float[12]);
        loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
        loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
        loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
@@ -2036,7 +2108,7 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                const float *intexcoord;
                msurface_t *surface;
 
-               loadmodel->surfacelist[i] = i;
+               loadmodel->sortedmodelsurfaces[i] = i;
                surface = loadmodel->data_surfaces + i;
                surface->texture = loadmodel->data_textures + i;
                surface->num_firsttriangle = meshtriangles;
@@ -2137,6 +2209,7 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        }
        Z_Free(bonepose);
        Mod_FreeSkinFiles(skinfiles);
+       Mod_MakeSortedSurfaces(loadmodel);
 
        // compute all the mesh information that was not loaded from the file
        Mod_BuildBaseBonePoses();
@@ -2182,6 +2255,7 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->Draw = R_Q1BSP_Draw;
        loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
        loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+       loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
        loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
        loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
        loadmodel->DrawLight = R_Q1BSP_DrawLight;
@@ -2530,17 +2604,17 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        if (loadmodel->numskins < 1)
                loadmodel->numskins = 1;
        loadmodel->num_bones = numbones;
-       loadmodel->num_poses = loadmodel->num_bones * loadmodel->numframes;
+       loadmodel->num_poses = loadmodel->numframes;
        loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
        loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
        loadmodel->num_texturesperskin = loadmodel->num_surfaces;
        loadmodel->surfmesh.num_vertices = meshvertices;
        loadmodel->surfmesh.num_triangles = meshtriangles;
        // do most allocations as one merged chunk
-       size = loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * sizeof(int[4]) + loadmodel->surfmesh.num_vertices * sizeof(float[4]) + loadmodel->num_poses * sizeof(float[12]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t) + ((loadmodel->surfmesh.num_vertices <= 65536) ? (loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0);
+       size = loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * sizeof(int[4]) + loadmodel->surfmesh.num_vertices * sizeof(float[4]) + loadmodel->num_poses * loadmodel->num_bones * sizeof(float[12]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t) + ((loadmodel->surfmesh.num_vertices <= 65536) ? (loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0);
        data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
        loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
-       loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
+       loadmodel->sortedmodelsurfaces = (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.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
        loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
@@ -2551,7 +2625,7 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
        loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += loadmodel->surfmesh.num_vertices * sizeof(int[4]);
        loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[4]);
-       loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[12]);
+       loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(float[12]);
        loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
        loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
        loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
@@ -2576,7 +2650,7 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        {
                // since psk models do not have named sections, reuse their shader name as the section name
                Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
-               loadmodel->surfacelist[index] = index;
+               loadmodel->sortedmodelsurfaces[index] = index;
                loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
                loadmodel->data_surfaces[index].num_firstvertex = 0;
                loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
@@ -2683,6 +2757,7 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        }
        Mod_FreeSkinFiles(skinfiles);
        Mem_Free(animfilebuffer);
+       Mod_MakeSortedSurfaces(loadmodel);
 
        // compute all the mesh information that was not loaded from the file
        // TODO: honor smoothing groups somehow?
@@ -2696,3 +2771,430 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
 }
 
+void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend)
+{
+#if 0
+       const char *textbase = (char *)buffer, *text = textbase;
+       char *s;
+       char *argv[512];
+       char line[1024];
+       char materialname[MAX_QPATH];
+       int j, index1, index2, index3, first, prev, index;
+       int argc;
+       int linelen;
+       int numtriangles = 0;
+       int maxtriangles = 32768;
+       int *element3i = Mem_Alloc(tempmempool, maxtriangles * sizeof(int[3]));
+       int *oldelement3i;
+       int numsurfaces = 0;
+       int maxsurfaces = 0;
+       msurface_t *surfaces = NULL;
+       int linenumber = 0;
+       int hashindex;
+       float *v, *vt, *vn;
+       float *oldv, *oldvt, *oldvn;
+       int maxv = 65536, numv = 1;
+       int maxvt = 65536, numvt = 1;
+       int maxvn = 65536, numvn = 1;
+       int maxverthash = 65536, numverthash = 0;
+       int numhashindex = 65536;
+       struct objverthash_s
+       {
+               struct objverthash_s *next;
+               int s;
+               int v;
+               int vt;
+               int vn;
+       }
+       *hash, **verthash = Mem_Alloc(tempmempool, numhashindex * sizeof(*verthash)), *verthashdata = Mem_Alloc(tempmempool, maxverthash * sizeof(*verthashdata)), *oldverthashdata;
+       skinfile_t *skinfiles;
+
+       dpsnprintf(materialname, sizeof(materialname), "%s", loadmodel->name);
+
+       skinfiles = Mod_LoadSkinFiles();
+
+       loadmodel->modeldatatypestring = "OBJ";
+
+       loadmodel->type = mod_alias;
+       loadmodel->AnimateVertices = NULL;
+       loadmodel->DrawSky = NULL;
+       loadmodel->DrawAddWaterPlanes = NULL;
+       loadmodel->Draw = R_Q1BSP_Draw;
+       loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
+       loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+       loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
+       loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
+       loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
+       loadmodel->DrawLight = R_Q1BSP_DrawLight;
+       loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
+       loadmodel->PointSuperContents = NULL;
+
+       // parse the OBJ text now
+       for(;;)
+       {
+               if (!*text)
+                       break;
+               linenumber++;
+               linelen = 0;
+               for (linelen = 0;text[linelen] && text[linelen] != '\r' && text[linelen] != '\n';linelen++)
+                       line[linelen] = text[linelen];
+               line[linelen] = 0;
+               for (argc = 0;argc < (int)(sizeof(argv)/sizeof(argv[0]));argc++)
+                       argv[argc] = "";
+               argc = 0;
+               s = line;
+               while (*s == ' ' || *s == '\t')
+                       s++;
+               while (*s)
+               {
+                       argv[argc++] = s;
+                       while (*s > ' ')
+                               s++;
+                       if (!*s)
+                               break;
+                       *s++ = 0;
+                       while (*s == ' ' || *s == '\t')
+                               s++;
+               }
+               if (!argc)
+                       continue;
+               if (argv[0][0] == '#')
+                       continue;
+               if (!strcmp(argv[0], "v"))
+               {
+                       if (maxv <= numv)
+                       {
+                               maxv *= 2;
+                               oldv = v;
+                               v = Mem_Alloc(tempmempool, maxv * sizeof(float[3]));
+                               if (oldv)
+                               {
+                                       memcpy(v, oldv, numv * sizeof(float[3]));
+                                       Mem_Free(oldv);
+                               }
+                       }
+                       v[numv*3+0] = atof(argv[1]);
+                       v[numv*3+1] = atof(argv[2]);
+                       v[numv*3+2] = atof(argv[3]);
+                       numv++;
+               }
+               else if (!strcmp(argv[0], "vt"))
+               {
+                       if (maxvt <= numvt)
+                       {
+                               maxvt *= 2;
+                               oldvt = vt;
+                               vt = Mem_Alloc(tempmempool, maxvt * sizeof(float[2]));
+                               if (oldvt)
+                               {
+                                       memcpy(vt, oldvt, numvt * sizeof(float[2]));
+                                       Mem_Free(oldvt);
+                               }
+                       }
+                       vt[numvt*2+0] = atof(argv[1]);
+                       vt[numvt*2+1] = atof(argv[2]);
+                       numvt++;
+               }
+               else if (!strcmp(argv[0], "vn"))
+               {
+                       if (maxvn <= numvn)
+                       {
+                               maxvn *= 2;
+                               oldvn = vn;
+                               vn = Mem_Alloc(tempmempool, maxvn * sizeof(float[3]));
+                               if (oldvn)
+                               {
+                                       memcpy(vn, oldvn, numvn * sizeof(float[3]));
+                                       Mem_Free(oldvn);
+                               }
+                       }
+                       vn[numvn*3+0] = atof(argv[1]);
+                       vn[numvn*3+1] = atof(argv[2]);
+                       vn[numvn*3+2] = atof(argv[3]);
+                       numvn++;
+               }
+               else if (!strcmp(argv[0], "f"))
+               {
+                       if (!surface)
+                       {
+                               if (maxsurfaces <= numsurfaces)
+                               {
+                                       maxsurfaces++;
+                                       oldsurfaces = surfaces;
+                                       surfaces = Mem_Alloc(tempmempool, maxsurfaces * sizeof(*surfaces));
+                                       if (oldsurfaces)
+                                       {
+                                               memcpy(surfaces, oldsurfaces, numsurfaces * sizeof(*surfaces));
+                                               Mem_Free(oldsurfaces);
+                                       }
+                               }
+                               surface = surfaces + numsurfaces++;
+                               surface->
+                       }
+                       for (j = 1;j < argc;j++)
+                       {
+                               index1 = atoi(argv[j]);
+                               while(argv[j][0] && argv[j][0] != '/')
+                                       argv[j]++;
+                               if (argv[j][0])
+                                       argv[j]++;
+                               if (index1 < 0)
+                                       index1 = numv + 1 - index1;
+                               index2 = atoi(argv[j]);
+                               if (index2 < 0)
+                                       index2 = numvt + 1 - index2;
+                               while(argv[j][0] && argv[j][0] != '/')
+                                       argv[j]++;
+                               if (argv[j][0])
+                                       argv[j]++;
+                               index3 = atoi(argv[j]);
+                               if (index3 < 0)
+                                       index3 = numvn + 1 - index3;
+                               hashindex = (index1 + index2 * 3571 + index3 * 42589) & (numhashindex - 1);
+                               for (hash = verthash[hashindex];hash;hash = hash->next)
+                                       if (hash->surface == numsurfaces-1 && hash->v == index1 && hash->vt == index2 && hash->vn == index3)
+                                               break;
+                               if (!hash)
+                               {
+                                       if (maxverthash <= numverthash)
+                                       {
+                                               maxverthash *= 2;
+                                               oldverthashdata = verthashdata;
+                                               verthashdata = Mem_Alloc(tempmempool, maxverthash * sizeof(*verthashdata));
+                                               if (oldverthashdata)
+                                               {
+                                                       memcpy(verthashdata, oldverthashdata, numverthash * sizeof(*verthashdata));
+                                                       Mem_Free(oldverthashdata);
+                                               }
+                                       }
+                                       hash = verthashdata + numverthash++;
+                                       hash->next = verthash[hashindex];
+                                       hash->s = numsurfaces;
+                                       hash->v = index1;
+                                       hash->vt = index2;
+                                       hash->vn = index3;
+                                       verthash[hashindex] = hash;
+                               }
+                               index = (int)((size_t)(hash - verthashdata));
+                               if (j == 1)
+                                       first = index;
+                               else if (j >= 3)
+                               {
+                                       if (maxtriangles <= numtriangles)
+                                       {
+                                               maxtriangles *= 2;
+                                               oldelement3i = element3i;
+                                               element3i = Mem_Alloc(tempmempool, numtriangles * sizeof(int[3]));
+                                               if (oldelement3i)
+                                               {
+                                                       memcpy(element3i, oldelement3i, numtriangles * sizeof(int[3]));
+                                                       Mem_Free(oldelement3i);
+                                               }
+                                       }
+                                       element3i[numtriangles*3+0] = first;
+                                       element3i[numtriangles*3+1] = prev;
+                                       element3i[numtriangles*3+2] = index;
+                                       numtriangles++;
+                               }
+                               prev = index;
+                       }
+               }
+               else if (!strcmp(argv[0], "o") || !strcmp(argv[0], "g"))
+                       surface = NULL;
+               else if (!!strcmp(argv[0], "usemtl"))
+               {
+                       surface = NULL;
+                       strlcpy(materialname, argv[1], sizeof(materialname);
+               }
+               text += linelen;
+               if (*text == '\r')
+                       text++;
+               if (*text == '\n')
+                       text++;
+       }
+
+       if (skinfiles)
+               Mod_FreeSkinFiles(skinfiles);
+
+       // now that we have the OBJ data loaded as-is, we can convert it
+       loadmodel->numskins = LittleLong(pinmodel->num_skins);
+       numxyz = LittleLong(pinmodel->num_xyz);
+       numst = LittleLong(pinmodel->num_st);
+       loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
+       loadmodel->numframes = LittleLong(pinmodel->num_frames);
+       loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
+       loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
+       skinwidth = LittleLong(pinmodel->skinwidth);
+       skinheight = LittleLong(pinmodel->skinheight);
+       iskinwidth = 1.0f / skinwidth;
+       iskinheight = 1.0f / skinheight;
+
+       loadmodel->num_surfaces = 1;
+       loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
+       data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->numframes * sizeof(animscene_t) + loadmodel->numframes * sizeof(float[6]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]));
+       loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
+       loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
+       loadmodel->sortedmodelsurfaces[0] = 0;
+       loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
+       loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
+       loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
+       loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
+
+       loadmodel->synctype = ST_RAND;
+
+       // load the skins
+       inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
+       skinfiles = Mod_LoadSkinFiles();
+       if (skinfiles)
+       {
+               loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
+               loadmodel->num_texturesperskin = loadmodel->num_surfaces;
+               loadmodel->data_textures = (texture_t *)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->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
+               loadmodel->num_texturesperskin = loadmodel->num_surfaces;
+               loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
+               for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
+                       Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP | TEXF_COMPRESS);
+       }
+       else
+       {
+               // no skins (most likely a player model)
+               loadmodel->numskins = 1;
+               loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
+               loadmodel->num_texturesperskin = loadmodel->num_surfaces;
+               loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
+               Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL);
+       }
+
+       loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
+       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;
+       }
+
+       // load the triangles and stvert data
+       inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
+       intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
+       md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
+       md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
+       // swap the triangle list
+       loadmodel->surfmesh.num_vertices = 0;
+       for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
+       {
+               for (j = 0;j < 3;j++)
+               {
+                       xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
+                       st = (unsigned short) LittleShort (intri[i].index_st[j]);
+                       if (xyz >= numxyz)
+                       {
+                               Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
+                               xyz = 0;
+                       }
+                       if (st >= numst)
+                       {
+                               Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
+                               st = 0;
+                       }
+                       hashindex = (xyz * 256 + st) & 65535;
+                       for (hash = md2verthash[hashindex];hash;hash = hash->next)
+                               if (hash->xyz == xyz && hash->st == st)
+                                       break;
+                       if (hash == NULL)
+                       {
+                               hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
+                               hash->xyz = xyz;
+                               hash->st = st;
+                               hash->next = md2verthash[hashindex];
+                               md2verthash[hashindex] = hash;
+                       }
+                       loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
+               }
+       }
+
+       vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
+       data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t));
+       loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
+       loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
+       for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
+       {
+               int sts, stt;
+               hash = md2verthashdata + i;
+               vertremap[i] = hash->xyz;
+               sts = LittleShort(inst[hash->st*2+0]);
+               stt = LittleShort(inst[hash->st*2+1]);
+               if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
+               {
+                       Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
+                       sts = 0;
+                       stt = 0;
+               }
+               loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
+               loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
+       }
+
+       Mem_Free(md2verthash);
+       Mem_Free(md2verthashdata);
+
+       // generate ushort elements array if possible
+       if (loadmodel->surfmesh.num_vertices <= 65536)
+       {
+               loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
+               for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
+                       loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
+       }
+
+       // load the frames
+       datapointer = (base + LittleLong(pinmodel->ofs_frames));
+       for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
+       {
+               int k;
+               trivertx_t *v;
+               trivertx_t *out;
+               pinframe = (md2frame_t *)datapointer;
+               datapointer += sizeof(md2frame_t);
+               // store the frame scale/translate into the appropriate array
+               for (j = 0;j < 3;j++)
+               {
+                       loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
+                       loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
+               }
+               // convert the vertices
+               v = (trivertx_t *)datapointer;
+               out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
+               for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
+                       out[k] = v[vertremap[k]];
+               datapointer += numxyz * sizeof(trivertx_t);
+
+               strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
+               loadmodel->animscenes[i].firstframe = i;
+               loadmodel->animscenes[i].framecount = 1;
+               loadmodel->animscenes[i].framerate = 10;
+               loadmodel->animscenes[i].loop = true;
+       }
+
+       Mem_Free(vertremap);
+
+       Mod_MakeSortedSurfaces(loadmodel);
+       Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
+       Mod_Alias_CalculateBoundingBox();
+       Mod_Alias_MorphMesh_CompileFrames();
+
+       surface = loadmodel->data_surfaces;
+       surface->texture = loadmodel->data_textures;
+       surface->num_firsttriangle = 0;
+       surface->num_triangles = loadmodel->surfmesh.num_triangles;
+       surface->num_firstvertex = 0;
+       surface->num_vertices = loadmodel->surfmesh.num_vertices;
+
+       loadmodel->surfmesh.isanimated = false;
+#endif
+}