+void Mod_Alias_GetMesh_Vertex3f(const model_t *model, const frameblend_t *frameblend, const aliasmesh_t *mesh, float *out3f)
+{
+ if (mesh->num_vertexboneweights)
+ {
+ int i, k, blends;
+ aliasvertexboneweight_t *v;
+ float *out, *matrix, m[12], bonepose[256][12];
+ // vertex weighted skeletal
+ // interpolate matrices and concatenate them to their parents
+ for (i = 0;i < model->alias.aliasnum_bones;i++)
+ {
+ for (k = 0;k < 12;k++)
+ m[k] = 0;
+ for (blends = 0;blends < 4 && frameblend[blends].lerp > 0;blends++)
+ {
+ matrix = model->alias.aliasdata_poses + (frameblend[blends].frame * model->alias.aliasnum_bones + i) * 12;
+ for (k = 0;k < 12;k++)
+ m[k] += matrix[k] * frameblend[blends].lerp;
+ }
+ if (model->alias.aliasdata_bones[i].parent >= 0)
+ R_ConcatTransforms(bonepose[model->alias.aliasdata_bones[i].parent], m, bonepose[i]);
+ else
+ for (k = 0;k < 12;k++)
+ bonepose[i][k] = m[k];
+ }
+ // blend the vertex bone weights
+ memset(out3f, 0, mesh->num_vertices * sizeof(float[3]));
+ v = mesh->data_vertexboneweights;
+ for (i = 0;i < mesh->num_vertexboneweights;i++, v++)
+ {
+ out = out3f + v->vertexindex * 3;
+ matrix = bonepose[v->boneindex];
+ // FIXME: this can very easily be optimized with SSE or 3DNow
+ out[0] += v->origin[0] * matrix[0] + v->origin[1] * matrix[1] + v->origin[2] * matrix[ 2] + v->origin[3] * matrix[ 3];
+ out[1] += v->origin[0] * matrix[4] + v->origin[1] * matrix[5] + v->origin[2] * matrix[ 6] + v->origin[3] * matrix[ 7];
+ out[2] += v->origin[0] * matrix[8] + v->origin[1] * matrix[9] + v->origin[2] * matrix[10] + v->origin[3] * matrix[11];
+ }
+ }
+ else
+ {
+ int i, vertcount;
+ float lerp1, lerp2, lerp3, lerp4;
+ const float *vertsbase, *verts1, *verts2, *verts3, *verts4;
+ // vertex morph
+ vertsbase = mesh->data_morphvertex3f;
+ vertcount = mesh->num_vertices;
+ verts1 = vertsbase + frameblend[0].frame * vertcount * 3;
+ lerp1 = frameblend[0].lerp;
+ if (frameblend[1].lerp)
+ {
+ verts2 = vertsbase + frameblend[1].frame * vertcount * 3;
+ lerp2 = frameblend[1].lerp;
+ if (frameblend[2].lerp)
+ {
+ verts3 = vertsbase + frameblend[2].frame * vertcount * 3;
+ lerp3 = frameblend[2].lerp;
+ if (frameblend[3].lerp)
+ {
+ verts4 = vertsbase + frameblend[3].frame * vertcount * 3;
+ lerp4 = frameblend[3].lerp;
+ for (i = 0;i < vertcount * 3;i++)
+ VectorMAMAMAM(lerp1, verts1 + i, lerp2, verts2 + i, lerp3, verts3 + i, lerp4, verts4 + i, out3f + i);
+ }
+ else
+ for (i = 0;i < vertcount * 3;i++)
+ VectorMAMAM(lerp1, verts1 + i, lerp2, verts2 + i, lerp3, verts3 + i, out3f + i);
+ }
+ else
+ for (i = 0;i < vertcount * 3;i++)
+ VectorMAM(lerp1, verts1 + i, lerp2, verts2 + i, out3f + i);
+ }
+ else
+ memcpy(out3f, verts1, vertcount * sizeof(float[3]));
+ }
+}
+
+int Mod_Alias_GetTagMatrix(const model_t *model, int poseframe, int tagindex, matrix4x4_t *outmatrix)
+{
+ const float *boneframe;
+ float tempbonematrix[12], bonematrix[12];
+ Matrix4x4_CreateIdentity(outmatrix);
+ if (model->alias.aliasnum_bones)
+ {
+ if (tagindex < 0 || tagindex >= model->alias.aliasnum_bones)
+ return 4;
+ if (poseframe >= model->alias.aliasnum_poses)
+ return 6;
+ boneframe = model->alias.aliasdata_poses + poseframe * model->alias.aliasnum_bones * 12;
+ memcpy(bonematrix, boneframe + tagindex * 12, sizeof(float[12]));
+ while (model->alias.aliasdata_bones[tagindex].parent >= 0)
+ {
+ memcpy(tempbonematrix, bonematrix, sizeof(float[12]));
+ R_ConcatTransforms(boneframe + model->alias.aliasdata_bones[tagindex].parent * 12, tempbonematrix, bonematrix);
+ tagindex = model->alias.aliasdata_bones[tagindex].parent;
+ }
+ outmatrix->m[0][0] = bonematrix[0];
+ outmatrix->m[0][1] = bonematrix[1];
+ outmatrix->m[0][2] = bonematrix[2];
+ outmatrix->m[0][3] = bonematrix[3];
+ outmatrix->m[1][0] = bonematrix[4];
+ outmatrix->m[1][1] = bonematrix[5];
+ outmatrix->m[1][2] = bonematrix[6];
+ outmatrix->m[1][3] = bonematrix[7];
+ outmatrix->m[2][0] = bonematrix[8];
+ outmatrix->m[2][1] = bonematrix[9];
+ outmatrix->m[2][2] = bonematrix[10];
+ outmatrix->m[2][3] = bonematrix[11];
+ outmatrix->m[3][0] = 0;
+ outmatrix->m[3][1] = 0;
+ outmatrix->m[3][2] = 0;
+ outmatrix->m[3][3] = 1;
+ }
+ else if (model->alias.aliasnum_tags)
+ {
+ if (tagindex < 0 || tagindex >= model->alias.aliasnum_tags)
+ return 4;
+ if (poseframe >= model->alias.aliasnum_tagframes)
+ return 6;
+ *outmatrix = model->alias.aliasdata_tags[poseframe * model->alias.aliasnum_tags + tagindex].matrix;
+ }
+ return 0;
+}
+
+int Mod_Alias_GetTagIndexForName(const model_t *model, unsigned int skin, const char *tagname)
+{
+ int i;
+ if (model->data_overridetagnamesforskin && skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)skin].num_overridetagnames)
+ for (i = 0;i < model->data_overridetagnamesforskin[skin].num_overridetagnames;i++)
+ if (!strcasecmp(tagname, model->data_overridetagnamesforskin[skin].data_overridetagnames[i].name))
+ return i + 1;
+ if (model->alias.aliasnum_bones)
+ for (i = 0;i < model->alias.aliasnum_bones;i++)
+ if (!strcasecmp(tagname, model->alias.aliasdata_bones[i].name))
+ return i + 1;
+ if (model->alias.aliasnum_tags)
+ for (i = 0;i < model->alias.aliasnum_tags;i++)
+ if (!strcasecmp(tagname, model->alias.aliasdata_tags[i].name))
+ return i + 1;
+ return 0;
+}
+
+static void Mod_Alias_Mesh_CompileFrameZero(aliasmesh_t *mesh)
+{
+ frameblend_t frameblend[4] = {{0, 1}, {0, 0}, {0, 0}, {0, 0}};
+ mesh->data_basevertex3f = Mem_Alloc(loadmodel->mempool, mesh->num_vertices * sizeof(float[3][4]));
+ mesh->data_basesvector3f = mesh->data_basevertex3f + mesh->num_vertices * 3;
+ mesh->data_basetvector3f = mesh->data_basevertex3f + mesh->num_vertices * 6;
+ mesh->data_basenormal3f = mesh->data_basevertex3f + mesh->num_vertices * 9;
+ Mod_Alias_GetMesh_Vertex3f(loadmodel, frameblend, mesh, mesh->data_basevertex3f);
+ Mod_BuildTextureVectorsAndNormals(0, mesh->num_vertices, mesh->num_triangles, mesh->data_basevertex3f, mesh->data_texcoord2f, mesh->data_element3i, mesh->data_basesvector3f, mesh->data_basetvector3f, mesh->data_basenormal3f);
+}
+
+static void Mod_MDLMD2MD3_TraceBox(model_t *model, int frame, trace_t *trace, const vec3_t boxstartmins, const vec3_t boxstartmaxs, const vec3_t boxendmins, const vec3_t boxendmaxs, int hitsupercontentsmask)
+{
+ int i, framenum;
+ float segmentmins[3], segmentmaxs[3];
+ colbrushf_t *thisbrush_start, *thisbrush_end;
+ matrix4x4_t startmatrix, endmatrix;
+ memset(trace, 0, sizeof(*trace));
+ trace->fraction = 1;
+ trace->realfraction = 1;
+ trace->hitsupercontentsmask = hitsupercontentsmask;
+ segmentmins[0] = min(boxstartmins[0], boxendmins[0]);
+ segmentmins[1] = min(boxstartmins[1], boxendmins[1]);
+ segmentmins[2] = min(boxstartmins[2], boxendmins[2]);
+ segmentmaxs[0] = max(boxstartmaxs[0], boxendmaxs[0]);
+ segmentmaxs[1] = max(boxstartmaxs[1], boxendmaxs[1]);
+ segmentmaxs[2] = max(boxstartmaxs[2], boxendmaxs[2]);
+ if (VectorCompare(boxstartmins, boxstartmaxs) && VectorCompare(boxendmins, boxendmaxs))
+ {
+ // line trace
+ for (i = 0;i < model->alias.aliasnum_meshes;i++)
+ {
+ framenum = frame;
+ if (framenum < 0 || framenum > model->alias.aliasdata_meshes[i].num_morphframes)
+ framenum = 0;
+ if (model->alias.aliasdata_meshes[i].data_morphvertex3f)
+ Collision_TraceLineTriangleMeshFloat(trace, boxstartmins, boxendmins, model->alias.aliasdata_meshes[i].num_triangles, model->alias.aliasdata_meshes[i].data_element3i, model->alias.aliasdata_meshes[i].data_morphvertex3f + framenum * model->alias.aliasdata_meshes[i].num_vertices * 3, SUPERCONTENTS_SOLID, segmentmins, segmentmaxs);
+ //else
+ // FIXME!!! this needs to handle skeletal!
+ }
+ }
+ else
+ {
+ // box trace, performed as brush trace
+ Matrix4x4_CreateIdentity(&startmatrix);
+ Matrix4x4_CreateIdentity(&endmatrix);
+ thisbrush_start = Collision_BrushForBox(&startmatrix, boxstartmins, boxstartmaxs);
+ thisbrush_end = Collision_BrushForBox(&endmatrix, boxendmins, boxendmaxs);
+ for (i = 0;i < model->alias.aliasnum_meshes;i++)
+ {
+ framenum = frame;
+ if (framenum < 0 || framenum > model->alias.aliasdata_meshes[i].num_morphframes)
+ framenum = 0;
+ if (model->alias.aliasdata_meshes[i].data_morphvertex3f)
+ Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, model->alias.aliasdata_meshes[i].num_triangles, model->alias.aliasdata_meshes[i].data_element3i, model->alias.aliasdata_meshes[i].data_morphvertex3f + framenum * model->alias.aliasdata_meshes[i].num_vertices * 3, SUPERCONTENTS_SOLID, segmentmins, segmentmaxs);
+ //else
+ // FIXME!!! this needs to handle skeletal!
+ }
+ }
+}