mod_md3_sin[i] = sin(i * M_PI * 2.0f / 256.0);
}
-void Mod_Skeletal_AnimateVertices(const dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, float *vertex3f, float *normal3f, float *svector3f, float *tvector3f)
+void Mod_Skeletal_InitBlends(dp_model_t *model)
+{
+ model->surfmesh.num_blends = 0;
+}
+
+int Mod_Skeletal_AddBlend(dp_model_t *model, const int *newindex, const float *newinfluence)
+{
+ int i;
+ int *weightindex = model->surfmesh.data_vertexweightindex4i;
+ float *weightinfluence = model->surfmesh.data_vertexweightinfluence4f;
+ if(newinfluence[0] == 1)
+ return newindex[0];
+ for (i = 0;i < model->surfmesh.num_blends;i++, weightindex += 4, weightinfluence += 4)
+ {
+ if (weightindex[0] == newindex[0] && weightindex[1] == newindex[1] && weightindex[2] == newindex[2] && weightindex[3] == newindex[3] &&
+ weightinfluence[0] == newinfluence[0] && weightinfluence[1] == newinfluence[1] && weightinfluence[2] == newinfluence[2] && weightinfluence[3] == newinfluence[3])
+ return model->num_bones + i;
+ }
+ model->surfmesh.num_blends++;
+ memcpy(weightindex, newindex, 4*sizeof(int));
+ memcpy(weightinfluence, newinfluence, 4*sizeof(float));
+ return model->num_bones + i;
+}
+
+static int maxbonepose = 0;
+static float (*bonepose)[12] = NULL;
+
+void Mod_Skeletal_FreeBuffers(void)
+{
+ if(bonepose)
+ Mem_Free(bonepose);
+ maxbonepose = 0;
+ bonepose = NULL;
+}
+
+#if defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1400)
+#define RESTRICT __restrict
+#else
+#define RESTRICT
+#endif
+
+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)
{
-#define MAX_BONES 256
// vertex weighted skeletal
int i, k;
int blends;
- float desiredscale[3];
- float boneposerelative[MAX_BONES][12];
- float *matrix, m[12], bonepose[MAX_BONES][12];
+ float m[12];
+ float (*boneposerelative)[12];
+ const int * RESTRICT weightindex;
+ const float * RESTRICT weightinfluence;
+
+ if (maxbonepose < model->num_bones*2 + model->surfmesh.num_blends)
+ {
+ if (bonepose)
+ Mem_Free(bonepose);
+ maxbonepose = model->num_bones*2 + model->surfmesh.num_blends;
+ bonepose = (float (*)[12])Mem_Alloc(r_main_mempool, maxbonepose * sizeof(float[12]));
+ }
+
+ boneposerelative = bonepose + model->num_bones;
if (skeleton && !skeleton->relativetransforms)
skeleton = NULL;
if (model->data_bones[i].parent >= 0)
R_ConcatTransforms(bonepose[model->data_bones[i].parent], m, bonepose[i]);
else
- for (k = 0;k < 12;k++)
- bonepose[i][k] = m[k];
-
+ memcpy(bonepose[i], 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], model->data_baseboneposeinverse + i * 12, boneposerelative[i]);
}
else
{
+ float originscale = model->num_posescale;
+ float x,y,z,w,lerp;
+ const short * RESTRICT pose6s;
for (i = 0;i < model->num_bones;i++)
{
- for (k = 0;k < 12;k++)
- m[k] = 0;
- VectorClear(desiredscale);
+ memset(m, 0, sizeof(m));
for (blends = 0;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
{
- matrix = model->data_poses + (frameblend[blends].subframe * model->num_bones + i) * 12;
- for (k = 0;k < 12;k++)
- m[k] += matrix[k] * frameblend[blends].lerp;
- desiredscale[0] += frameblend[blends].lerp * VectorLength(matrix );
- desiredscale[1] += frameblend[blends].lerp * VectorLength(matrix + 4);
- desiredscale[2] += frameblend[blends].lerp * VectorLength(matrix + 8);
+ pose6s = model->data_poses6s + 6 * (frameblend[blends].subframe * model->num_bones + i);
+ lerp = frameblend[blends].lerp;
+ 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;
+ m[ 0] += (1-2*(y*y+z*z)) * lerp;
+ m[ 1] += ( 2*(x*y-z*w)) * lerp;
+ m[ 2] += ( 2*(x*z+y*w)) * lerp;
+ m[ 3] += (pose6s[0] * originscale) * lerp;
+ m[ 4] += ( 2*(x*y+z*w)) * lerp;
+ m[ 5] += (1-2*(x*x+z*z)) * lerp;
+ m[ 6] += ( 2*(y*z-x*w)) * lerp;
+ m[ 7] += (pose6s[1] * originscale) * lerp;
+ m[ 8] += ( 2*(x*z-y*w)) * lerp;
+ m[ 9] += ( 2*(y*z+x*w)) * lerp;
+ m[10] += (1-2*(x*x+y*y)) * lerp;
+ m[11] += (pose6s[2] * originscale) * lerp;
}
- VectorNormalize(m );
+ 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 (model->data_bones[i].parent >= 0)
R_ConcatTransforms(bonepose[model->data_bones[i].parent], m, bonepose[i]);
else
- for (k = 0;k < 12;k++)
- bonepose[i][k] = m[k];
+ memcpy(bonepose[i], 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], model->data_baseboneposeinverse + i * 12, boneposerelative[i]);
}
}
+
+ // generate matrices for all blend combinations
+ weightindex = model->surfmesh.data_vertexweightindex4i + model->num_bones*4;
+ weightinfluence = model->surfmesh.data_vertexweightinfluence4f + model->num_bones*4;
+ for (i = 0;i < model->surfmesh.num_blends;i++, weightindex += 4, weightinfluence += 4)
+ {
+ float * RESTRICT b = boneposerelative[model->num_bones + i];
+ const float * RESTRICT m = boneposerelative[weightindex[0]];
+ float f = weightinfluence[0];
+ b[ 0] = f*m[ 0]; b[ 1] = f*m[ 1]; b[ 2] = f*m[ 2]; b[ 3] = f*m[ 3];
+ b[ 4] = f*m[ 4]; b[ 5] = f*m[ 5]; b[ 6] = f*m[ 6]; b[ 7] = f*m[ 7];
+ b[ 8] = f*m[ 8]; b[ 9] = f*m[ 9]; b[10] = f*m[10]; b[11] = f*m[11];
+ for (k = 1;k < 4 && weightinfluence[k];k++)
+ {
+ m = boneposerelative[weightindex[k]];
+ f = weightinfluence[k];
+ b[ 0] += f*m[ 0]; b[ 1] += f*m[ 1]; b[ 2] += f*m[ 2]; b[ 3] += f*m[ 3];
+ b[ 4] += f*m[ 4]; b[ 5] += f*m[ 5]; b[ 6] += f*m[ 6]; b[ 7] += f*m[ 7];
+ b[ 8] += f*m[ 8]; b[ 9] += f*m[ 9]; b[10] += f*m[10]; b[11] += f*m[11];
+ }
+ }
- // blend the vertex bone weights
- // special case for the extremely common wf[0] == 1 because it saves 3 multiplies per array when compared to the other case (w[0] is always 1 if only one bone controls this vertex, artists only use multiple bones for certain special cases)
- // special case for the first bone because it avoids the need to memset the arrays before filling
+ // transform vertex attributes by blended matrices
if (vertex3f)
{
- const float *v = model->surfmesh.data_vertex3f;
- const int *wi = model->surfmesh.data_vertexweightindex4i;
- const float *wf = model->surfmesh.data_vertexweightinfluence4f;
- memset(vertex3f, 0, sizeof(float[3]) * model->surfmesh.num_vertices);
- for (i = 0;i < model->surfmesh.num_vertices;i++, v += 3, wi += 4, wf += 4, vertex3f += 3)
+ const float * RESTRICT v = model->surfmesh.data_vertex3f;
+ const unsigned short * RESTRICT b = model->surfmesh.blends;
+ // special case common combinations of attributes to avoid repeated loading of matrices
+ if (normal3f)
{
- if (wf[0] == 1)
+ const float * RESTRICT n = model->surfmesh.data_normal3f;
+ if (svector3f && tvector3f)
{
- const float *m = boneposerelative[wi[0]];
- vertex3f[0] = (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]);
- vertex3f[1] = (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]);
- vertex3f[2] = (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]);
- }
- else
- {
- const float *m = boneposerelative[wi[0]];
- float f = wf[0];
- vertex3f[0] = f * (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]);
- vertex3f[1] = f * (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]);
- vertex3f[2] = f * (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]);
- for (k = 1;k < 4 && wf[k];k++)
+ const float * RESTRICT sv = model->surfmesh.data_svector3f;
+ const float * RESTRICT tv = model->surfmesh.data_tvector3f;
+ for (i = 0;i < model->surfmesh.num_vertices;i++, v += 3, n += 3, sv += 3, tv += 3, b++, vertex3f += 3, normal3f += 3, svector3f += 3, tvector3f += 3)
{
- const float *m = boneposerelative[wi[k]];
- float f = wf[k];
- vertex3f[0] += f * (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]);
- vertex3f[1] += f * (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]);
- vertex3f[2] += f * (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]);
+ const float * RESTRICT m = boneposerelative[*b];
+ vertex3f[0] = (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]);
+ vertex3f[1] = (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]);
+ vertex3f[2] = (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]);
+ normal3f[0] = (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]);
+ normal3f[1] = (n[0] * m[4] + n[1] * m[5] + n[2] * m[ 6]);
+ normal3f[2] = (n[0] * m[8] + n[1] * m[9] + n[2] * m[10]);
+ svector3f[0] = (sv[0] * m[0] + sv[1] * m[1] + sv[2] * m[ 2]);
+ svector3f[1] = (sv[0] * m[4] + sv[1] * m[5] + sv[2] * m[ 6]);
+ svector3f[2] = (sv[0] * m[8] + sv[1] * m[9] + sv[2] * m[10]);
+ tvector3f[0] = (tv[0] * m[0] + tv[1] * m[1] + tv[2] * m[ 2]);
+ tvector3f[1] = (tv[0] * m[4] + tv[1] * m[5] + tv[2] * m[ 6]);
+ tvector3f[2] = (tv[0] * m[8] + tv[1] * m[9] + tv[2] * m[10]);
}
+ return;
}
- }
- }
- if (normal3f)
- {
- const float *n = model->surfmesh.data_normal3f;
- const int *wi = model->surfmesh.data_vertexweightindex4i;
- const float *wf = model->surfmesh.data_vertexweightinfluence4f;
- memset(normal3f, 0, sizeof(float[3]) * model->surfmesh.num_vertices);
- for (i = 0;i < model->surfmesh.num_vertices;i++, n += 3, wi += 4, wf += 4, normal3f += 3)
- {
- if (wf[0] == 1)
+ for (i = 0;i < model->surfmesh.num_vertices;i++, v += 3, n += 3, b++, vertex3f += 3, normal3f += 3)
{
- const float *m = boneposerelative[wi[0]];
- normal3f[0] = (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]);
+ const float * RESTRICT m = boneposerelative[*b];
+ vertex3f[0] = (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]);
+ vertex3f[1] = (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]);
+ vertex3f[2] = (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]);
+ normal3f[0] = (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]);
normal3f[1] = (n[0] * m[4] + n[1] * m[5] + n[2] * m[ 6]);
normal3f[2] = (n[0] * m[8] + n[1] * m[9] + n[2] * m[10]);
}
- else
+ }
+ else
+ {
+ for (i = 0;i < model->surfmesh.num_vertices;i++, v += 3, b++, vertex3f += 3)
{
- const float *m = boneposerelative[wi[0]];
- float f = wf[0];
- normal3f[0] = f * (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]);
- normal3f[1] = f * (n[0] * m[4] + n[1] * m[5] + n[2] * m[ 6]);
- normal3f[2] = f * (n[0] * m[8] + n[1] * m[9] + n[2] * m[10]);
- for (k = 1;k < 4 && wf[k];k++)
- {
- const float *m = boneposerelative[wi[k]];
- float f = wf[k];
- normal3f[0] += f * (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]);
- normal3f[1] += f * (n[0] * m[4] + n[1] * m[5] + n[2] * m[ 6]);
- normal3f[2] += f * (n[0] * m[8] + n[1] * m[9] + n[2] * m[10]);
- }
+ const float * RESTRICT m = boneposerelative[*b];
+ vertex3f[0] = (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]);
+ vertex3f[1] = (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]);
+ vertex3f[2] = (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]);
}
}
}
+ else if (normal3f)
+ {
+ const float * RESTRICT n = model->surfmesh.data_normal3f;
+ const unsigned short * RESTRICT b = model->surfmesh.blends;
+ for (i = 0;i < model->surfmesh.num_vertices;i++, n += 3, b++, normal3f += 3)
+ {
+ const float * RESTRICT m = boneposerelative[*b];
+ normal3f[0] = (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]);
+ normal3f[1] = (n[0] * m[4] + n[1] * m[5] + n[2] * m[ 6]);
+ normal3f[2] = (n[0] * m[8] + n[1] * m[9] + n[2] * m[10]);
+ }
+ }
+
if (svector3f)
{
- const float *sv = model->surfmesh.data_svector3f;
- const int *wi = model->surfmesh.data_vertexweightindex4i;
- const float *wf = model->surfmesh.data_vertexweightinfluence4f;
- memset(svector3f, 0, sizeof(float[3]) * model->surfmesh.num_vertices);
- for (i = 0;i < model->surfmesh.num_vertices;i++, sv += 3, wi += 4, wf += 4, svector3f += 3)
+ const float * RESTRICT sv = model->surfmesh.data_svector3f;
+ const unsigned short * RESTRICT b = model->surfmesh.blends;
+ for (i = 0;i < model->surfmesh.num_vertices;i++, sv += 3, b++, svector3f += 3)
{
- if (wf[0] == 1)
- {
- const float *m = boneposerelative[wi[0]];
- svector3f[0] = (sv[0] * m[0] + sv[1] * m[1] + sv[2] * m[ 2]);
- svector3f[1] = (sv[0] * m[4] + sv[1] * m[5] + sv[2] * m[ 6]);
- svector3f[2] = (sv[0] * m[8] + sv[1] * m[9] + sv[2] * m[10]);
- }
- else
- {
- const float *m = boneposerelative[wi[0]];
- float f = wf[0];
- svector3f[0] = f * (sv[0] * m[0] + sv[1] * m[1] + sv[2] * m[ 2]);
- svector3f[1] = f * (sv[0] * m[4] + sv[1] * m[5] + sv[2] * m[ 6]);
- svector3f[2] = f * (sv[0] * m[8] + sv[1] * m[9] + sv[2] * m[10]);
- for (k = 1;k < 4 && wf[k];k++)
- {
- const float *m = boneposerelative[wi[k]];
- float f = wf[k];
- svector3f[0] += f * (sv[0] * m[0] + sv[1] * m[1] + sv[2] * m[ 2]);
- svector3f[1] += f * (sv[0] * m[4] + sv[1] * m[5] + sv[2] * m[ 6]);
- svector3f[2] += f * (sv[0] * m[8] + sv[1] * m[9] + sv[2] * m[10]);
- }
- }
+ const float * RESTRICT m = boneposerelative[*b];
+ svector3f[0] = (sv[0] * m[0] + sv[1] * m[1] + sv[2] * m[ 2]);
+ svector3f[1] = (sv[0] * m[4] + sv[1] * m[5] + sv[2] * m[ 6]);
+ svector3f[2] = (sv[0] * m[8] + sv[1] * m[9] + sv[2] * m[10]);
}
}
+
if (tvector3f)
{
- const float *tv = model->surfmesh.data_tvector3f;
- const int *wi = model->surfmesh.data_vertexweightindex4i;
- const float *wf = model->surfmesh.data_vertexweightinfluence4f;
- memset(tvector3f, 0, sizeof(float[3]) * model->surfmesh.num_vertices);
- for (i = 0;i < model->surfmesh.num_vertices;i++, tv += 3, wi += 4, wf += 4, tvector3f += 3)
+ const float * RESTRICT tv = model->surfmesh.data_tvector3f;
+ const unsigned short * RESTRICT b = model->surfmesh.blends;
+ for (i = 0;i < model->surfmesh.num_vertices;i++, tv += 3, b++, tvector3f += 3)
{
- if (wf[0] == 1)
- {
- const float *m = boneposerelative[wi[0]];
- tvector3f[0] = (tv[0] * m[0] + tv[1] * m[1] + tv[2] * m[ 2]);
- tvector3f[1] = (tv[0] * m[4] + tv[1] * m[5] + tv[2] * m[ 6]);
- tvector3f[2] = (tv[0] * m[8] + tv[1] * m[9] + tv[2] * m[10]);
- }
- else
- {
- const float *m = boneposerelative[wi[0]];
- float f = wf[0];
- tvector3f[0] = f * (tv[0] * m[0] + tv[1] * m[1] + tv[2] * m[ 2]);
- tvector3f[1] = f * (tv[0] * m[4] + tv[1] * m[5] + tv[2] * m[ 6]);
- tvector3f[2] = f * (tv[0] * m[8] + tv[1] * m[9] + tv[2] * m[10]);
- for (k = 1;k < 4 && wf[k];k++)
- {
- const float *m = boneposerelative[wi[k]];
- float f = wf[k];
- tvector3f[0] += f * (tv[0] * m[0] + tv[1] * m[1] + tv[2] * m[ 2]);
- tvector3f[1] += f * (tv[0] * m[4] + tv[1] * m[5] + tv[2] * m[ 6]);
- tvector3f[2] += f * (tv[0] * m[8] + tv[1] * m[9] + tv[2] * m[10]);
- }
- }
+ const float * RESTRICT m = boneposerelative[*b];
+ tvector3f[0] = (tv[0] * m[0] + tv[1] * m[1] + tv[2] * m[ 2]);
+ tvector3f[1] = (tv[0] * m[4] + tv[1] * m[5] + tv[2] * m[ 6]);
+ tvector3f[2] = (tv[0] * m[8] + tv[1] * m[9] + tv[2] * m[10]);
}
}
}
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;
- float tempbonematrix[12], bonematrix[12], blendmatrix[12];
+ const float *input;
+ float blendtag[12];
*outmatrix = identitymatrix;
if (skeleton && skeleton->relativetransforms)
{
{
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;
- 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)
{
- 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++)
- 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++)
- blendmatrix[k] += input[k] * lerp;
+ blendtag[k] += input[k] * lerp;
}
- Matrix4x4_FromArray12FloatGL(outmatrix, blendmatrix);
+ Matrix4x4_FromArray12FloatGL(outmatrix, blendtag);
}
if(!mod_alias_supporttagscale.integer)
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;
- float blendmatrix[12];
+ matrix4x4_t bonematrix;
+ matrix4x4_t blendmatrix;
+ const float *input;
+ float blendtag[12];
if (skeleton && skeleton->relativetransforms)
{
}
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;
+ Matrix4x4_Clear(&blendmatrix);
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)
{
- if(tagindex >= model->num_tags || tagindex < 0)
+ if (tagindex < 0 || tagindex >= model->num_tags)
return 1;
*parentindex = -1;
*tagname = model->data_tags[tagindex].name;
+ 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++)
- blendmatrix[k] += input[k] * lerp;
+ blendtag[k] += input[k] * lerp;
}
- Matrix4x4_FromArray12FloatGL(tag_localmatrix, blendmatrix);
+ Matrix4x4_FromArray12FloatGL(tag_localmatrix, blendtag);
return 0;
}
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;
- 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);
}
{
VectorAdd(start, boxmins, shiftstart);
VectorAdd(end, boxmins, shiftend);
- Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask);
+ Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask);
VectorSubtract(trace->endpos, boxmins, trace->endpos);
return;
}
if (texture->currentskinframe->hasalpha)
texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
texture->currentmaterialflags = texture->basematerialflags;
+ texture->specularscalemod = 1;
+ texture->specularpowermod = 1;
}
-static void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
+void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
{
int i;
skinfileitem_t *skinfileitem;
// leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
if (!strcmp(skinfileitem->name, meshname))
{
- Mod_LoadTextureFromQ3Shader(skin, skinfileitem->replacement, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP | TEXF_COMPRESS);
+ Mod_LoadTextureFromQ3Shader(skin, skinfileitem->replacement, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
break;
}
}
}
}
else
- Mod_LoadTextureFromQ3Shader(skin, shadername, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP | TEXF_COMPRESS);
+ Mod_LoadTextureFromQ3Shader(skin, shadername, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
}
#define BOUNDI(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%d exceeds %d - %d)", loadmodel->name, VALUE, MIN, MAX);
loadmodel->Draw = R_Q1BSP_Draw;
loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+ loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
loadmodel->numframes = LittleLong(pinmodel->numframes);
BOUNDI(loadmodel->numframes,0,65536);
loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
- BOUNDI(loadmodel->synctype,0,2);
+ BOUNDI((int)loadmodel->synctype,0,2);
// convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
i = LittleLong (pinmodel->flags);
loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
else
dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
- if (!Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS | TEXF_PRECACHE))
- Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, R_SkinFrame_LoadInternalQuake(name, TEXF_PRECACHE | (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight));
+ if (!Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS))
+ Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, R_SkinFrame_LoadInternalQuake(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight));
datapointer += skinwidth * skinheight;
totalskins++;
}
loadmodel->Draw = R_Q1BSP_Draw;
loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+ loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
loadmodel->num_texturesperskin = loadmodel->num_surfaces;
loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
- Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP | TEXF_COMPRESS);
+ Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
}
else
{
loadmodel->Draw = R_Q1BSP_Draw;
loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+ loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
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, tempvec[3], modelscale;
zymvertex_t *verts, *vertdata;
zymscene_t *scene;
zymbone_t *bone;
loadmodel->Draw = R_Q1BSP_Draw;
loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+ loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
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]) + meshvertices * sizeof(unsigned short) + 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->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->surfmesh.num_blends = 0;
loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
+ loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
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);
- for (i = 0;i < pheader->lump_poses.length / 4;i++)
- loadmodel->data_poses[i] = BigFloat(poses[i]);
+ // figure out scale of model from root bone, for compatibility with old zmodel versions
+ tempvec[0] = BigFloat(poses[0]);
+ tempvec[1] = BigFloat(poses[1]);
+ tempvec[2] = BigFloat(poses[2]);
+ modelscale = VectorLength(tempvec);
+ 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 < numposes;i++)
+ {
+ const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
+ for (j = 0;j < loadmodel->num_bones;j++)
+ {
+ float pose[12];
+ matrix4x4_t posematrix;
+ for (k = 0;k < 12;k++)
+ pose[k] = BigFloat(frameposes[j*12+k]);
+ //if (j < loadmodel->num_bones)
+ // Con_Printf("%s: bone %i = %f %f %f %f : %f %f %f %f : %f %f %f %f : scale = %f\n", loadmodel->name, j, pose[0], pose[1], pose[2], pose[3], pose[4], pose[5], pose[6], pose[7], pose[8], pose[9], pose[10], pose[11], VectorLength(pose));
+ // scale child bones to match the root scale
+ if (loadmodel->data_bones[j].parent >= 0)
+ {
+ pose[3] *= modelscale;
+ pose[7] *= modelscale;
+ pose[11] *= modelscale;
+ }
+ // normalize rotation matrix
+ VectorNormalize(pose + 0);
+ VectorNormalize(pose + 4);
+ VectorNormalize(pose + 8);
+ Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
+ Matrix4x4_ToBonePose6s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses6s + 6*(i*loadmodel->num_bones+j));
+ }
+ }
//zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
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
for (k = 0;k < 12;k++)
bonepose[12*i+k] = m[k];
}
+ Mod_Skeletal_InitBlends(loadmodel);
for (j = 0;j < pheader->numverts;j++)
{
// this format really should have had a per vertexweight weight value...
loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
// store the weight as the primary weight on this vertex
- loadmodel->surfmesh.data_vertexweightindex4i[j*4+0] = boneindex;
- loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+0] = 1;
+ loadmodel->surfmesh.blends[j] = boneindex;
}
Z_Free(bonepose);
// normals and tangents are calculated after elements are loaded
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;
skinfile_t *skinfiles;
unsigned char *data;
float *bonepose;
+ float biggestorigin, tempvec[3], modelscale;
+ float f;
+ float *poses;
pheader = (dpmheader_t *)buffer;
pbase = (unsigned char *)buffer;
loadmodel->Draw = R_Q1BSP_Draw;
loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+ loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
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]) + sizeof(unsigned short)) + 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->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->surfmesh.num_blends = 0;
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);
+ loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
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++)
{
}
// load the frames
- frame = (dpmframe_t *) (pbase + pheader->ofs_frames);
+ frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
+ // figure out scale of model from root bone, for compatibility with old dpmodel versions
+ poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
+ tempvec[0] = BigFloat(poses[0]);
+ tempvec[1] = BigFloat(poses[1]);
+ tempvec[2] = BigFloat(poses[2]);
+ modelscale = VectorLength(tempvec);
+ biggestorigin = 0;
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
- poses = (float *) (pbase + BigLong(frame->ofs_bonepositions));
+ poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
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
- frame++;
+ }
+ loadmodel->num_posescale = biggestorigin / 32767.0f;
+ loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
+ for (i = 0;i < loadmodel->numframes;i++)
+ {
+ const float *frameposes = (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(frameposes[j*12+k]);
+ // scale child bones to match the root scale
+ if (loadmodel->data_bones[j].parent >= 0)
+ {
+ pose[3] *= modelscale;
+ pose[7] *= modelscale;
+ pose[11] *= modelscale;
+ }
+ // normalize rotation matrix
+ VectorNormalize(pose + 0);
+ VectorNormalize(pose + 4);
+ VectorNormalize(pose + 8);
+ Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
+ Matrix4x4_ToBonePose6s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses6s + 6*(i*loadmodel->num_bones+j));
+ }
}
// load the meshes now
// 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++)
{
- 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
for (k = 0;k < 12;k++)
bonepose[12*i+k] = m[k];
}
+ Mod_Skeletal_InitBlends(loadmodel);
for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
{
const int *inelements;
data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
{
+ int weightindex[4] = { 0, 0, 0, 0 };
+ float weightinfluence[4] = { 0, 0, 0, 0 };
float sum;
int l;
int numweights = BigLong(((dpmvertex_t *)data)->numbones);
if (!k)
{
// store the first (and often only) weight
- loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+0] = influence;
- loadmodel->surfmesh.data_vertexweightindex4i[j*4+0] = boneindex;
+ weightinfluence[0] = influence;
+ weightindex[0] = boneindex;
}
else
{
// (which only accepts up to 4 bones per vertex)
for (l = 0;l < 4;l++)
{
- if (loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] < influence)
+ if (weightinfluence[l] < influence)
{
// move weaker influence weights out of the way first
int l2;
for (l2 = 3;l2 > l;l2--)
{
- loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l2] = loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l2-1];
- loadmodel->surfmesh.data_vertexweightindex4i[j*4+l2] = loadmodel->surfmesh.data_vertexweightindex4i[j*4+l2-1];
+ weightinfluence[l2] = weightinfluence[l2-1];
+ weightindex[l2] = weightindex[l2-1];
}
// store the new weight
- loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] = influence;
- loadmodel->surfmesh.data_vertexweightindex4i[j*4+l] = boneindex;
+ weightinfluence[l] = influence;
+ weightindex[l] = boneindex;
break;
}
}
}
sum = 0;
for (l = 0;l < 4;l++)
- sum += loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l];
+ sum += weightinfluence[l];
if (sum && fabs(sum - 1) > (1.0f / 256.0f))
{
float f = 1.0f / sum;
for (l = 0;l < 4;l++)
- loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] *= f;
+ weightinfluence[l] *= f;
}
+ loadmodel->surfmesh.blends[j] = Mod_Skeletal_AddBlend(loadmodel, weightindex, weightinfluence);
}
// since dpm models do not have named sections, reuse their shader name as the section name
pskmatt_t *matts;
pskboneinfo_t *bones;
pskrawweights_t *rawweights;
- pskboneinfo_t *animbones;
+ //pskboneinfo_t *animbones;
pskaniminfo_t *anims;
pskanimkeys_t *animkeys;
void *animfilebuffer, *animbuffer, *animbufferend;
skinfile_t *skinfiles;
char animname[MAX_QPATH];
size_t size;
+ float biggestorigin;
pchunk = (pskchunk_t *)buffer;
if (strcmp(pchunk->id, "ACTRHEAD"))
loadmodel->Draw = R_Q1BSP_Draw;
loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+ loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
version = LittleLong(pchunk->version);
recordsize = LittleLong(pchunk->recordsize);
numrecords = LittleLong(pchunk->numrecords);
- if (developer.integer >= 100)
- Con_Printf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
+ if (developer_extra.integer)
+ Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
Con_Printf ("%s: chunk %s has unknown version %x (0x1e83b9, 0x1e9179, 0x2e, 0x12f2bc, 0x12f2f0 are currently supported), trying to load anyway!\n", loadmodel->name, pchunk->id, version);
if (!strcmp(pchunk->id, "ACTRHEAD"))
version = LittleLong(pchunk->version);
recordsize = LittleLong(pchunk->recordsize);
numrecords = LittleLong(pchunk->numrecords);
- if (developer.integer >= 100)
- Con_Printf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
+ if (developer_extra.integer)
+ Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
Con_Printf ("%s: chunk %s has unknown version %x (0x1e83b9, 0x1e9179, 0x2e, 0x12f2bc, 0x12f2f0 are currently supported), trying to load anyway!\n", animname, pchunk->id, version);
if (!strcmp(pchunk->id, "ANIMHEAD"))
Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
// byteswap in place and keep the pointer
numanimbones = numrecords;
- animbones = (pskboneinfo_t *)animbuffer;
+ //animbones = (pskboneinfo_t *)animbuffer;
// NOTE: supposedly psa does not need to match the psk model, the
// bones missing from the psa would simply use their base
// positions from the psk, but this is hard for me to implement
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->surfmesh.num_vertices * sizeof(unsigned short) + 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);
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->surfmesh.num_blends = 0;
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);
+ loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
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++)
{
// sort the psk point weights into the vertex weight tables
// (which only accept up to 4 bones per vertex)
+ Mod_Skeletal_InitBlends(loadmodel);
for (index = 0;index < numvtxw;index++)
{
+ int weightindex[4];
+ float weightinfluence[4];
int l;
float sum;
for (j = 0;j < numrawweights;j++)
float influence = rawweights[j].weight;
for (l = 0;l < 4;l++)
{
- if (loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] < influence)
+ if (weightinfluence[l] < influence)
{
// move lower influence weights out of the way first
int l2;
for (l2 = 3;l2 > l;l2--)
{
- loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l2] = loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l2-1];
- loadmodel->surfmesh.data_vertexweightindex4i[index*4+l2] = loadmodel->surfmesh.data_vertexweightindex4i[index*4+l2-1];
+ weightinfluence[l2] = weightinfluence[l2-1];
+ weightindex[l2] = weightindex[l2-1];
}
// store the new weight
- loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] = influence;
- loadmodel->surfmesh.data_vertexweightindex4i[index*4+l] = boneindex;
+ weightinfluence[l] = influence;
+ weightindex[l] = boneindex;
break;
}
}
}
sum = 0;
for (l = 0;l < 4;l++)
- sum += loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l];
+ sum += weightinfluence[l];
if (sum && fabs(sum - 1) > (1.0f / 256.0f))
{
float f = 1.0f / sum;
for (l = 0;l < 4;l++)
- loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] *= f;
+ weightinfluence[l] *= f;
}
+ loadmodel->surfmesh.blends[index] = Mod_Skeletal_AddBlend(loadmodel, weightindex, weightinfluence);
}
// set up the animscenes based on the anims
}
}
+ // 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;
- 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);