]> de.git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
redesigned skeletal model animation bone pose format - instead of
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sat, 9 Jan 2010 08:41:34 +0000 (08:41 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sat, 9 Jan 2010 08:41:34 +0000 (08:41 +0000)
float[12] matrix data it is now short[6] origin+quat data with
appropriate scale factors detected at load to preserve full range of
motion, this does however lose the ability to scale bones in a model...
this reduces memory usage significantly in some games

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@9815 d7cf8633-e32d-0410-b094-e92efae38249

clvm_cmds.c
mathlib.h
matrixlib.c
matrixlib.h
model_alias.c
model_shared.c
model_shared.h
prvm_cmds.c
svvm_cmds.c

index c8140474379c4a4d603df21008d7fa9a75dd2c6c..393531ea7069628c5f1d11ea568e35d9d1543cec 100644 (file)
@@ -3697,7 +3697,7 @@ static void VM_CL_skel_build(void)
                Matrix4x4_Accumulate(&blendedmatrix, &skeleton->relativetransforms[bonenum], retainfrac);
                for (blendindex = 0;blendindex < numblends;blendindex++)
                {
                Matrix4x4_Accumulate(&blendedmatrix, &skeleton->relativetransforms[bonenum], retainfrac);
                for (blendindex = 0;blendindex < numblends;blendindex++)
                {
-                       Matrix4x4_FromArray12FloatD3D(&matrix, model->data_poses + 12 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
+                       Matrix4x4_FromBonePose6s(&matrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
                        Matrix4x4_Accumulate(&blendedmatrix, &matrix, frameblend[blendindex].lerp);
                }
                skeleton->relativetransforms[bonenum] = blendedmatrix;
                        Matrix4x4_Accumulate(&blendedmatrix, &matrix, frameblend[blendindex].lerp);
                }
                skeleton->relativetransforms[bonenum] = blendedmatrix;
index 85bf7b62a816469df1c9444874c7c096aea4c6ce..52c711138a5d40a92d91ae6ebd4f5f3fd4d77a0a 100644 (file)
--- a/mathlib.h
+++ b/mathlib.h
@@ -83,6 +83,7 @@ unsigned int CeilPowerOf2(unsigned int value);
 #define Vector2Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1])
 #define Vector2Negate(a,b) ((b)[0]=-((a)[0]),(b)[1]=-((a)[1]))
 #define Vector2Set(a,b,c,d,e) ((a)[0]=(b),(a)[1]=(c))
 #define Vector2Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1])
 #define Vector2Negate(a,b) ((b)[0]=-((a)[0]),(b)[1]=-((a)[1]))
 #define Vector2Set(a,b,c,d,e) ((a)[0]=(b),(a)[1]=(c))
+#define Vector2Normalize2(v,dest) {float ilength = (float) sqrt(DotProduct2((v),(v)));if (ilength) ilength = 1.0f / ilength;dest[0] = (v)[0] * ilength;dest[1] = (v)[1] * ilength;}
 
 #define DotProduct4(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2]+(a)[3]*(b)[3])
 #define Vector4Clear(a) ((a)[0]=(a)[1]=(a)[2]=(a)[3]=0)
 
 #define DotProduct4(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2]+(a)[3]*(b)[3])
 #define Vector4Clear(a) ((a)[0]=(a)[1]=(a)[2]=(a)[3]=0)
@@ -90,6 +91,7 @@ unsigned int CeilPowerOf2(unsigned int value);
 #define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3])
 #define Vector4Negate(a,b) ((b)[0]=-((a)[0]),(b)[1]=-((a)[1]),(b)[2]=-((a)[2]),(b)[3]=-((a)[3]))
 #define Vector4Set(a,b,c,d,e) ((a)[0]=(b),(a)[1]=(c),(a)[2]=(d),(a)[3]=(e))
 #define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3])
 #define Vector4Negate(a,b) ((b)[0]=-((a)[0]),(b)[1]=-((a)[1]),(b)[2]=-((a)[2]),(b)[3]=-((a)[3]))
 #define Vector4Set(a,b,c,d,e) ((a)[0]=(b),(a)[1]=(c),(a)[2]=(d),(a)[3]=(e))
+#define Vector4Normalize2(v,dest) {float ilength = (float) sqrt(DotProduct4((v),(v)));if (ilength) ilength = 1.0f / ilength;dest[0] = (v)[0] * ilength;dest[1] = (v)[1] * ilength;dest[2] = (v)[2] * ilength;dest[3] = (v)[3] * ilength;}
 
 #define VectorNegate(a,b) ((b)[0]=-((a)[0]),(b)[1]=-((a)[1]),(b)[2]=-((a)[2]))
 #define VectorSet(a,b,c,d) ((a)[0]=(b),(a)[1]=(c),(a)[2]=(d))
 
 #define VectorNegate(a,b) ((b)[0]=-((a)[0]),(b)[1]=-((a)[1]),(b)[2]=-((a)[2]))
 #define VectorSet(a,b,c,d) ((a)[0]=(b),(a)[1]=(c),(a)[2]=(d))
index cfc4627a5b1e544cf01e32417af00179866130fd..89c131144dd7e9e71df20dbdbca81b1ad0c20696 100644 (file)
@@ -1427,12 +1427,35 @@ void Matrix4x4_FromOriginQuat(matrix4x4_t *m, double ox, double oy, double oz, d
 #endif
 }
 
 #endif
 }
 
+// see http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
+void Matrix4x4_ToOrigin3Quat4Float(const matrix4x4_t *m, float *origin, float *quat)
+{
+       float s;
+       quat[3] = sqrt(1.0f + m->m[0][0] + m->m[1][1] + m->m[2][2]) * 0.5f;
+       s = 0.25f / quat[3];
+#ifdef MATRIX4x4_OPENGLORIENTATION
+       origin[0] = m->m[3][0];
+       origin[1] = m->m[3][1];
+       origin[2] = m->m[3][2];
+       quat[0] = (m->m[1][2] - m->m[2][1]) * s;
+       quat[1] = (m->m[2][0] - m->m[0][2]) * s;
+       quat[2] = (m->m[0][1] - m->m[1][0]) * s;
+#else
+       origin[0] = m->m[0][3];
+       origin[1] = m->m[1][3];
+       origin[2] = m->m[2][3];
+       quat[0] = (m->m[2][1] - m->m[1][2]) * s;
+       quat[1] = (m->m[0][2] - m->m[2][0]) * s;
+       quat[2] = (m->m[1][0] - m->m[0][1]) * s;
+#endif
+}
+
 // LordHavoc: I got this code from:
 //http://www.doom3world.org/phpbb2/viewtopic.php?t=2884
 void Matrix4x4_FromDoom3Joint(matrix4x4_t *m, double ox, double oy, double oz, double x, double y, double z)
 {
 // LordHavoc: I got this code from:
 //http://www.doom3world.org/phpbb2/viewtopic.php?t=2884
 void Matrix4x4_FromDoom3Joint(matrix4x4_t *m, double ox, double oy, double oz, double x, double y, double z)
 {
-       double w = 1.0 - (x*x+y*y+z*z);
-       w = w > 0.0 ? -sqrt(w) : 0.0;
+       double w = 1.0f - (x*x+y*y+z*z);
+       w = w > 0.0f ? -sqrt(w) : 0.0f;
 #ifdef MATRIX4x4_OPENGLORIENTATION
        m->m[0][0]=1-2*(y*y+z*z);m->m[1][0]=  2*(x*y-z*w);m->m[2][0]=  2*(x*z+y*w);m->m[3][0]=ox;
        m->m[0][1]=  2*(x*y+z*w);m->m[1][1]=1-2*(x*x+z*z);m->m[2][1]=  2*(y*z-x*w);m->m[3][1]=oy;
 #ifdef MATRIX4x4_OPENGLORIENTATION
        m->m[0][0]=1-2*(y*y+z*z);m->m[1][0]=  2*(x*y-z*w);m->m[2][0]=  2*(x*z+y*w);m->m[3][0]=ox;
        m->m[0][1]=  2*(x*y+z*w);m->m[1][1]=1-2*(x*x+z*z);m->m[2][1]=  2*(y*z-x*w);m->m[3][1]=oy;
@@ -1446,6 +1469,47 @@ void Matrix4x4_FromDoom3Joint(matrix4x4_t *m, double ox, double oy, double oz, d
 #endif
 }
 
 #endif
 }
 
+void Matrix4x4_FromBonePose6s(matrix4x4_t *m, float originscale, const short *pose6s)
+{
+       float origin[3];
+       float quat[4];
+       origin[0] = pose6s[0] * originscale;
+       origin[1] = pose6s[1] * originscale;
+       origin[2] = pose6s[2] * originscale;
+       quat[0] = pose6s[3] * (1.0f / 32767.0f);
+       quat[1] = pose6s[4] * (1.0f / 32767.0f);
+       quat[2] = pose6s[5] * (1.0f / 32767.0f);
+       quat[3] = 1.0f - (quat[0]*quat[0]+quat[1]*quat[1]+quat[2]*quat[2]);
+       quat[3] = quat[3] > 0.0f ? -sqrt(quat[3]) : 0.0f;
+       Matrix4x4_FromOriginQuat(m, origin[0], origin[1], origin[2], quat[0], quat[1], quat[2], quat[3]);
+}
+
+void Matrix4x4_ToBonePose6s(const matrix4x4_t *m, float origininvscale, short *pose6s)
+{
+       float origin[3];
+       float quat[4];
+       float s;
+       Matrix4x4_ToOrigin3Quat4Float(m, origin, quat);
+       // normalize quaternion so that it is unit length
+       s = quat[0]*quat[0]+quat[1]*quat[1]+quat[2]*quat[2]+quat[3]*quat[3];
+       if (s)
+       {
+               s = 1.0f / sqrt(s);
+               quat[0] *= s;
+               quat[1] *= s;
+               quat[2] *= s;
+               quat[3] *= s;
+       }
+       // use a negative scale on the quat because the above function produces a
+       // positive quat[3] and canonical quaternions have negative quat[3]
+       pose6s[0] = origin[0] * origininvscale;
+       pose6s[1] = origin[1] * origininvscale;
+       pose6s[2] = origin[2] * origininvscale;
+       pose6s[3] = quat[0] * -32767.0f;
+       pose6s[4] = quat[1] * -32767.0f;
+       pose6s[5] = quat[2] * -32767.0f;
+}
+
 void Matrix4x4_Blend (matrix4x4_t *out, const matrix4x4_t *in1, const matrix4x4_t *in2, double blend)
 {
        double iblend = 1 - blend;
 void Matrix4x4_Blend (matrix4x4_t *out, const matrix4x4_t *in1, const matrix4x4_t *in2, double blend)
 {
        double iblend = 1 - blend;
index 7673c5b35097e668da7e83b6f573a7503f81af5c..ae83c1d68901cab73bf8642990b7ebb8bde2f7cf 100644 (file)
@@ -115,9 +115,16 @@ void Matrix4x4_FromArray12FloatD3D(matrix4x4_t *out, const float in[12]);
 
 // creates a matrix4x4 from an origin and quaternion (used mostly with skeletal model formats such as PSK)
 void Matrix4x4_FromOriginQuat(matrix4x4_t *m, double ox, double oy, double oz, double x, double y, double z, double w);
 
 // creates a matrix4x4 from an origin and quaternion (used mostly with skeletal model formats such as PSK)
 void Matrix4x4_FromOriginQuat(matrix4x4_t *m, double ox, double oy, double oz, double x, double y, double z, double w);
+// creates an origin and quaternion from a matrix4x4_t, quat[3] is always positive
+void Matrix4x4_ToOrigin3Quat4Float(const matrix4x4_t *m, float *origin, float *quat);
 // creates a matrix4x4 from an origin and canonical unit-length quaternion (used mostly with skeletal model formats such as MD5)
 void Matrix4x4_FromDoom3Joint(matrix4x4_t *m, double ox, double oy, double oz, double x, double y, double z);
 
 // creates a matrix4x4 from an origin and canonical unit-length quaternion (used mostly with skeletal model formats such as MD5)
 void Matrix4x4_FromDoom3Joint(matrix4x4_t *m, double ox, double oy, double oz, double x, double y, double z);
 
+// creates a matrix4x4_t from an origin and canonical unit-length quaternion in short[6] normalized format
+void Matrix4x4_FromBonePose6s(matrix4x4_t *m, float originscale, const short *pose6s);
+// creates a short[6] representation from normalized matrix4x4_t
+void Matrix4x4_ToBonePose6s(const matrix4x4_t *m, float origininvscale, short *pose6s);
+
 // blends two matrices together, at a given percentage (blend controls percentage of in2)
 void Matrix4x4_Blend (matrix4x4_t *out, const matrix4x4_t *in1, const matrix4x4_t *in2, double blend);
 
 // blends two matrices together, at a given percentage (blend controls percentage of in2)
 void Matrix4x4_Blend (matrix4x4_t *out, const matrix4x4_t *in1, const matrix4x4_t *in2, double blend);
 
index 18cfc562d88e2587d6179bc45ae32b32586b189c..74d63c742956e9ce1a29e9bdae8bfdaaa9cbb67e 100644 (file)
@@ -52,9 +52,8 @@ void Mod_Skeletal_AnimateVertices(const dp_model_t *model, const frameblend_t *f
        // vertex weighted skeletal
        int i, k;
        int blends;
        // vertex weighted skeletal
        int i, k;
        int blends;
-       float desiredscale[3];
        float boneposerelative[MAX_BONES][12];
        float boneposerelative[MAX_BONES][12];
-       float *matrix, m[12], bonepose[MAX_BONES][12];
+       float matrix[12], m[12], bonepose[MAX_BONES][12];
 
        if (skeleton && !skeleton->relativetransforms)
                skeleton = NULL;
 
        if (skeleton && !skeleton->relativetransforms)
                skeleton = NULL;
@@ -78,26 +77,39 @@ void Mod_Skeletal_AnimateVertices(const dp_model_t *model, const frameblend_t *f
        }
        else
        {
        }
        else
        {
+               float originscale = model->num_posescale;
+               float x,y,z,w;
+               const short *pose6s;
                for (i = 0;i < model->num_bones;i++)
                {
                        for (k = 0;k < 12;k++)
                                m[k] = 0;
                for (i = 0;i < model->num_bones;i++)
                {
                        for (k = 0;k < 12;k++)
                                m[k] = 0;
-                       VectorClear(desiredscale);
                        for (blends = 0;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
                        {
                        for (blends = 0;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
                        {
-                               matrix = model->data_poses + (frameblend[blends].subframe * model->num_bones + i) * 12;
+                               pose6s = model->data_poses6s + 6 * (frameblend[blends].subframe * model->num_bones + i);
+                               x = pose6s[3] * (1.0f / 32767.0f);
+                               y = pose6s[4] * (1.0f / 32767.0f);
+                               z = pose6s[5] * (1.0f / 32767.0f);
+                               w = 1.0f - (x*x+y*y+z*z);
+                               w = w > 0.0f ? -sqrt(w) : 0.0f;
+                               matrix[ 0]=1-2*(y*y+z*z);
+                               matrix[ 1]=  2*(x*y-z*w);
+                               matrix[ 2]=  2*(x*z+y*w);
+                               matrix[ 3]=pose6s[0] * originscale;
+                               matrix[ 4]=  2*(x*y+z*w);
+                               matrix[ 5]=1-2*(x*x+z*z);
+                               matrix[ 6]=  2*(y*z-x*w);
+                               matrix[ 7]=pose6s[1] * originscale;
+                               matrix[ 8]=  2*(x*z-y*w);
+                               matrix[ 9]=  2*(y*z+x*w);
+                               matrix[10]=1-2*(x*x+y*y);
+                               matrix[11]=pose6s[2] * originscale;
                                for (k = 0;k < 12;k++)
                                        m[k] += matrix[k] * frameblend[blends].lerp;
                                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);
                        }
                        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;
                        if (i == r_skeletal_debugbone.integer)
                                m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value;
                        m[3] *= r_skeletal_debugtranslatex.value;
@@ -440,13 +452,16 @@ void Mod_MDL_AnimateVertices(const dp_model_t *model, const frameblend_t *frameb
 int Mod_Alias_GetTagMatrix(const dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, matrix4x4_t *outmatrix)
 {
        matrix4x4_t temp;
 int Mod_Alias_GetTagMatrix(const dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, matrix4x4_t *outmatrix)
 {
        matrix4x4_t temp;
-       const float *boneframe;
-       const float *input;
+       matrix4x4_t parentbonematrix;
+       matrix4x4_t tempbonematrix;
+       matrix4x4_t bonematrix;
+       matrix4x4_t blendmatrix;
        int blendindex;
        int parenttagindex;
        int k;
        float lerp;
        int blendindex;
        int parenttagindex;
        int k;
        float lerp;
-       float tempbonematrix[12], bonematrix[12], blendmatrix[12];
+       const float *input;
+       float blendtag[12];
        *outmatrix = identitymatrix;
        if (skeleton && skeleton->relativetransforms)
        {
        *outmatrix = identitymatrix;
        if (skeleton && skeleton->relativetransforms)
        {
@@ -463,42 +478,36 @@ int Mod_Alias_GetTagMatrix(const dp_model_t *model, const frameblend_t *frameble
        {
                if (tagindex < 0 || tagindex >= model->num_bones)
                        return 4;
        {
                if (tagindex < 0 || tagindex >= model->num_bones)
                        return 4;
-               for (k = 0;k < 12;k++)
-                       blendmatrix[k] = 0;
+               Matrix4x4_Clear(&blendmatrix);
                for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
                {
                        lerp = frameblend[blendindex].lerp;
                for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
                {
                        lerp = frameblend[blendindex].lerp;
-                       boneframe = model->data_poses + frameblend[blendindex].subframe * model->num_bones * 12;
-                       input = boneframe + tagindex * 12;
-                       for (k = 0;k < 12;k++)
-                               bonematrix[k] = input[k];
+                       Matrix4x4_FromBonePose6s(&bonematrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + tagindex));
                        parenttagindex = tagindex;
                        while ((parenttagindex = model->data_bones[parenttagindex].parent) >= 0)
                        {
                        parenttagindex = tagindex;
                        while ((parenttagindex = model->data_bones[parenttagindex].parent) >= 0)
                        {
-                               for (k = 0;k < 12;k++)
-                                       tempbonematrix[k] = bonematrix[k];
-                               input = boneframe + parenttagindex * 12;
-                               R_ConcatTransforms(input, tempbonematrix, bonematrix);
+                               Matrix4x4_FromBonePose6s(&parentbonematrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + parenttagindex));
+                               tempbonematrix = bonematrix;
+                               Matrix4x4_Concat(&bonematrix, &parentbonematrix, &tempbonematrix);
                        }
                        }
-                       for (k = 0;k < 12;k++)
-                               blendmatrix[k] += bonematrix[k] * lerp;
+                       Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
                }
                }
-               Matrix4x4_FromArray12FloatD3D(outmatrix, blendmatrix);
+               *outmatrix = blendmatrix;
        }
        else if (model->num_tags)
        {
                if (tagindex < 0 || tagindex >= model->num_tags)
                        return 4;
                for (k = 0;k < 12;k++)
        }
        else if (model->num_tags)
        {
                if (tagindex < 0 || tagindex >= model->num_tags)
                        return 4;
                for (k = 0;k < 12;k++)
-                       blendmatrix[k] = 0;
+                       blendtag[k] = 0;
                for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
                {
                        lerp = frameblend[blendindex].lerp;
                        input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
                        for (k = 0;k < 12;k++)
                for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
                {
                        lerp = frameblend[blendindex].lerp;
                        input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
                        for (k = 0;k < 12;k++)
-                               blendmatrix[k] += input[k] * lerp;
+                               blendtag[k] += input[k] * lerp;
                }
                }
-               Matrix4x4_FromArray12FloatGL(outmatrix, blendmatrix);
+               Matrix4x4_FromArray12FloatGL(outmatrix, blendtag);
        }
 
        if(!mod_alias_supporttagscale.integer)
        }
 
        if(!mod_alias_supporttagscale.integer)
@@ -509,12 +518,13 @@ int Mod_Alias_GetTagMatrix(const dp_model_t *model, const frameblend_t *frameble
 
 int Mod_Alias_GetExtendedTagInfoForIndex(const dp_model_t *model, unsigned int skin, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
 {
 
 int Mod_Alias_GetExtendedTagInfoForIndex(const dp_model_t *model, unsigned int skin, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
 {
-       const float *boneframe;
-       const float *input;
        int blendindex;
        int k;
        float lerp;
        int blendindex;
        int k;
        float lerp;
-       float blendmatrix[12];
+       matrix4x4_t bonematrix;
+       matrix4x4_t blendmatrix;
+       const float *input;
+       float blendtag[12];
 
        if (skeleton && skeleton->relativetransforms)
        {
 
        if (skeleton && skeleton->relativetransforms)
        {
@@ -527,37 +537,36 @@ int Mod_Alias_GetExtendedTagInfoForIndex(const dp_model_t *model, unsigned int s
        }
        else if (model->num_bones)
        {
        }
        else if (model->num_bones)
        {
-               if(tagindex >= model->num_bones || tagindex < 0)
+               if (tagindex < 0 || tagindex >= model->num_bones)
                        return 1;
                *parentindex = model->data_bones[tagindex].parent;
                *tagname = model->data_bones[tagindex].name;
                        return 1;
                *parentindex = model->data_bones[tagindex].parent;
                *tagname = model->data_bones[tagindex].name;
-               memset(blendmatrix, 0, sizeof(blendmatrix));
+               Matrix4x4_Clear(&blendmatrix);
                for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
                {
                        lerp = frameblend[blendindex].lerp;
                for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
                {
                        lerp = frameblend[blendindex].lerp;
-                       boneframe = model->data_poses + frameblend[blendindex].subframe * model->num_bones * 12;
-                       input = boneframe + tagindex * 12;
-                       for (k = 0;k < 12;k++)
-                               blendmatrix[k] += input[k] * lerp;
+                       Matrix4x4_FromBonePose6s(&bonematrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + tagindex));
+                       Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
                }
                }
-               Matrix4x4_FromArray12FloatD3D(tag_localmatrix, blendmatrix);
+               *tag_localmatrix = blendmatrix;
                return 0;
        }
        else if (model->num_tags)
        {
                return 0;
        }
        else if (model->num_tags)
        {
-               if(tagindex >= model->num_tags || tagindex < 0)
+               if (tagindex < 0 || tagindex >= model->num_tags)
                        return 1;
                *parentindex = -1;
                *tagname = model->data_tags[tagindex].name;
                        return 1;
                *parentindex = -1;
                *tagname = model->data_tags[tagindex].name;
-               memset(blendmatrix, 0, sizeof(blendmatrix));
+               for (k = 0;k < 12;k++)
+                       blendtag[k] = 0;
                for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
                {
                        lerp = frameblend[blendindex].lerp;
                        input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
                        for (k = 0;k < 12;k++)
                for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
                {
                        lerp = frameblend[blendindex].lerp;
                        input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
                        for (k = 0;k < 12;k++)
-                               blendmatrix[k] += input[k] * lerp;
+                               blendtag[k] += input[k] * lerp;
                }
                }
-               Matrix4x4_FromArray12FloatGL(tag_localmatrix, blendmatrix);
+               Matrix4x4_FromArray12FloatGL(tag_localmatrix, blendtag);
                return 0;
        }
 
                return 0;
        }
 
@@ -582,47 +591,25 @@ int Mod_Alias_GetTagIndexForName(const dp_model_t *model, unsigned int skin, con
 
 static void Mod_BuildBaseBonePoses(void)
 {
 
 static void Mod_BuildBaseBonePoses(void)
 {
-       int i, k;
-       double scale;
-       float *basebonepose;
-       float *in12f = loadmodel->data_poses;
-       float *out12f;
-       float *outinv12f = loadmodel->data_baseboneposeinverse;
+       int boneindex;
+       matrix4x4_t *basebonepose;
+       float *outinvmatrix = loadmodel->data_baseboneposeinverse;
+       matrix4x4_t bonematrix;
+       matrix4x4_t tempbonematrix;
        if (!loadmodel->num_bones)
                return;
        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)
+       basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
+       for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
        {
        {
-               if (loadmodel->data_bones[i].parent >= 0)
-                       R_ConcatTransforms(basebonepose + 12 * loadmodel->data_bones[i].parent, in12f, out12f);
-               else
-                       for (k = 0;k < 12;k++)
-                               out12f[k] = in12f[k];
-
-               // invert The Matrix
-
-               // we only support uniform scaling, so assume the first row is enough
-               // (note the lack of sqrt here, because we're trying to undo the scaling,
-               // this means multiplying by the inverse scale twice - squaring it, which
-               // makes the sqrt a waste of time)
-               scale = 1.0 / (out12f[ 0] * out12f[ 0] + out12f[ 1] * out12f[ 1] + out12f[ 2] * out12f[ 2]);
-
-               // invert the rotation by transposing and multiplying by the squared
-               // recipricol of the input matrix scale as described above
-               outinv12f[ 0] = (float)(out12f[ 0] * scale);
-               outinv12f[ 1] = (float)(out12f[ 4] * scale);
-               outinv12f[ 2] = (float)(out12f[ 8] * scale);
-               outinv12f[ 4] = (float)(out12f[ 1] * scale);
-               outinv12f[ 5] = (float)(out12f[ 5] * scale);
-               outinv12f[ 6] = (float)(out12f[ 9] * scale);
-               outinv12f[ 8] = (float)(out12f[ 2] * scale);
-               outinv12f[ 9] = (float)(out12f[ 6] * scale);
-               outinv12f[10] = (float)(out12f[10] * scale);
-
-               // invert the translate
-               outinv12f[ 3] = -(out12f[ 3] * outinv12f[ 0] + out12f[ 7] * outinv12f[ 1] + out12f[11] * outinv12f[ 2]);
-               outinv12f[ 7] = -(out12f[ 3] * outinv12f[ 4] + out12f[ 7] * outinv12f[ 5] + out12f[11] * outinv12f[ 6]);
-               outinv12f[11] = -(out12f[ 3] * outinv12f[ 8] + out12f[ 7] * outinv12f[ 9] + out12f[11] * outinv12f[10]);
+               Matrix4x4_FromBonePose6s(&bonematrix, loadmodel->num_posescale, loadmodel->data_poses6s + 6 * boneindex);
+               if (loadmodel->data_bones[boneindex].parent >= 0)
+               {
+                       tempbonematrix = bonematrix;
+                       Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
+               }
+               basebonepose[boneindex] = bonematrix;
+               Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
+               Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
        }
        Mem_Free(basebonepose);
 }
        }
        Mem_Free(basebonepose);
 }
@@ -1700,7 +1687,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        zymtype1header_t *pinmodel, *pheader;
        unsigned char *pbase;
        int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
        zymtype1header_t *pinmodel, *pheader;
        unsigned char *pbase;
        int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
-       float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose;
+       float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin;
        zymvertex_t *verts, *vertdata;
        zymscene_t *scene;
        zymbone_t *bone;
        zymvertex_t *verts, *vertdata;
        zymscene_t *scene;
        zymbone_t *bone;
@@ -1873,7 +1860,7 @@ 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;
        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 * loadmodel->num_bones * 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(short[6]) + loadmodel->num_bones * sizeof(float[12]));
        loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
        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->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
        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);
@@ -1888,15 +1875,30 @@ 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->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 * loadmodel->num_bones * sizeof(float[12]);
        loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
        if (loadmodel->surfmesh.num_vertices <= 65536)
                loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
        loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
        if (loadmodel->surfmesh.num_vertices <= 65536)
                loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
+       loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
 
        //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
        poses = (float *) (pheader->lump_poses.start + pbase);
 
        //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
        poses = (float *) (pheader->lump_poses.start + pbase);
-       for (i = 0;i < pheader->lump_poses.length / 4;i++)
-               loadmodel->data_poses[i] = BigFloat(poses[i]);
+       biggestorigin = 0;
+       for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
+       {
+               f = fabs(BigFloat(poses[i]));
+               biggestorigin = max(biggestorigin, f);
+       }
+       loadmodel->num_posescale = biggestorigin / 32767.0f;
+       loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
+       for (i = 0;i < loadmodel->num_bones * numposes;i++)
+       {
+               float pose[12];
+               matrix4x4_t posematrix;
+               for (j = 0;j < 12;j++)
+                       pose[j] = BigFloat(poses[i*12+j]);
+               Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
+               Matrix4x4_ToBonePose6s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses6s + 6*i);
+       }
 
        //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
        verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
 
        //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
        verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
@@ -1907,7 +1909,9 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
        for (i = 0;i < loadmodel->num_bones;i++)
        {
        bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
        for (i = 0;i < loadmodel->num_bones;i++)
        {
-               const float *m = loadmodel->data_poses + i * 12;
+               float m[12];
+               for (k = 0;k < 12;k++)
+                       m[k] = BigFloat(poses[i*12+k]);
                if (loadmodel->data_bones[i].parent >= 0)
                        R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
                else
                if (loadmodel->data_bones[i].parent >= 0)
                        R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
                else
@@ -2022,7 +2026,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
 {
        dpmheader_t *pheader;
 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
 {
        dpmheader_t *pheader;
-       dpmframe_t *frame;
+       dpmframe_t *frames;
        dpmbone_t *bone;
        dpmmesh_t *dpmmesh;
        unsigned char *pbase;
        dpmbone_t *bone;
        dpmmesh_t *dpmmesh;
        unsigned char *pbase;
@@ -2030,6 +2034,9 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        skinfile_t *skinfiles;
        unsigned char *data;
        float *bonepose;
        skinfile_t *skinfiles;
        unsigned char *data;
        float *bonepose;
+       float biggestorigin;
+       float f;
+       float *poses;
 
        pheader = (dpmheader_t *)buffer;
        pbase = (unsigned char *)buffer;
 
        pheader = (dpmheader_t *)buffer;
        pbase = (unsigned char *)buffer;
@@ -2126,7 +2133,7 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
        loadmodel->num_texturesperskin = loadmodel->num_surfaces;
        // do most allocations as one merged chunk
        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 * 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));
+       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(short[6]) + 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->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->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
        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);
@@ -2141,13 +2148,13 @@ 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->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 * 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);
        loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
        if (meshvertices <= 65536)
                loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
        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);
        loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
        if (meshvertices <= 65536)
                loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
+       loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
 
        for (i = 0;i < loadmodel->numskins;i++)
        {
 
        for (i = 0;i < loadmodel->numskins;i++)
        {
@@ -2169,21 +2176,39 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        }
 
        // load the frames
        }
 
        // load the frames
-       frame = (dpmframe_t *) (pbase + pheader->ofs_frames);
+       frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
+       biggestorigin = 0;
        for (i = 0;i < loadmodel->numframes;i++)
        {
                const float *poses;
        for (i = 0;i < loadmodel->numframes;i++)
        {
                const float *poses;
-               memcpy(loadmodel->animscenes[i].name, frame->name, sizeof(frame->name));
+               memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
                loadmodel->animscenes[i].firstframe = i;
                loadmodel->animscenes[i].framecount = 1;
                loadmodel->animscenes[i].loop = true;
                loadmodel->animscenes[i].framerate = 10;
                // load the bone poses for this frame
                loadmodel->animscenes[i].firstframe = i;
                loadmodel->animscenes[i].framecount = 1;
                loadmodel->animscenes[i].loop = true;
                loadmodel->animscenes[i].framerate = 10;
                // load the bone poses for this frame
-               poses = (float *) (pbase + BigLong(frame->ofs_bonepositions));
+               poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
                for (j = 0;j < loadmodel->num_bones*12;j++)
                for (j = 0;j < loadmodel->num_bones*12;j++)
-                       loadmodel->data_poses[i * loadmodel->num_bones*12 + j] = BigFloat(poses[j]);
+               {
+                       f = fabs(BigFloat(poses[j]));
+                       biggestorigin = max(biggestorigin, f);
+               }
                // stuff not processed here: mins, maxs, yawradius, allradius
                // stuff not processed here: mins, maxs, yawradius, allradius
-               frame++;
+       }
+       loadmodel->num_posescale = biggestorigin / 32767.0f;
+       loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
+       for (i = 0;i < loadmodel->numframes;i++)
+       {
+               poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
+               for (j = 0;j < loadmodel->num_bones;j++)
+               {
+                       float pose[12];
+                       matrix4x4_t posematrix;
+                       for (k = 0;k < 12;k++)
+                               pose[k] = BigFloat(poses[j*12+k]);
+                       Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
+                       Matrix4x4_ToBonePose6s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses6s + 6*(i*loadmodel->num_bones+j));
+               }
        }
 
        // load the meshes now
        }
 
        // load the meshes now
@@ -2193,10 +2218,13 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        // reconstruct frame 0 matrices to allow reconstruction of the base mesh
        // (converting from weight-blending skeletal animation to
        //  deformation-based skeletal animation)
        // reconstruct frame 0 matrices to allow reconstruction of the base mesh
        // (converting from weight-blending skeletal animation to
        //  deformation-based skeletal animation)
+       poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
        bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
        for (i = 0;i < loadmodel->num_bones;i++)
        {
        bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
        for (i = 0;i < loadmodel->num_bones;i++)
        {
-               const float *m = loadmodel->data_poses + i * 12;
+               float m[12];
+               for (k = 0;k < 12;k++)
+                       m[k] = BigFloat(poses[i*12+k]);
                if (loadmodel->data_bones[i].parent >= 0)
                        R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
                else
                if (loadmodel->data_bones[i].parent >= 0)
                        R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
                else
@@ -2346,6 +2374,7 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        skinfile_t *skinfiles;
        char animname[MAX_QPATH];
        size_t size;
        skinfile_t *skinfiles;
        char animname[MAX_QPATH];
        size_t size;
+       float biggestorigin;
 
        pchunk = (pskchunk_t *)buffer;
        if (strcmp(pchunk->id, "ACTRHEAD"))
 
        pchunk = (pskchunk_t *)buffer;
        if (strcmp(pchunk->id, "ACTRHEAD"))
@@ -2719,7 +2748,7 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->surfmesh.num_vertices = meshvertices;
        loadmodel->surfmesh.num_triangles = meshtriangles;
        // do most allocations as one merged chunk
        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 * 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);
+       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(short[6]) + 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->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
        data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
        loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
        loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
@@ -2733,13 +2762,13 @@ 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->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 * 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);
        loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
        if (loadmodel->surfmesh.num_vertices <= 65536)
                loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
        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);
        loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
        if (loadmodel->surfmesh.num_vertices <= 65536)
                loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
+       loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
 
        for (i = 0;i < loadmodel->numskins;i++)
        {
 
        for (i = 0;i < loadmodel->numskins;i++)
        {
@@ -2851,13 +2880,34 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                }
        }
 
                }
        }
 
+       // calculate the scaling value for bone origins so they can be compressed to short
+       biggestorigin = 0;
+       for (index = 0;index < numanimkeys;index++)
+       {
+               pskanimkeys_t *k = animkeys + index;
+               biggestorigin = max(biggestorigin, fabs(k->origin[0]));
+               biggestorigin = max(biggestorigin, fabs(k->origin[1]));
+               biggestorigin = max(biggestorigin, fabs(k->origin[2]));
+       }
+       loadmodel->num_posescale = biggestorigin / 32767.0f;
+       loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
+
        // load the poses from the animkeys
        for (index = 0;index < numanimkeys;index++)
        {
                pskanimkeys_t *k = animkeys + index;
        // load the poses from the animkeys
        for (index = 0;index < numanimkeys;index++)
        {
                pskanimkeys_t *k = animkeys + index;
-               matrix4x4_t matrix;
-               Matrix4x4_FromOriginQuat(&matrix, k->origin[0], k->origin[1], k->origin[2], k->quat[0], k->quat[1], k->quat[2], k->quat[3]);
-               Matrix4x4_ToArray12FloatD3D(&matrix, loadmodel->data_poses + index*12);
+               float quat[4];
+               Vector4Copy(k->quat, quat);
+               if (quat[3] > 0)
+                       Vector4Negate(quat, quat);
+               Vector4Normalize2(quat, quat);
+               // compress poses to the short[6] format for longterm storage
+               loadmodel->data_poses6s[index*6+0] = k->origin[0] * loadmodel->num_poseinvscale;
+               loadmodel->data_poses6s[index*6+1] = k->origin[1] * loadmodel->num_poseinvscale;
+               loadmodel->data_poses6s[index*6+2] = k->origin[2] * loadmodel->num_poseinvscale;
+               loadmodel->data_poses6s[index*6+3] = quat[0] * 32767.0f;
+               loadmodel->data_poses6s[index*6+4] = quat[1] * 32767.0f;
+               loadmodel->data_poses6s[index*6+5] = quat[2] * 32767.0f;
        }
        Mod_FreeSkinFiles(skinfiles);
        Mem_Free(animfilebuffer);
        }
        Mod_FreeSkinFiles(skinfiles);
        Mem_Free(animfilebuffer);
index a5f23db9d443d52b3c3d17220d111bbc25e50d09..9d44b9c822093a44297dc4dc9bc8d61c95c108e0 100644 (file)
@@ -2650,7 +2650,6 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first
        int transformindex;
        int poseindex;
        int cornerindex;
        int transformindex;
        int poseindex;
        int cornerindex;
-       float modelscale;
        const int *e;
        const float *pose;
        size_t l;
        const int *e;
        const float *pose;
        size_t l;
@@ -2661,16 +2660,6 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first
        l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "version 1\nnodes\n");
        if (l > 0)
                outbufferpos += l;
        l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "version 1\nnodes\n");
        if (l > 0)
                outbufferpos += l;
-       modelscale = 1;
-       if(model->num_poses >= 0)
-               modelscale = sqrt(model->data_poses[0] * model->data_poses[0] + model->data_poses[1] * model->data_poses[1] + model->data_poses[2] * model->data_poses[2]);
-       if(fabs(modelscale - 1) > 1e-4)
-       {
-               if(firstpose == 0) // only print the when writing the reference pose
-                       Con_Printf("The model has an old-style model scale of %f\n", modelscale);
-       }
-       else
-               modelscale = 1;
        for (transformindex = 0;transformindex < model->num_bones;transformindex++)
        {
                if (outbufferpos >= outbuffermax >> 1)
        for (transformindex = 0;transformindex < model->num_bones;transformindex++)
        {
                if (outbufferpos >= outbuffermax >> 1)
@@ -2689,7 +2678,7 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first
        l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\nskeleton\n");
        if (l > 0)
                outbufferpos += l;
        l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\nskeleton\n");
        if (l > 0)
                outbufferpos += l;
-       for (poseindex = 0, pose = model->data_poses + model->num_bones * 12 * firstpose;poseindex < numposes;poseindex++)
+       for (poseindex = 0;poseindex < numposes;poseindex++)
        {
                countframes++;
                l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "time %i\n", poseindex);
        {
                countframes++;
                l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "time %i\n", poseindex);
@@ -2699,7 +2688,8 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first
                {
                        float a, b, c;
                        float angles[3];
                {
                        float a, b, c;
                        float angles[3];
-                       float mtest[3][4];
+                       float mtest[4][3];
+                       matrix4x4_t posematrix;
                        if (outbufferpos >= outbuffermax >> 1)
                        {
                                outbuffermax *= 2;
                        if (outbufferpos >= outbuffermax >> 1)
                        {
                                outbuffermax *= 2;
@@ -2711,18 +2701,8 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first
 
                        // strangely the smd angles are for a transposed matrix, so we
                        // have to generate a transposed matrix, then convert that...
 
                        // strangely the smd angles are for a transposed matrix, so we
                        // have to generate a transposed matrix, then convert that...
-                       mtest[0][0] = pose[ 0];
-                       mtest[0][1] = pose[ 4];
-                       mtest[0][2] = pose[ 8];
-                       mtest[0][3] = pose[ 3];
-                       mtest[1][0] = pose[ 1];
-                       mtest[1][1] = pose[ 5];
-                       mtest[1][2] = pose[ 9];
-                       mtest[1][3] = pose[ 7];
-                       mtest[2][0] = pose[ 2];
-                       mtest[2][1] = pose[ 6];
-                       mtest[2][2] = pose[10];
-                       mtest[2][3] = pose[11];
+                       Matrix4x4_FromBonePose6s(&posematrix, model->num_posescale, model->data_poses6s + 6*(model->num_bones * poseindex + transformindex));
+                       Matrix4x4_ToArray12FloatGL(&posematrix, mtest[0]);
                        AnglesFromVectors(angles, mtest[0], mtest[2], false);
                        if (angles[0] >= 180) angles[0] -= 360;
                        if (angles[1] >= 180) angles[1] -= 360;
                        AnglesFromVectors(angles, mtest[0], mtest[2], false);
                        if (angles[0] >= 180) angles[0] -= 360;
                        if (angles[1] >= 180) angles[1] -= 360;
@@ -2735,8 +2715,8 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first
 #if 0
 {
                        float cy, sy, cp, sp, cr, sr;
 #if 0
 {
                        float cy, sy, cp, sp, cr, sr;
-                       float test[3][4];
-                       // smd matrix construction, for comparing to non-transposed m
+                       float test[4][3];
+                       // smd matrix construction, for comparing
                        sy = sin(c);
                        cy = cos(c);
                        sp = sin(b);
                        sy = sin(c);
                        cy = cos(c);
                        sp = sin(b);
@@ -2745,20 +2725,20 @@ static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int first
                        cr = cos(a);
 
                        test[0][0] = cp*cy;
                        cr = cos(a);
 
                        test[0][0] = cp*cy;
-                       test[1][0] = cp*sy;
-                       test[2][0] = -sp;
-                       test[0][1] = sr*sp*cy+cr*-sy;
+                       test[0][1] = cp*sy;
+                       test[0][2] = -sp;
+                       test[1][0] = sr*sp*cy+cr*-sy;
                        test[1][1] = sr*sp*sy+cr*cy;
                        test[1][1] = sr*sp*sy+cr*cy;
-                       test[2][1] = sr*cp;
-                       test[0][2] = (cr*sp*cy+-sr*-sy);
-                       test[1][2] = (cr*sp*sy+-sr*cy);
+                       test[1][2] = sr*cp;
+                       test[2][0] = (cr*sp*cy+-sr*-sy);
+                       test[2][1] = (cr*sp*sy+-sr*cy);
                        test[2][2] = cr*cp;
                        test[2][2] = cr*cp;
-                       test[0][3] = pose[3];
-                       test[1][3] = pose[7];
-                       test[2][3] = pose[11];
+                       test[3][0] = pose[9];
+                       test[3][1] = pose[10];
+                       test[3][2] = pose[11];
 }
 #endif
 }
 #endif
-                       l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f\n", transformindex, pose[3] * modelscale, pose[7] * modelscale, pose[11] * modelscale, DEG2RAD(angles[ROLL]), DEG2RAD(angles[PITCH]), DEG2RAD(angles[YAW]));
+                       l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f\n", transformindex, mtest[3][0], mtest[3][1], mtest[3][2], DEG2RAD(angles[ROLL]), DEG2RAD(angles[PITCH]), DEG2RAD(angles[YAW]));
                        if (l > 0)
                                outbufferpos += l;
                }
                        if (l > 0)
                                outbufferpos += l;
                }
index 19b252b1200971be1c642a0d59d90ce217f15c04..36336d2d62f80c76af544e77c4f26479e0c6e267 100644 (file)
@@ -868,8 +868,10 @@ typedef struct model_s
        // for skeletal models
        int                             num_bones;
        aliasbone_t             *data_bones;
        // for skeletal models
        int                             num_bones;
        aliasbone_t             *data_bones;
+       float                   num_posescale; // scaling factor from origin in poses6s format (includes divide by 32767)
+       float                   num_poseinvscale; // scaling factor to origin in poses6s format (includes multiply by 32767)
        int                             num_poses;
        int                             num_poses;
-       float                   *data_poses;
+       short                   *data_poses6s; // origin xyz, quat xyz, w implied negative, unit length, values normalized to +/-32767 range
        float                   *data_baseboneposeinverse;
        // textures of this model
        int                             num_textures;
        float                   *data_baseboneposeinverse;
        // textures of this model
        int                             num_textures;
index 97304495fc176a802c8d970257eeebf142b08a0a..20f75b55170d99ce576a608b5b05fe9c76d101a7 100644 (file)
@@ -204,19 +204,19 @@ void VM_UpdateEdictSkeleton(prvm_edict_t *ed, const dp_model_t *edmodel, const f
                        int blendindex;
                        int bonenum;
                        int numbones = ed->priv.server->skeleton.model->num_bones;
                        int blendindex;
                        int bonenum;
                        int numbones = ed->priv.server->skeleton.model->num_bones;
-                       const float *poses = ed->priv.server->skeleton.model->data_poses;
-                       const float *framebones;
+                       const short *framebones6s;
                        float lerp;
                        float lerp;
+                       float scale = ed->priv.server->skeleton.model->num_posescale;
                        matrix4x4_t *relativetransforms = ed->priv.server->skeleton.relativetransforms;
                        matrix4x4_t matrix;
                        memset(relativetransforms, 0, numbones * sizeof(matrix4x4_t));
                        for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
                        {
                                lerp = frameblend[blendindex].lerp;
                        matrix4x4_t *relativetransforms = ed->priv.server->skeleton.relativetransforms;
                        matrix4x4_t matrix;
                        memset(relativetransforms, 0, numbones * sizeof(matrix4x4_t));
                        for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
                        {
                                lerp = frameblend[blendindex].lerp;
-                               framebones = poses + 12 * frameblend[blendindex].subframe * numbones;
+                               framebones6s = ed->priv.server->skeleton.model->data_poses6s + 6 * frameblend[blendindex].subframe * numbones;
                                for (bonenum = 0;bonenum < numbones;bonenum++)
                                {
                                for (bonenum = 0;bonenum < numbones;bonenum++)
                                {
-                                       Matrix4x4_FromArray12FloatD3D(&matrix, framebones + 12 * bonenum);
+                                       Matrix4x4_FromBonePose6s(&matrix, scale, framebones6s + 6 * bonenum);
                                        Matrix4x4_Accumulate(&ed->priv.server->skeleton.relativetransforms[bonenum], &matrix, lerp);
                                }
                        }
                                        Matrix4x4_Accumulate(&ed->priv.server->skeleton.relativetransforms[bonenum], &matrix, lerp);
                                }
                        }
index db253573c72cde7c5a7445321e2d54a80bef775d..f0954e821130e9e9187967b6de45f01d2d86919a 100644 (file)
@@ -3120,7 +3120,7 @@ static void VM_SV_skel_build(void)
                Matrix4x4_Accumulate(&blendedmatrix, &skeleton->relativetransforms[bonenum], retainfrac);
                for (blendindex = 0;blendindex < numblends;blendindex++)
                {
                Matrix4x4_Accumulate(&blendedmatrix, &skeleton->relativetransforms[bonenum], retainfrac);
                for (blendindex = 0;blendindex < numblends;blendindex++)
                {
-                       Matrix4x4_FromArray12FloatD3D(&matrix, model->data_poses + 12 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
+                       Matrix4x4_FromBonePose6s(&matrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
                        Matrix4x4_Accumulate(&blendedmatrix, &matrix, frameblend[blendindex].lerp);
                }
                skeleton->relativetransforms[bonenum] = blendedmatrix;
                        Matrix4x4_Accumulate(&blendedmatrix, &matrix, frameblend[blendindex].lerp);
                }
                skeleton->relativetransforms[bonenum] = blendedmatrix;