]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_alias.c
Overhauled quake3 shader loading such that it now produces shader passes that could...
[xonotic/darkplaces.git] / model_alias.c
index 5407c86d5041bd2569a40b3fee2ca3ce4ae28d5a..68f19b8db914fadc0cbe76128bb7c1131a2d44f6 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 firstpose7s = model->data_poses7s + 7 * (frameblend[0].subframe * model->num_bones + i);
+                       float firstlerp = frameblend[0].lerp,
+                               firsttx = firstpose7s[0], firstty = firstpose7s[1], firsttz = firstpose7s[2],
+                               rx = firstpose7s[3] * firstlerp,
+                               ry = firstpose7s[4] * firstlerp,
+                               rz = firstpose7s[5] * firstlerp,
+                               rw = firstpose7s[6] * firstlerp,
+                               dx = firsttx*rw + firstty*rz - firsttz*ry,
+                               dy = -firsttx*rz + firstty*rw + firsttz*rx,
+                               dz = firsttx*ry - firstty*rx + firsttz*rw,
+                               dw = -firsttx*rx - firstty*ry - firsttz*rz,
+                               scale, sx, sy, sz, sw;
+                       for (blends = 1;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
+                       {
+                               const short * RESTRICT blendpose7s = model->data_poses7s + 7 * (frameblend[blends].subframe * model->num_bones + i);
+                               float blendlerp = frameblend[blends].lerp,
+                                       blendtx = blendpose7s[0], blendty = blendpose7s[1], blendtz = blendpose7s[2],
+                                       qx = blendpose7s[3], qy = blendpose7s[4], qz = blendpose7s[5], qw = blendpose7s[6];
+                               if(rx*qx + ry*qy + rz*qz + rw*qw < 0) blendlerp = -blendlerp;
+                               qx *= blendlerp;
+                               qy *= blendlerp;
+                               qz *= blendlerp;
+                               qw *= blendlerp;
+                               rx += qx;
+                               ry += qy;
+                               rz += qz;
+                               rw += qw;
+                               dx += blendtx*qw + blendty*qz - blendtz*qy;
+                               dy += -blendtx*qz + blendty*qw + blendtz*qx;
+                               dz += blendtx*qy - blendty*qx + blendtz*qw;
+                               dw += -blendtx*qx - blendty*qy - blendtz*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)
@@ -649,7 +761,6 @@ static void Mod_MDLMD2MD3_TraceLine(dp_model_t *model, const frameblend_t *frame
        float *vertex3f = vertex3fbuf;
        memset(trace, 0, sizeof(*trace));
        trace->fraction = 1;
-       trace->realfraction = 1;
        trace->hitsupercontentsmask = hitsupercontentsmask;
        if (model->surfmesh.num_vertices > 1024)
                vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
@@ -689,7 +800,6 @@ static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, const frameblend_t *frameb
        // box trace, performed as brush trace
        memset(trace, 0, sizeof(*trace));
        trace->fraction = 1;
-       trace->realfraction = 1;
        trace->hitsupercontentsmask = hitsupercontentsmask;
        if (model->surfmesh.num_vertices > 1024)
                vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
@@ -799,9 +909,7 @@ static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *ski
        memset(texture, 0, sizeof(*texture));
        texture->currentframe = texture;
        //texture->animated = false;
-       texture->numskinframes = 1;
-       texture->skinframerate = 1;
-       texture->skinframes[0] = skinframe;
+       texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(skinframe);
        texture->currentskinframe = skinframe;
        //texture->backgroundnumskinframes = 0;
        //texture->customblendfunc[0] = 0;
@@ -812,6 +920,7 @@ static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *ski
        //texture->textureflags = 0;
 
        texture->basematerialflags = MATERIALFLAG_WALL;
+       texture->basealpha = 1.0f;
        if (texture->currentskinframe->hasalpha)
                texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
        texture->currentmaterialflags = texture->basematerialflags;
@@ -927,6 +1036,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 +1202,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 +1324,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 +1393,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 +1584,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 +1659,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 +1784,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 +1899,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 +1919,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 +1989,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 +2189,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 +2283,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 +2323,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 +2567,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 +2636,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 +2990,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 +3245,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 +3469,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 +3482,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 +3632,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)