+ m[k] += matrix[k] * frameblend[blends].lerp;
+ desiredscale[0] += frameblend[blends].lerp * VectorLength(matrix );
+ desiredscale[1] += frameblend[blends].lerp * VectorLength(matrix + 4);
+ desiredscale[2] += frameblend[blends].lerp * VectorLength(matrix + 8);
+ }
+ VectorNormalize(m );
+ VectorNormalize(m + 4);
+ VectorNormalize(m + 8);
+ VectorScale(m , desiredscale[0], m );
+ VectorScale(m + 4, desiredscale[1], m + 4);
+ VectorScale(m + 8, desiredscale[2], m + 8);
+ if (i == r_skeletal_debugbone.integer)
+ m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value;
+ m[3] *= r_skeletal_debugtranslatex.value;
+ m[7] *= r_skeletal_debugtranslatey.value;
+ m[11] *= r_skeletal_debugtranslatez.value;
+ if (model->data_bones[i].parent >= 0)
+ R_ConcatTransforms(bonepose[model->data_bones[i].parent], m, bonepose[i]);
+ else
+ for (k = 0;k < 12;k++)
+ bonepose[i][k] = m[k];
+ // 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]);
+ }
+ // 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
+ {
+ 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)
+ {
+ if (wf[0] == 1)