]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_alias.c
set vid_stereobuffer cvar based on whether GL_STEREO is true after setting the mode
[xonotic/darkplaces.git] / model_alias.c
index 5407c86d5041bd2569a40b3fee2ca3ce4ae28d5a..ddcd849e63e487a838e3dcf4c836a0cbc5261567 100644 (file)
@@ -62,6 +62,104 @@ void *Mod_Skeletal_AnimateVertices_AllocBuffers(size_t nbytes)
        return Mod_Skeletal_AnimateVertices_bonepose;
 }
 
+void Mod_Skeletal_BuildTransforms(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT bonepose, float * RESTRICT boneposerelative)
+{
+       int i, blends;
+       float m[12];
+
+       if (!bonepose)
+               bonepose = (float * RESTRICT) Mod_Skeletal_AnimateVertices_AllocBuffers(sizeof(float[12]) * model->num_bones);
+               
+       if (skeleton && !skeleton->relativetransforms)
+               skeleton = NULL;
+
+       // interpolate matrices
+       if (skeleton)
+       {
+               for (i = 0;i < model->num_bones;i++)
+               {
+                       Matrix4x4_ToArray12FloatD3D(&skeleton->relativetransforms[i], m);
+                       if (model->data_bones[i].parent >= 0)
+                               R_ConcatTransforms(bonepose + model->data_bones[i].parent * 12, m, bonepose + i * 12);
+                       else
+                               memcpy(bonepose + i * 12, m, sizeof(m));
+
+                       // create a relative deformation matrix to describe displacement
+                       // from the base mesh, which is used by the actual weighting
+                       R_ConcatTransforms(bonepose + i * 12, model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12);
+               }
+       }
+       else
+       {
+               for (i = 0;i < model->num_bones;i++)
+               {
+                       // blend by transform each quaternion/translation into a dual-quaternion first, then blending
+                       const short * RESTRICT pose7s = model->data_poses7s + 7 * (frameblend[0].subframe * model->num_bones + i);
+                       float lerp = frameblend[0].lerp,
+                               tx = pose7s[0], ty = pose7s[1], tz = pose7s[2],
+                               rx = pose7s[3] * lerp,
+                               ry = pose7s[4] * lerp,
+                               rz = pose7s[5] * lerp,
+                               rw = pose7s[6] * lerp,
+                               dx = tx*rw + ty*rz - tz*ry,
+                               dy = -tx*rz + ty*rw + tz*rx,
+                               dz = tx*ry - ty*rx + tz*rw,
+                               dw = -tx*rx - ty*ry - tz*rz,
+                               scale, sx, sy, sz, sw;
+                       for (blends = 1;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
+                       {
+                               const short * RESTRICT pose7s = model->data_poses7s + 7 * (frameblend[blends].subframe * model->num_bones + i);
+                               float lerp = frameblend[blends].lerp,
+                                       tx = pose7s[0], ty = pose7s[1], tz = pose7s[2],
+                                       qx = pose7s[3], qy = pose7s[4], qz = pose7s[5], qw = pose7s[6];
+                               if(rx*qx + ry*qy + rz*qz + rw*qw < 0) lerp = -lerp;
+                               qx *= lerp;
+                               qy *= lerp;
+                               qz *= lerp;
+                               qw *= lerp;
+                               rx += qx;
+                               ry += qy;
+                               rz += qz;
+                               rw += qw;
+                               dx += tx*qw + ty*qz - tz*qy;
+                               dy += -tx*qz + ty*qw + tz*qx;
+                               dz += tx*qy - ty*qx + tz*qw;
+                               dw += -tx*qx - ty*qy - tz*qz;
+                       }
+                       // generate a matrix from the dual-quaternion, implicitly normalizing it in the process
+                       scale = 1.0f / (rx*rx + ry*ry + rz*rz + rw*rw);
+                       sx = rx * scale;
+                       sy = ry * scale;
+                       sz = rz * scale;
+                       sw = rw * scale;
+                       m[0] = sw*rw + sx*rx - sy*ry - sz*rz;
+                       m[1] = 2*(sx*ry - sw*rz);
+                       m[2] = 2*(sx*rz + sw*ry);
+                       m[3] = model->num_posescale*(dx*sw - dy*sz + dz*sy - dw*sx);
+                       m[4] = 2*(sx*ry + sw*rz);
+                       m[5] = sw*rw + sy*ry - sx*rx - sz*rz;
+                       m[6] = 2*(sy*rz - sw*rx);
+                       m[7] = model->num_posescale*(dx*sz + dy*sw - dz*sx - dw*sy);
+                       m[8] = 2*(sx*rz - sw*ry);
+                       m[9] = 2*(sy*rz + sw*rx);
+                       m[10] = sw*rw + sz*rz - sx*rx - sy*ry;
+                       m[11] = model->num_posescale*(dy*sx + dz*sw - dx*sy - dw*sz);
+                       if (i == r_skeletal_debugbone.integer)
+                               m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value;
+                       m[3] *= r_skeletal_debugtranslatex.value;
+                       m[7] *= r_skeletal_debugtranslatey.value;
+                       m[11] *= r_skeletal_debugtranslatez.value;
+                       if (model->data_bones[i].parent >= 0)
+                               R_ConcatTransforms(bonepose + model->data_bones[i].parent * 12, m, bonepose + i * 12);
+                       else
+                               memcpy(bonepose + i * 12, m, sizeof(m));
+                       // create a relative deformation matrix to describe displacement
+                       // from the base mesh, which is used by the actual weighting
+                       R_ConcatTransforms(bonepose + i * 12, model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12);
+               }
+       }
+}
+
 static void Mod_Skeletal_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
 {
 
@@ -525,26 +623,39 @@ static void Mod_BuildBaseBonePoses(void)
        Mem_Free(basebonepose);
 }
 
-static void Mod_Alias_CalculateBoundingBox(void)
+static qboolean Mod_Alias_CalculateBoundingBox(void)
 {
        int vnum;
        qboolean firstvertex = true;
        float dist, yawradius, radius;
        float *v;
+       qboolean isanimated = false;
        VectorClear(loadmodel->normalmins);
        VectorClear(loadmodel->normalmaxs);
        yawradius = 0;
        radius = 0;
        if (loadmodel->AnimateVertices)
        {
-               float *vertex3f;
+               float *vertex3f, *refvertex3f;
                frameblend_t frameblend[MAX_FRAMEBLENDS];
                memset(frameblend, 0, sizeof(frameblend));
                frameblend[0].lerp = 1;
-               vertex3f = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
+               vertex3f = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]) * 2);
+               refvertex3f = NULL;
                for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++)
                {
                        loadmodel->AnimateVertices(loadmodel, frameblend, NULL, vertex3f, NULL, NULL, NULL);
+                       if (!refvertex3f)
+                       {
+                               // make a copy of the first frame for comparing all others
+                               refvertex3f = vertex3f + loadmodel->surfmesh.num_vertices * 3;
+                               memcpy(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
+                       }
+                       else
+                       {
+                               if (!isanimated && memcmp(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3])))
+                                       isanimated = true;
+                       }
                        for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
                        {
                                if (firstvertex)
@@ -610,6 +721,7 @@ static void Mod_Alias_CalculateBoundingBox(void)
        loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
        loadmodel->radius = radius;
        loadmodel->radius2 = radius * radius;
+       return isanimated;
 }
 
 static void Mod_Alias_MorphMesh_CompileFrames(void)
@@ -927,6 +1039,7 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
        // FIXME add TraceBrush!
        loadmodel->PointSuperContents = NULL;
+       loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
 
        loadmodel->num_surfaces = 1;
        loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
@@ -1092,10 +1205,9 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
                loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
        }
        Mod_MDL_LoadFrames (startframes, numverts, vertremap);
-       loadmodel->AnimateVertices = Mod_MDL_AnimateVertices; // needed during loading, may be cleared by code later in this function
        if (loadmodel->surfmesh.data_neighbor3i)
                Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
-       Mod_Alias_CalculateBoundingBox();
+       loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
        Mod_Alias_MorphMesh_CompileFrames();
 
        Mem_Free(vertst);
@@ -1215,10 +1327,8 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
        surface->num_firstvertex = 0;
        surface->num_vertices = loadmodel->surfmesh.num_vertices;
 
-       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
        if(mod_alias_force_animated.string[0])
                loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
-       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_MDL_AnimateVertices : NULL;
 
        if (!loadmodel->surfmesh.isanimated)
        {
@@ -1286,6 +1396,7 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
        loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
        loadmodel->PointSuperContents = NULL;
+       loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
 
        if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
                Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
@@ -1476,15 +1587,12 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
 
        Mem_Free(vertremap);
 
-       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
-       if(mod_alias_force_animated.string[0])
-               loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
-       loadmodel->AnimateVertices = Mod_MDL_AnimateVertices; // needed during loading, may be cleared by code later in this function
        if (loadmodel->surfmesh.data_neighbor3i)
                Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
-       Mod_Alias_CalculateBoundingBox();
+       loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
        Mod_Alias_MorphMesh_CompileFrames();
-       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_MDL_AnimateVertices : NULL;
+       if(mod_alias_force_animated.string[0])
+               loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
 
        surface = loadmodel->data_surfaces;
        surface->texture = loadmodel->data_textures;
@@ -1554,6 +1662,7 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
        loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
        loadmodel->PointSuperContents = NULL;
+       loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
        loadmodel->synctype = ST_RAND;
        // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
        i = LittleLong (pinmodel->flags);
@@ -1678,17 +1787,14 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
        if (loadmodel->surfmesh.data_element3s)
                for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
                        loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
-       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
-       if(mod_alias_force_animated.string[0])
-               loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
-       loadmodel->AnimateVertices = Mod_MD3_AnimateVertices; // needed during loading, may be cleared by code later in this function
        if (loadmodel->surfmesh.data_neighbor3i)
                Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
        Mod_Alias_MorphMesh_CompileFrames();
-       Mod_Alias_CalculateBoundingBox();
+       loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
        Mod_FreeSkinFiles(skinfiles);
        Mod_MakeSortedSurfaces(loadmodel);
-       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_MD3_AnimateVertices : NULL;
+       if(mod_alias_force_animated.string[0])
+               loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
 
        if (!loadmodel->surfmesh.isanimated)
        {
@@ -1796,6 +1902,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
        loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
        loadmodel->PointSuperContents = NULL;
+       loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
 
        loadmodel->numframes = pheader->numscenes;
        loadmodel->num_surfaces = pheader->numshaders;
@@ -1815,6 +1922,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        }
 
        // model bbox
+       // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
        modelradius = pheader->radius;
        for (i = 0;i < 3;i++)
        {
@@ -1884,10 +1992,6 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        meshvertices = pheader->numverts;
        meshtriangles = pheader->numtris;
 
-       loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
-       if(mod_alias_force_animated.string[0])
-               loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
-       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
        loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
        loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
        loadmodel->num_texturesperskin = loadmodel->num_surfaces;
@@ -2088,6 +2192,9 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        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);
        if (loadmodel->surfmesh.data_neighbor3i)
                Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
+       loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
+       if(mod_alias_force_animated.string[0])
+               loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
 
        if (!loadmodel->surfmesh.isanimated)
        {
@@ -2179,8 +2286,10 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
        loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
        loadmodel->PointSuperContents = NULL;
+       loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
 
        // model bbox
+       // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
        for (i = 0;i < 3;i++)
        {
                loadmodel->normalmins[i] = pheader->mins[i];
@@ -2217,10 +2326,6 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
        loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
        loadmodel->num_texturesperskin = loadmodel->num_surfaces;
-       loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
-       if(mod_alias_force_animated.string[0])
-               loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
-       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
        // 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) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + meshvertices * (sizeof(float[14]) + sizeof(unsigned short) + sizeof(unsigned char[2][4])) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + 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);
@@ -2465,6 +2570,9 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        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);
        if (loadmodel->surfmesh.data_neighbor3i)
                Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
+       loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
+       if(mod_alias_force_animated.string[0])
+               loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
 
        if (!loadmodel->surfmesh.isanimated)
        {
@@ -2531,6 +2639,7 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
        loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
        loadmodel->PointSuperContents = NULL;
+       loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
        loadmodel->synctype = ST_RAND;
 
        FS_StripExtension(loadmodel->name, animname, sizeof(animname));
@@ -2884,10 +2993,6 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->num_texturesperskin = loadmodel->num_surfaces;
        loadmodel->surfmesh.num_vertices = meshvertices;
        loadmodel->surfmesh.num_triangles = meshtriangles;
-       loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
-       if(mod_alias_force_animated.string[0])
-               loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
-       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
        // 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]) + (r_enableshadowvolumes.integer ? loadmodel->surfmesh.num_triangles * sizeof(int[3]) : 0)  + 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(unsigned char[4]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned short) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + 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);
@@ -3143,7 +3248,9 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        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);
        if (loadmodel->surfmesh.data_neighbor3i)
                Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
-       Mod_Alias_CalculateBoundingBox();
+       loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
+       if(mod_alias_force_animated.string[0])
+               loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
 
        if (!loadmodel->surfmesh.isanimated)
        {
@@ -3365,6 +3472,7 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
        loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
        loadmodel->PointSuperContents = NULL;
+       loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
 
        // load external .skin files if present
        skinfiles = Mod_LoadSkinFiles();
@@ -3377,7 +3485,6 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header.num_meshes;
        loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
        loadmodel->num_texturesperskin = loadmodel->num_surfaces;
-       loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices; // updated later
 
        meshvertices = header.num_vertexes;
        meshtriangles = header.num_triangles;
@@ -3528,7 +3635,6 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
        if(mod_alias_force_animated.string[0])
                loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
-       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
 
        biggestorigin = 0;
        if (header.version == 1)