2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "mod_skeletal_animatevertices_generic.h"
26 #include "mod_skeletal_animatevertices_sse.h"
30 static qbool r_skeletal_use_sse_defined = false;
31 cvar_t r_skeletal_use_sse = {CF_CLIENT, "r_skeletal_use_sse", "1", "use SSE for skeletal model animation"};
33 cvar_t r_skeletal_debugbone = {CF_CLIENT, "r_skeletal_debugbone", "-1", "development cvar for testing skeletal model code"};
34 cvar_t r_skeletal_debugbonecomponent = {CF_CLIENT, "r_skeletal_debugbonecomponent", "3", "development cvar for testing skeletal model code"};
35 cvar_t r_skeletal_debugbonevalue = {CF_CLIENT, "r_skeletal_debugbonevalue", "100", "development cvar for testing skeletal model code"};
36 cvar_t r_skeletal_debugtranslatex = {CF_CLIENT, "r_skeletal_debugtranslatex", "1", "development cvar for testing skeletal model code"};
37 cvar_t r_skeletal_debugtranslatey = {CF_CLIENT, "r_skeletal_debugtranslatey", "1", "development cvar for testing skeletal model code"};
38 cvar_t r_skeletal_debugtranslatez = {CF_CLIENT, "r_skeletal_debugtranslatez", "1", "development cvar for testing skeletal model code"};
39 cvar_t mod_alias_supporttagscale = {CF_CLIENT | CF_SERVER, "mod_alias_supporttagscale", "1", "support scaling factors in bone/tag attachment matrices as supported by MD3"};
40 cvar_t mod_alias_force_animated = {CF_CLIENT | CF_SERVER, "mod_alias_force_animated", "", "if set to an non-empty string, overrides the is-animated flag of any alias models (for benchmarking)"};
42 float mod_md3_sin[320];
44 static size_t Mod_Skeletal_AnimateVertices_maxbonepose = 0;
45 static void *Mod_Skeletal_AnimateVertices_bonepose = NULL;
46 void Mod_Skeletal_FreeBuffers(void)
48 if(Mod_Skeletal_AnimateVertices_bonepose)
49 Mem_Free(Mod_Skeletal_AnimateVertices_bonepose);
50 Mod_Skeletal_AnimateVertices_maxbonepose = 0;
51 Mod_Skeletal_AnimateVertices_bonepose = NULL;
53 void *Mod_Skeletal_AnimateVertices_AllocBuffers(size_t nbytes)
55 if(Mod_Skeletal_AnimateVertices_maxbonepose < nbytes)
57 if(Mod_Skeletal_AnimateVertices_bonepose)
58 Mem_Free(Mod_Skeletal_AnimateVertices_bonepose);
59 Mod_Skeletal_AnimateVertices_bonepose = Z_Malloc(nbytes);
60 Mod_Skeletal_AnimateVertices_maxbonepose = nbytes;
62 return Mod_Skeletal_AnimateVertices_bonepose;
65 void Mod_Skeletal_BuildTransforms(const model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT bonepose, float * RESTRICT boneposerelative)
71 bonepose = (float * RESTRICT) Mod_Skeletal_AnimateVertices_AllocBuffers(sizeof(float[12]) * model->num_bones);
73 if (skeleton && !skeleton->relativetransforms)
76 // interpolate matrices
79 for (i = 0;i < model->num_bones;i++)
81 Matrix4x4_ToArray12FloatD3D(&skeleton->relativetransforms[i], m);
82 if (model->data_bones[i].parent >= 0)
83 R_ConcatTransforms(bonepose + model->data_bones[i].parent * 12, m, bonepose + i * 12);
85 memcpy(bonepose + i * 12, m, sizeof(m));
87 // create a relative deformation matrix to describe displacement
88 // from the base mesh, which is used by the actual weighting
89 R_ConcatTransforms(bonepose + i * 12, model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12);
94 for (i = 0;i < model->num_bones;i++)
96 // blend by transform each quaternion/translation into a dual-quaternion first, then blending
97 const short * RESTRICT firstpose7s = model->data_poses7s + 7 * (frameblend[0].subframe * model->num_bones + i);
98 float firstlerp = frameblend[0].lerp,
99 firsttx = firstpose7s[0], firstty = firstpose7s[1], firsttz = firstpose7s[2],
100 rx = firstpose7s[3] * firstlerp,
101 ry = firstpose7s[4] * firstlerp,
102 rz = firstpose7s[5] * firstlerp,
103 rw = firstpose7s[6] * firstlerp,
104 dx = firsttx*rw + firstty*rz - firsttz*ry,
105 dy = -firsttx*rz + firstty*rw + firsttz*rx,
106 dz = firsttx*ry - firstty*rx + firsttz*rw,
107 dw = -firsttx*rx - firstty*ry - firsttz*rz,
108 scale, sx, sy, sz, sw;
109 for (blends = 1;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
111 const short * RESTRICT blendpose7s = model->data_poses7s + 7 * (frameblend[blends].subframe * model->num_bones + i);
112 float blendlerp = frameblend[blends].lerp,
113 blendtx = blendpose7s[0], blendty = blendpose7s[1], blendtz = blendpose7s[2],
114 qx = blendpose7s[3], qy = blendpose7s[4], qz = blendpose7s[5], qw = blendpose7s[6];
115 if(rx*qx + ry*qy + rz*qz + rw*qw < 0) blendlerp = -blendlerp;
124 dx += blendtx*qw + blendty*qz - blendtz*qy;
125 dy += -blendtx*qz + blendty*qw + blendtz*qx;
126 dz += blendtx*qy - blendty*qx + blendtz*qw;
127 dw += -blendtx*qx - blendty*qy - blendtz*qz;
129 // generate a matrix from the dual-quaternion, implicitly normalizing it in the process
130 scale = 1.0f / (rx*rx + ry*ry + rz*rz + rw*rw);
135 m[0] = sw*rw + sx*rx - sy*ry - sz*rz;
136 m[1] = 2*(sx*ry - sw*rz);
137 m[2] = 2*(sx*rz + sw*ry);
138 m[3] = model->num_posescale*(dx*sw - dy*sz + dz*sy - dw*sx);
139 m[4] = 2*(sx*ry + sw*rz);
140 m[5] = sw*rw + sy*ry - sx*rx - sz*rz;
141 m[6] = 2*(sy*rz - sw*rx);
142 m[7] = model->num_posescale*(dx*sz + dy*sw - dz*sx - dw*sy);
143 m[8] = 2*(sx*rz - sw*ry);
144 m[9] = 2*(sy*rz + sw*rx);
145 m[10] = sw*rw + sz*rz - sx*rx - sy*ry;
146 m[11] = model->num_posescale*(dy*sx + dz*sw - dx*sy - dw*sz);
147 if (i == r_skeletal_debugbone.integer)
148 m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value;
149 m[3] *= r_skeletal_debugtranslatex.value;
150 m[7] *= r_skeletal_debugtranslatey.value;
151 m[11] *= r_skeletal_debugtranslatez.value;
152 if (model->data_bones[i].parent >= 0)
153 R_ConcatTransforms(bonepose + model->data_bones[i].parent * 12, m, bonepose + i * 12);
155 memcpy(bonepose + i * 12, m, sizeof(m));
156 // create a relative deformation matrix to describe displacement
157 // from the base mesh, which is used by the actual weighting
158 R_ConcatTransforms(bonepose + i * 12, model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12);
163 static void Mod_Skeletal_AnimateVertices(const 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)
166 if (!model->surfmesh.num_vertices)
169 if (!model->num_bones)
171 if (vertex3f) memcpy(vertex3f, model->surfmesh.data_vertex3f, model->surfmesh.num_vertices*sizeof(float[3]));
172 if (normal3f) memcpy(normal3f, model->surfmesh.data_normal3f, model->surfmesh.num_vertices*sizeof(float[3]));
173 if (svector3f) memcpy(svector3f, model->surfmesh.data_svector3f, model->surfmesh.num_vertices*sizeof(float[3]));
174 if (tvector3f) memcpy(tvector3f, model->surfmesh.data_tvector3f, model->surfmesh.num_vertices*sizeof(float[3]));
179 if(r_skeletal_use_sse_defined)
180 if(r_skeletal_use_sse.integer)
182 Mod_Skeletal_AnimateVertices_SSE(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f);
186 Mod_Skeletal_AnimateVertices_Generic(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f);
189 void Mod_AliasInit (void)
192 Cvar_RegisterVariable(&r_skeletal_debugbone);
193 Cvar_RegisterVariable(&r_skeletal_debugbonecomponent);
194 Cvar_RegisterVariable(&r_skeletal_debugbonevalue);
195 Cvar_RegisterVariable(&r_skeletal_debugtranslatex);
196 Cvar_RegisterVariable(&r_skeletal_debugtranslatey);
197 Cvar_RegisterVariable(&r_skeletal_debugtranslatez);
198 Cvar_RegisterVariable(&mod_alias_supporttagscale);
199 Cvar_RegisterVariable(&mod_alias_force_animated);
200 for (i = 0;i < 320;i++)
201 mod_md3_sin[i] = sin(i * M_PI * 2.0f / 256.0);
205 Con_Printf("Skeletal animation uses SSE code path\n");
206 r_skeletal_use_sse_defined = true;
207 Cvar_RegisterVariable(&r_skeletal_use_sse);
210 Con_Printf("Skeletal animation uses generic code path (SSE disabled or not detected)\n");
212 Con_Printf("Skeletal animation uses generic code path (SSE not compiled in)\n");
216 static int Mod_Skeletal_AddBlend(model_t *model, const blendweights_t *newweights)
219 blendweights_t *weights;
220 if(!newweights->influence[1])
221 return newweights->index[0];
222 weights = model->surfmesh.data_blendweights;
223 for (i = 0;i < model->surfmesh.num_blends;i++, weights++)
225 if (!memcmp(weights, newweights, sizeof(blendweights_t)))
226 return model->num_bones + i;
228 model->surfmesh.num_blends++;
229 memcpy(weights, newweights, sizeof(blendweights_t));
230 return model->num_bones + i;
233 static int Mod_Skeletal_CompressBlend(model_t *model, const int *newindex, const float *newinfluence)
237 blendweights_t newweights;
241 for (i = 0;i < 4;i++)
242 scale += newinfluence[i];
243 scale = 255.0f / scale;
245 for (i = 0;i < 4;i++)
247 newweights.index[i] = newindex[i];
248 newweights.influence[i] = (unsigned char)(newinfluence[i] * scale);
249 total += newweights.influence[i];
253 for (i = 0;i < 4;i++)
255 if(newweights.influence[i] > 0 && total > 255)
257 newweights.influence[i]--;
264 for (i = 0; i < 4;i++)
266 if(newweights.influence[i] < 255 && total < 255)
268 newweights.influence[i]++;
273 return Mod_Skeletal_AddBlend(model, &newweights);
276 static void Mod_MD3_AnimateVertices(const 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)
279 int i, numblends, blendnum;
280 int numverts = model->surfmesh.num_vertices;
282 for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
284 //VectorMA(translate, model->surfmesh.num_morphmdlframetranslate, frameblend[blendnum].lerp, translate);
285 if (frameblend[blendnum].lerp > 0)
286 numblends = blendnum + 1;
288 // special case for the first blend because it avoids some adds and the need to memset the arrays first
289 for (blendnum = 0;blendnum < numblends;blendnum++)
291 const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].subframe;
294 float scale = frameblend[blendnum].lerp * (1.0f / 64.0f);
297 for (i = 0;i < numverts;i++)
299 vertex3f[i * 3 + 0] = verts[i].origin[0] * scale;
300 vertex3f[i * 3 + 1] = verts[i].origin[1] * scale;
301 vertex3f[i * 3 + 2] = verts[i].origin[2] * scale;
306 for (i = 0;i < numverts;i++)
308 vertex3f[i * 3 + 0] += verts[i].origin[0] * scale;
309 vertex3f[i * 3 + 1] += verts[i].origin[1] * scale;
310 vertex3f[i * 3 + 2] += verts[i].origin[2] * scale;
314 // the yaw and pitch stored in md3 models are 8bit quantized angles
315 // (0-255), and as such a lookup table is very well suited to
316 // decoding them, and since cosine is equivalent to sine with an
317 // extra 45 degree rotation, this uses one lookup table for both
318 // sine and cosine with a +64 bias to get cosine.
321 float lerp = frameblend[blendnum].lerp;
324 for (i = 0;i < numverts;i++)
326 normal3f[i * 3 + 0] = mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch ] * lerp;
327 normal3f[i * 3 + 1] = mod_md3_sin[verts[i].yaw ] * mod_md3_sin[verts[i].pitch ] * lerp;
328 normal3f[i * 3 + 2] = mod_md3_sin[verts[i].pitch + 64] * lerp;
333 for (i = 0;i < numverts;i++)
335 normal3f[i * 3 + 0] += mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch ] * lerp;
336 normal3f[i * 3 + 1] += mod_md3_sin[verts[i].yaw ] * mod_md3_sin[verts[i].pitch ] * lerp;
337 normal3f[i * 3 + 2] += mod_md3_sin[verts[i].pitch + 64] * lerp;
343 const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
344 float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
347 for (i = 0;i < numverts;i++, texvecvert++)
349 VectorScale(texvecvert->svec, f, svector3f + i*3);
350 VectorScale(texvecvert->tvec, f, tvector3f + i*3);
355 for (i = 0;i < numverts;i++, texvecvert++)
357 VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
358 VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
364 static void Mod_MDL_AnimateVertices(const 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)
367 int i, numblends, blendnum;
368 int numverts = model->surfmesh.num_vertices;
370 VectorClear(translate);
372 // blend the frame translates to avoid redundantly doing so on each vertex
373 // (a bit of a brain twister but it works)
374 for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
376 if (model->surfmesh.data_morphmd2framesize6f)
377 VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6 + 3, translate);
379 VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.num_morphmdlframetranslate, translate);
380 if (frameblend[blendnum].lerp > 0)
381 numblends = blendnum + 1;
383 // special case for the first blend because it avoids some adds and the need to memset the arrays first
384 for (blendnum = 0;blendnum < numblends;blendnum++)
386 const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].subframe;
390 if (model->surfmesh.data_morphmd2framesize6f)
391 VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6, frameblend[blendnum].lerp, scale);
393 VectorScale(model->surfmesh.num_morphmdlframescale, frameblend[blendnum].lerp, scale);
396 for (i = 0;i < numverts;i++)
398 vertex3f[i * 3 + 0] = translate[0] + verts[i].v[0] * scale[0];
399 vertex3f[i * 3 + 1] = translate[1] + verts[i].v[1] * scale[1];
400 vertex3f[i * 3 + 2] = translate[2] + verts[i].v[2] * scale[2];
405 for (i = 0;i < numverts;i++)
407 vertex3f[i * 3 + 0] += verts[i].v[0] * scale[0];
408 vertex3f[i * 3 + 1] += verts[i].v[1] * scale[1];
409 vertex3f[i * 3 + 2] += verts[i].v[2] * scale[2];
413 // the vertex normals in mdl models are an index into a table of
414 // 162 unique values, this very crude quantization reduces the
415 // vertex normal to only one byte, which saves a lot of space but
416 // also makes lighting pretty coarse
419 float lerp = frameblend[blendnum].lerp;
422 for (i = 0;i < numverts;i++)
424 const float *vn = m_bytenormals[verts[i].lightnormalindex];
425 VectorScale(vn, lerp, normal3f + i*3);
430 for (i = 0;i < numverts;i++)
432 const float *vn = m_bytenormals[verts[i].lightnormalindex];
433 VectorMA(normal3f + i*3, lerp, vn, normal3f + i*3);
439 const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
440 float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
443 for (i = 0;i < numverts;i++, texvecvert++)
445 VectorScale(texvecvert->svec, f, svector3f + i*3);
446 VectorScale(texvecvert->tvec, f, tvector3f + i*3);
451 for (i = 0;i < numverts;i++, texvecvert++)
453 VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
454 VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
461 int Mod_Alias_GetTagMatrix(const model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, matrix4x4_t *outmatrix)
464 matrix4x4_t parentbonematrix;
465 matrix4x4_t tempbonematrix;
466 matrix4x4_t bonematrix;
467 matrix4x4_t blendmatrix;
474 *outmatrix = identitymatrix;
475 if (skeleton && skeleton->relativetransforms)
477 if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
479 *outmatrix = skeleton->relativetransforms[tagindex];
480 while ((tagindex = model->data_bones[tagindex].parent) >= 0)
483 Matrix4x4_Concat(outmatrix, &skeleton->relativetransforms[tagindex], &temp);
486 else if (model->num_bones)
488 if (tagindex < 0 || tagindex >= model->num_bones)
490 Matrix4x4_Clear(&blendmatrix);
491 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
493 lerp = frameblend[blendindex].lerp;
494 Matrix4x4_FromBonePose7s(&bonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + tagindex));
495 parenttagindex = tagindex;
496 while ((parenttagindex = model->data_bones[parenttagindex].parent) >= 0)
498 Matrix4x4_FromBonePose7s(&parentbonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + parenttagindex));
499 tempbonematrix = bonematrix;
500 Matrix4x4_Concat(&bonematrix, &parentbonematrix, &tempbonematrix);
502 Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
504 *outmatrix = blendmatrix;
506 else if (model->num_tags)
508 if (tagindex < 0 || tagindex >= model->num_tags)
510 for (k = 0;k < 12;k++)
512 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
514 lerp = frameblend[blendindex].lerp;
515 input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
516 for (k = 0;k < 12;k++)
517 blendtag[k] += input[k] * lerp;
519 Matrix4x4_FromArray12FloatGL(outmatrix, blendtag);
522 if(!mod_alias_supporttagscale.integer)
523 Matrix4x4_Normalize3(outmatrix, outmatrix);
528 int Mod_Alias_GetExtendedTagInfoForIndex(const 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)
533 matrix4x4_t bonematrix;
534 matrix4x4_t blendmatrix;
538 if (skeleton && skeleton->relativetransforms)
540 if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
542 *parentindex = skeleton->model->data_bones[tagindex].parent;
543 *tagname = skeleton->model->data_bones[tagindex].name;
544 *tag_localmatrix = skeleton->relativetransforms[tagindex];
547 else if (model->num_bones)
549 if (tagindex < 0 || tagindex >= model->num_bones)
551 *parentindex = model->data_bones[tagindex].parent;
552 *tagname = model->data_bones[tagindex].name;
553 Matrix4x4_Clear(&blendmatrix);
554 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
556 lerp = frameblend[blendindex].lerp;
557 Matrix4x4_FromBonePose7s(&bonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + tagindex));
558 Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
560 *tag_localmatrix = blendmatrix;
563 else if (model->num_tags)
565 if (tagindex < 0 || tagindex >= model->num_tags)
568 *tagname = model->data_tags[tagindex].name;
569 for (k = 0;k < 12;k++)
571 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
573 lerp = frameblend[blendindex].lerp;
574 input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
575 for (k = 0;k < 12;k++)
576 blendtag[k] += input[k] * lerp;
578 Matrix4x4_FromArray12FloatGL(tag_localmatrix, blendtag);
585 int Mod_Alias_GetTagIndexForName(const model_t *model, unsigned int skin, const char *tagname)
588 if(skin >= (unsigned int)model->numskins)
590 if (model->num_bones)
591 for (i = 0;i < model->num_bones;i++)
592 if (!strcasecmp(tagname, model->data_bones[i].name))
595 for (i = 0;i < model->num_tags;i++)
596 if (!strcasecmp(tagname, model->data_tags[i].name))
601 static void Mod_BuildBaseBonePoses(void)
604 matrix4x4_t *basebonepose;
605 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
606 matrix4x4_t bonematrix;
607 matrix4x4_t tempbonematrix;
608 if (!loadmodel->num_bones)
610 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
611 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
613 Matrix4x4_FromBonePose7s(&bonematrix, loadmodel->num_posescale, loadmodel->data_poses7s + 7 * boneindex);
614 if (loadmodel->data_bones[boneindex].parent >= 0)
616 tempbonematrix = bonematrix;
617 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
619 basebonepose[boneindex] = bonematrix;
620 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
621 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
623 Mem_Free(basebonepose);
626 static qbool Mod_Alias_CalculateBoundingBox(void)
629 qbool firstvertex = true;
630 float dist, yawradius, radius;
632 qbool isanimated = false;
633 VectorClear(loadmodel->normalmins);
634 VectorClear(loadmodel->normalmaxs);
637 if (loadmodel->AnimateVertices)
639 float *vertex3f, *refvertex3f;
640 frameblend_t frameblend[MAX_FRAMEBLENDS];
641 memset(frameblend, 0, sizeof(frameblend));
642 frameblend[0].lerp = 1;
643 vertex3f = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]) * 2);
645 for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++)
647 loadmodel->AnimateVertices(loadmodel, frameblend, NULL, vertex3f, NULL, NULL, NULL);
650 // make a copy of the first frame for comparing all others
651 refvertex3f = vertex3f + loadmodel->surfmesh.num_vertices * 3;
652 memcpy(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
656 if (!isanimated && memcmp(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3])))
659 for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
664 VectorCopy(v, loadmodel->normalmins);
665 VectorCopy(v, loadmodel->normalmaxs);
669 if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
670 if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
671 if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
672 if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
673 if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
674 if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
676 dist = v[0] * v[0] + v[1] * v[1];
677 if (yawradius < dist)
689 for (vnum = 0, v = loadmodel->surfmesh.data_vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
694 VectorCopy(v, loadmodel->normalmins);
695 VectorCopy(v, loadmodel->normalmaxs);
699 if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
700 if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
701 if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
702 if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
703 if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
704 if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
706 dist = v[0] * v[0] + v[1] * v[1];
707 if (yawradius < dist)
714 radius = sqrt(radius);
715 yawradius = sqrt(yawradius);
716 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius;
717 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = yawradius;
718 loadmodel->yawmins[2] = loadmodel->normalmins[2];
719 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
720 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
721 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
722 loadmodel->radius = radius;
723 loadmodel->radius2 = radius * radius;
727 static void Mod_Alias_MorphMesh_CompileFrames(void)
730 frameblend_t frameblend[MAX_FRAMEBLENDS];
731 unsigned char *datapointer;
732 memset(frameblend, 0, sizeof(frameblend));
733 frameblend[0].lerp = 1;
734 datapointer = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * (sizeof(float[3]) * 4 + loadmodel->surfmesh.num_morphframes * sizeof(texvecvertex_t)));
735 loadmodel->surfmesh.data_vertex3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
736 loadmodel->surfmesh.data_svector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
737 loadmodel->surfmesh.data_tvector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
738 loadmodel->surfmesh.data_normal3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
739 loadmodel->surfmesh.data_morphtexvecvertex = (texvecvertex_t *)datapointer;datapointer += loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices * sizeof(texvecvertex_t);
740 // this counts down from the last frame to the first so that the final data in surfmesh is for frame zero (which is what the renderer expects to be there)
741 for (i = loadmodel->surfmesh.num_morphframes-1;i >= 0;i--)
743 frameblend[0].subframe = i;
744 loadmodel->AnimateVertices(loadmodel, frameblend, NULL, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_normal3f, NULL, NULL);
745 Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
746 // encode the svector and tvector in 3 byte format for permanent storage
747 for (j = 0;j < loadmodel->surfmesh.num_vertices;j++)
749 VectorScaleCast(loadmodel->surfmesh.data_svector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].svec);
750 VectorScaleCast(loadmodel->surfmesh.data_tvector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].tvec);
755 static void Mod_MDLMD2MD3_TraceLine(model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
758 float segmentmins[3], segmentmaxs[3];
760 float vertex3fbuf[1024 * 3];
761 float *vertex3f = vertex3fbuf;
762 float *freevertex3f = NULL;
763 // for static cases we can just call CollisionBIH which is much faster
764 if ((frameblend == NULL || (frameblend[0].subframe == 0 && frameblend[1].lerp == 0)) && (skeleton == NULL || skeleton->relativetransforms == NULL))
766 Mod_CollisionBIH_TraceLine(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
769 memset(trace, 0, sizeof(*trace));
771 trace->hitsupercontentsmask = hitsupercontentsmask;
772 trace->skipsupercontentsmask = skipsupercontentsmask;
773 trace->skipmaterialflagsmask = skipmaterialflagsmask;
774 segmentmins[0] = min(start[0], end[0]) - 1;
775 segmentmins[1] = min(start[1], end[1]) - 1;
776 segmentmins[2] = min(start[2], end[2]) - 1;
777 segmentmaxs[0] = max(start[0], end[0]) + 1;
778 segmentmaxs[1] = max(start[1], end[1]) + 1;
779 segmentmaxs[2] = max(start[2], end[2]) + 1;
780 if (frameblend == NULL || frameblend[0].subframe != 0 || frameblend[0].lerp != 0 || skeleton != NULL)
782 if (model->surfmesh.num_vertices > 1024)
783 vertex3f = freevertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
784 model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
787 vertex3f = model->surfmesh.data_vertex3f;
788 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
789 Collision_TraceLineTriangleMeshFloat(trace, start, end, surface->num_triangles, model->surfmesh.data_element3i + 3 * surface->num_firsttriangle, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
791 Mem_Free(freevertex3f);
794 static void Mod_MDLMD2MD3_TraceBox(model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
797 vec3_t shiftstart, shiftend;
798 float segmentmins[3], segmentmaxs[3];
800 float vertex3fbuf[1024*3];
801 float *vertex3f = vertex3fbuf;
802 colboxbrushf_t thisbrush_start, thisbrush_end;
803 vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
805 if (VectorCompare(boxmins, boxmaxs))
807 VectorAdd(start, boxmins, shiftstart);
808 VectorAdd(end, boxmins, shiftend);
809 Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
810 VectorSubtract(trace->endpos, boxmins, trace->endpos);
814 // for static cases we can just call CollisionBIH which is much faster
815 if ((frameblend == NULL || (frameblend[0].subframe == 0 && frameblend[1].lerp == 0)) && (skeleton == NULL || skeleton->relativetransforms == NULL))
817 Mod_CollisionBIH_TraceBox(model, frameblend, skeleton, trace, start, boxmins, boxmaxs, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
821 // box trace, performed as brush trace
822 memset(trace, 0, sizeof(*trace));
824 trace->hitsupercontentsmask = hitsupercontentsmask;
825 trace->skipsupercontentsmask = skipsupercontentsmask;
826 trace->skipmaterialflagsmask = skipmaterialflagsmask;
827 if (model->surfmesh.num_vertices > 1024)
828 vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
829 segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1;
830 segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1;
831 segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1;
832 segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1;
833 segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1;
834 segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1;
835 VectorAdd(start, boxmins, boxstartmins);
836 VectorAdd(start, boxmaxs, boxstartmaxs);
837 VectorAdd(end, boxmins, boxendmins);
838 VectorAdd(end, boxmaxs, boxendmaxs);
839 Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL);
840 Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL);
841 model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
842 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
843 Collision_TraceBrushTriangleMeshFloat(trace, &thisbrush_start.brush, &thisbrush_end.brush, surface->num_triangles, model->surfmesh.data_element3i + 3 * surface->num_firsttriangle, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
844 if (vertex3f != vertex3fbuf)
848 static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap)
851 for (i = 0;i < inverts;i++)
853 if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
855 j = vertremap[i]; // not onseam
858 j = vertremap[i+inverts]; // onseam
864 static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *vertremap)
866 int i, f, pose, groupframes;
868 daliasframetype_t *pframetype;
869 daliasframe_t *pinframe;
870 daliasgroup_t *group;
871 daliasinterval_t *intervals;
874 scene = loadmodel->animscenes;
875 for (f = 0;f < loadmodel->numframes;f++)
877 pframetype = (daliasframetype_t *)datapointer;
878 datapointer += sizeof(daliasframetype_t);
879 if (LittleLong (pframetype->type) == ALIAS_SINGLE)
881 // a single frame is still treated as a group
888 group = (daliasgroup_t *)datapointer;
889 datapointer += sizeof(daliasgroup_t);
890 groupframes = LittleLong (group->numframes);
892 // intervals (time per frame)
893 intervals = (daliasinterval_t *)datapointer;
894 datapointer += sizeof(daliasinterval_t) * groupframes;
896 interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
897 if (interval < 0.01f)
899 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
904 // get scene name from first frame
905 pinframe = (daliasframe_t *)datapointer;
907 dp_strlcpy(scene->name, pinframe->name, sizeof(scene->name));
908 scene->firstframe = pose;
909 scene->framecount = groupframes;
910 scene->framerate = 1.0f / interval;
915 for (i = 0;i < groupframes;i++)
917 datapointer += sizeof(daliasframe_t);
918 Mod_ConvertAliasVerts(inverts, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphmdlvertex + pose * loadmodel->surfmesh.num_vertices, vertremap);
919 datapointer += sizeof(trivertx_t) * inverts;
925 void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
928 char stripbuf[MAX_QPATH];
929 skinfileitem_t *skinfileitem;
930 if(developer_extra.integer)
931 Con_DPrintf("Looking up texture for %s (default: %s)\n", meshname, shadername);
934 // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
935 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
937 memset(skin, 0, sizeof(*skin));
939 for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
941 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
942 if (!strcmp(skinfileitem->name, meshname))
944 Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf));
945 if(developer_extra.integer)
946 Con_DPrintf("--> got %s from skin file\n", stripbuf);
947 Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
953 // don't render unmentioned meshes
954 Mod_LoadCustomMaterial(loadmodel->mempool, skin, meshname, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing());
955 if(developer_extra.integer)
956 Con_DPrintf("--> skipping\n");
957 skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW;
963 if(developer_extra.integer)
964 Con_DPrintf("--> using default\n");
965 Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf));
966 Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
969 extern cvar_t r_nolerp_list;
970 #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);
971 #define BOUNDF(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%f exceeds %f - %f)", loadmodel->name, VALUE, MIN, MAX);
972 void Mod_IDP0_Load(model_t *mod, void *buffer, void *bufferend)
974 int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
975 float scales, scalet, interval;
979 stvert_t *pinstverts;
980 dtriangle_t *pintriangles;
981 daliasskintype_t *pinskintype;
982 daliasskingroup_t *pinskingroup;
983 daliasskininterval_t *pinskinintervals;
984 daliasframetype_t *pinframetype;
985 daliasgroup_t *pinframegroup;
986 unsigned char *datapointer, *startframes, *startskins;
987 char name[MAX_QPATH];
988 skinframe_t *tempskinframe;
989 animscene_t *tempskinscenes;
990 texture_t *tempaliasskins;
992 int *vertonseam, *vertremap;
993 skinfile_t *skinfiles;
995 datapointer = (unsigned char *)buffer;
996 pinmodel = (mdl_t *)datapointer;
997 datapointer += sizeof(mdl_t);
999 version = LittleLong (pinmodel->version);
1000 if (version != ALIAS_VERSION)
1001 Host_Error ("%s has wrong version number (%i should be %i)",
1002 loadmodel->name, version, ALIAS_VERSION);
1004 loadmodel->modeldatatypestring = "MDL";
1006 loadmodel->type = mod_alias;
1007 loadmodel->Draw = R_Mod_Draw;
1008 loadmodel->DrawDepth = R_Mod_DrawDepth;
1009 loadmodel->DrawDebug = R_Mod_DrawDebug;
1010 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1011 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1012 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1013 loadmodel->DrawLight = R_Mod_DrawLight;
1014 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1015 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1016 // FIXME add TraceBrush!
1017 loadmodel->PointSuperContents = NULL;
1018 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1020 loadmodel->num_surfaces = 1;
1021 loadmodel->submodelsurfaces_start = 0;
1022 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1023 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
1024 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1025 loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1026 loadmodel->modelsurfaces_sorted[0] = 0;
1028 loadmodel->numskins = LittleLong(pinmodel->numskins);
1029 BOUNDI(loadmodel->numskins,0,65536);
1030 skinwidth = LittleLong (pinmodel->skinwidth);
1031 BOUNDI(skinwidth,0,65536);
1032 skinheight = LittleLong (pinmodel->skinheight);
1033 BOUNDI(skinheight,0,65536);
1034 numverts = LittleLong(pinmodel->numverts);
1035 BOUNDI(numverts,0,65536);
1036 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
1037 BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
1038 loadmodel->numframes = LittleLong(pinmodel->numframes);
1039 BOUNDI(loadmodel->numframes,0,65536);
1040 loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
1041 BOUNDI((int)loadmodel->synctype,0,2);
1042 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1043 i = LittleLong (pinmodel->flags);
1044 loadmodel->effects = (((unsigned)i & 255) << 24) | (i & 0x00FFFF00);
1046 if (strstr(r_nolerp_list.string, loadmodel->name))
1047 loadmodel->nolerp = true;
1049 for (i = 0;i < 3;i++)
1051 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
1052 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
1055 startskins = datapointer;
1057 for (i = 0;i < loadmodel->numskins;i++)
1059 pinskintype = (daliasskintype_t *)datapointer;
1060 datapointer += sizeof(daliasskintype_t);
1061 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
1065 pinskingroup = (daliasskingroup_t *)datapointer;
1066 datapointer += sizeof(daliasskingroup_t);
1067 groupskins = LittleLong(pinskingroup->numskins);
1068 datapointer += sizeof(daliasskininterval_t) * groupskins;
1071 for (j = 0;j < groupskins;j++)
1073 datapointer += skinwidth * skinheight;
1078 pinstverts = (stvert_t *)datapointer;
1079 datapointer += sizeof(stvert_t) * numverts;
1081 pintriangles = (dtriangle_t *)datapointer;
1082 datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
1084 startframes = datapointer;
1085 loadmodel->surfmesh.num_morphframes = 0;
1086 for (i = 0;i < loadmodel->numframes;i++)
1088 pinframetype = (daliasframetype_t *)datapointer;
1089 datapointer += sizeof(daliasframetype_t);
1090 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1094 pinframegroup = (daliasgroup_t *)datapointer;
1095 datapointer += sizeof(daliasgroup_t);
1096 groupframes = LittleLong(pinframegroup->numframes);
1097 datapointer += sizeof(daliasinterval_t) * groupframes;
1100 for (j = 0;j < groupframes;j++)
1102 datapointer += sizeof(daliasframe_t);
1103 datapointer += sizeof(trivertx_t) * numverts;
1104 loadmodel->surfmesh.num_morphframes++;
1107 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1109 // store texture coordinates into temporary array, they will be stored
1110 // after usage is determined (triangle data)
1111 vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1112 vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1113 vertonseam = vertremap + numverts * 2;
1115 scales = 1.0 / skinwidth;
1116 scalet = 1.0 / skinheight;
1117 for (i = 0;i < numverts;i++)
1119 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1120 vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales;
1121 vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet;
1122 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1123 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1126 // load triangle data
1127 loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1129 // read the triangle elements
1130 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1131 for (j = 0;j < 3;j++)
1132 loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1133 // validate (note numverts is used because this is the original data)
1134 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, NULL, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1135 // now butcher the elements according to vertonseam and tri->facesfront
1136 // and then compact the vertex set to remove duplicates
1137 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1138 if (!LittleLong(pintriangles[i].facesfront)) // backface
1139 for (j = 0;j < 3;j++)
1140 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1141 loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1143 // (this uses vertremap to count usage to save some memory)
1144 for (i = 0;i < numverts*2;i++)
1146 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1147 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1148 // build remapping table and compact array
1149 loadmodel->surfmesh.num_vertices = 0;
1150 for (i = 0;i < numverts*2;i++)
1154 vertremap[i] = loadmodel->surfmesh.num_vertices;
1155 vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1156 vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1157 loadmodel->surfmesh.num_vertices++;
1160 vertremap[i] = -1; // not used at all
1162 // remap the elements to the new vertex set
1163 for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1164 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1165 // store the texture coordinates
1166 loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1167 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1169 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1170 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1173 // generate ushort elements array if possible
1174 if (loadmodel->surfmesh.num_vertices <= 65536)
1175 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1176 if (loadmodel->surfmesh.data_element3s)
1177 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1178 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1181 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1182 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1183 Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1184 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1185 Mod_Alias_MorphMesh_CompileFrames();
1188 Mem_Free(vertremap);
1191 skinfiles = Mod_LoadSkinFiles();
1194 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1195 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1196 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1197 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1198 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1199 Mod_FreeSkinFiles(skinfiles);
1200 for (i = 0;i < loadmodel->numskins;i++)
1202 loadmodel->skinscenes[i].firstframe = i;
1203 loadmodel->skinscenes[i].framecount = 1;
1204 loadmodel->skinscenes[i].loop = true;
1205 loadmodel->skinscenes[i].framerate = 10;
1210 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1211 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1212 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1213 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1215 datapointer = startskins;
1216 for (i = 0;i < loadmodel->numskins;i++)
1218 pinskintype = (daliasskintype_t *)datapointer;
1219 datapointer += sizeof(daliasskintype_t);
1221 if (pinskintype->type == ALIAS_SKIN_SINGLE)
1228 pinskingroup = (daliasskingroup_t *)datapointer;
1229 datapointer += sizeof(daliasskingroup_t);
1231 groupskins = LittleLong (pinskingroup->numskins);
1233 pinskinintervals = (daliasskininterval_t *)datapointer;
1234 datapointer += sizeof(daliasskininterval_t) * groupskins;
1236 interval = LittleFloat(pinskinintervals[0].interval);
1237 if (interval < 0.01f)
1239 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1244 dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1245 loadmodel->skinscenes[i].firstframe = totalskins;
1246 loadmodel->skinscenes[i].framecount = groupskins;
1247 loadmodel->skinscenes[i].framerate = 1.0f / interval;
1248 loadmodel->skinscenes[i].loop = true;
1250 for (j = 0;j < groupskins;j++)
1253 dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1255 dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1256 if (!Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, false, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL))
1257 Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadInternalQuake(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight));
1258 datapointer += skinwidth * skinheight;
1262 // check for skins that don't exist in the model, but do exist as external images
1263 // (this was added because yummyluv kept pestering me about support for it)
1264 // TODO: support shaders here?
1267 dpsnprintf(name, sizeof(name), "%s_%i", loadmodel->name, loadmodel->numskins);
1268 tempskinframe = R_SkinFrame_LoadExternal(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false, false);
1271 // expand the arrays to make room
1272 tempskinscenes = loadmodel->skinscenes;
1273 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1274 memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1275 Mem_Free(tempskinscenes);
1277 tempaliasskins = loadmodel->data_textures;
1278 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1279 memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1280 Mem_Free(tempaliasskins);
1282 // store the info about the new skin
1283 Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, tempskinframe);
1284 dp_strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1285 loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1286 loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1287 loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1288 loadmodel->skinscenes[loadmodel->numskins].loop = true;
1290 //increase skin counts
1291 loadmodel->num_textures++;
1292 loadmodel->numskins++;
1295 // fix up the pointers since they are pointing at the old textures array
1296 // FIXME: this is a hack!
1297 for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1298 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1302 surface = loadmodel->data_surfaces;
1303 surface->texture = loadmodel->data_textures;
1304 surface->num_firsttriangle = 0;
1305 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1306 surface->num_firstvertex = 0;
1307 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1309 if(mod_alias_force_animated.string[0])
1310 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1312 // Always make a BIH for the first frame, we can use it where possible.
1313 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1314 if (!loadmodel->surfmesh.isanimated)
1316 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1317 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1318 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1319 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1320 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1324 void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend)
1326 int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1327 float iskinwidth, iskinheight;
1328 unsigned char *data;
1329 msurface_t *surface;
1331 unsigned char *base, *datapointer;
1332 md2frame_t *pinframe;
1334 md2triangle_t *intri;
1335 unsigned short *inst;
1336 struct md2verthash_s
1338 struct md2verthash_s *next;
1342 *hash, **md2verthash, *md2verthashdata;
1343 skinfile_t *skinfiles;
1345 pinmodel = (md2_t *)buffer;
1346 base = (unsigned char *)buffer;
1348 version = LittleLong (pinmodel->version);
1349 if (version != MD2ALIAS_VERSION)
1350 Host_Error ("%s has wrong version number (%i should be %i)",
1351 loadmodel->name, version, MD2ALIAS_VERSION);
1353 loadmodel->modeldatatypestring = "MD2";
1355 loadmodel->type = mod_alias;
1356 loadmodel->Draw = R_Mod_Draw;
1357 loadmodel->DrawDepth = R_Mod_DrawDepth;
1358 loadmodel->DrawDebug = R_Mod_DrawDebug;
1359 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1360 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1361 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1362 loadmodel->DrawLight = R_Mod_DrawLight;
1363 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1364 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1365 loadmodel->PointSuperContents = NULL;
1366 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1368 if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1369 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1370 if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1371 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1372 if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1373 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1374 if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1375 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1377 end = LittleLong(pinmodel->ofs_end);
1378 if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1379 Host_Error ("%s is not a valid model", loadmodel->name);
1380 if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1381 Host_Error ("%s is not a valid model", loadmodel->name);
1382 if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1383 Host_Error ("%s is not a valid model", loadmodel->name);
1384 if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1385 Host_Error ("%s is not a valid model", loadmodel->name);
1386 if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1387 Host_Error ("%s is not a valid model", loadmodel->name);
1389 loadmodel->numskins = LittleLong(pinmodel->num_skins);
1390 numxyz = LittleLong(pinmodel->num_xyz);
1391 numst = LittleLong(pinmodel->num_st);
1392 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1393 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1394 loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1395 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1396 skinwidth = LittleLong(pinmodel->skinwidth);
1397 skinheight = LittleLong(pinmodel->skinheight);
1398 iskinwidth = 1.0f / skinwidth;
1399 iskinheight = 1.0f / skinheight;
1401 loadmodel->num_surfaces = 1;
1402 loadmodel->submodelsurfaces_start = 0;
1403 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1404 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->numframes * sizeof(animscene_t) + loadmodel->numframes * sizeof(float[6]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]));
1405 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1406 loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1407 loadmodel->modelsurfaces_sorted[0] = 0;
1408 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1409 loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1410 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1412 loadmodel->synctype = ST_RAND;
1415 inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1416 skinfiles = Mod_LoadSkinFiles();
1419 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1420 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1421 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1422 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1423 Mod_FreeSkinFiles(skinfiles);
1425 else if (loadmodel->numskins)
1427 // skins found (most likely not a player model)
1428 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1429 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1430 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1431 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1432 Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
1436 // no skins (most likely a player model)
1437 loadmodel->numskins = 1;
1438 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1439 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1440 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1441 Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures, loadmodel->name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing());
1444 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1445 for (i = 0;i < loadmodel->numskins;i++)
1447 loadmodel->skinscenes[i].firstframe = i;
1448 loadmodel->skinscenes[i].framecount = 1;
1449 loadmodel->skinscenes[i].loop = true;
1450 loadmodel->skinscenes[i].framerate = 10;
1453 // load the triangles and stvert data
1454 inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1455 intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1456 md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1457 md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1458 // swap the triangle list
1459 loadmodel->surfmesh.num_vertices = 0;
1460 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1462 for (j = 0;j < 3;j++)
1464 xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1465 st = (unsigned short) LittleShort (intri[i].index_st[j]);
1468 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1473 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1476 hashindex = (xyz * 256 + st) & 65535;
1477 for (hash = md2verthash[hashindex];hash;hash = hash->next)
1478 if (hash->xyz == xyz && hash->st == st)
1482 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1485 hash->next = md2verthash[hashindex];
1486 md2verthash[hashindex] = hash;
1488 loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1492 vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1493 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t));
1494 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1495 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1496 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1499 hash = md2verthashdata + i;
1500 vertremap[i] = hash->xyz;
1501 sts = LittleShort(inst[hash->st*2+0]);
1502 stt = LittleShort(inst[hash->st*2+1]);
1503 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1505 Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1509 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1510 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1513 Mem_Free(md2verthash);
1514 Mem_Free(md2verthashdata);
1516 // generate ushort elements array if possible
1517 if (loadmodel->surfmesh.num_vertices <= 65536)
1518 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1519 if (loadmodel->surfmesh.data_element3s)
1520 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1521 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1524 datapointer = (base + LittleLong(pinmodel->ofs_frames));
1525 for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1530 pinframe = (md2frame_t *)datapointer;
1531 datapointer += sizeof(md2frame_t);
1532 // store the frame scale/translate into the appropriate array
1533 for (j = 0;j < 3;j++)
1535 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1536 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1538 // convert the vertices
1539 v = (trivertx_t *)datapointer;
1540 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1541 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1542 out[k] = v[vertremap[k]];
1543 datapointer += numxyz * sizeof(trivertx_t);
1545 dp_strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1546 loadmodel->animscenes[i].firstframe = i;
1547 loadmodel->animscenes[i].framecount = 1;
1548 loadmodel->animscenes[i].framerate = 10;
1549 loadmodel->animscenes[i].loop = true;
1552 Mem_Free(vertremap);
1554 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1555 Mod_Alias_MorphMesh_CompileFrames();
1556 if(mod_alias_force_animated.string[0])
1557 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1559 surface = loadmodel->data_surfaces;
1560 surface->texture = loadmodel->data_textures;
1561 surface->num_firsttriangle = 0;
1562 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1563 surface->num_firstvertex = 0;
1564 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1566 // Always make a BIH for the first frame, we can use it where possible.
1567 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1568 if (!loadmodel->surfmesh.isanimated)
1570 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1571 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1572 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1573 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1574 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1578 void Mod_IDP3_Load(model_t *mod, void *buffer, void *bufferend)
1580 int i, j, k, version, meshvertices, meshtriangles;
1581 unsigned char *data;
1582 msurface_t *surface;
1583 md3modelheader_t *pinmodel;
1584 md3frameinfo_t *pinframe;
1587 skinfile_t *skinfiles;
1589 pinmodel = (md3modelheader_t *)buffer;
1591 if (memcmp(pinmodel->identifier, "IDP3", 4))
1592 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1593 version = LittleLong (pinmodel->version);
1594 if (version != MD3VERSION)
1595 Host_Error ("%s has wrong version number (%i should be %i)",
1596 loadmodel->name, version, MD3VERSION);
1598 skinfiles = Mod_LoadSkinFiles();
1599 if (loadmodel->numskins < 1)
1600 loadmodel->numskins = 1;
1602 loadmodel->modeldatatypestring = "MD3";
1604 loadmodel->type = mod_alias;
1605 loadmodel->Draw = R_Mod_Draw;
1606 loadmodel->DrawDepth = R_Mod_DrawDepth;
1607 loadmodel->DrawDebug = R_Mod_DrawDebug;
1608 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1609 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1610 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1611 loadmodel->DrawLight = R_Mod_DrawLight;
1612 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1613 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1614 loadmodel->PointSuperContents = NULL;
1615 loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1616 loadmodel->synctype = ST_RAND;
1617 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1618 i = LittleLong (pinmodel->flags);
1619 loadmodel->effects = (((unsigned)i & 255) << 24) | (i & 0x00FFFF00);
1621 // set up some global info about the model
1622 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1623 loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1625 // make skinscenes for the skins (no groups)
1626 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1627 for (i = 0;i < loadmodel->numskins;i++)
1629 loadmodel->skinscenes[i].firstframe = i;
1630 loadmodel->skinscenes[i].framecount = 1;
1631 loadmodel->skinscenes[i].loop = true;
1632 loadmodel->skinscenes[i].framerate = 10;
1636 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1637 for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1639 dp_strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1640 loadmodel->animscenes[i].firstframe = i;
1641 loadmodel->animscenes[i].framecount = 1;
1642 loadmodel->animscenes[i].framerate = 10;
1643 loadmodel->animscenes[i].loop = true;
1647 loadmodel->num_tagframes = loadmodel->numframes;
1648 loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1649 loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1650 for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1652 dp_strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1653 for (j = 0;j < 9;j++)
1654 loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1655 for (j = 0;j < 3;j++)
1656 loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1657 //Con_Printf("model \"%s\" frame #%i tag #%i \"%s\"\n", loadmodel->name, i / loadmodel->num_tags, i % loadmodel->num_tags, loadmodel->data_tags[i].name);
1663 for (i = 0, pinmesh = (md3mesh_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_meshes));i < loadmodel->num_surfaces;i++, pinmesh = (md3mesh_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_end)))
1665 if (memcmp(pinmesh->identifier, "IDP3", 4))
1666 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1667 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1668 Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1669 meshvertices += LittleLong(pinmesh->num_vertices);
1670 meshtriangles += LittleLong(pinmesh->num_triangles);
1673 loadmodel->submodelsurfaces_start = 0;
1674 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1675 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1676 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1677 loadmodel->surfmesh.num_vertices = meshvertices;
1678 loadmodel->surfmesh.num_triangles = meshtriangles;
1679 loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1680 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1682 // do most allocations as one merged chunk
1683 // This is only robust for C standard types!
1684 data = (unsigned char *)Mem_Alloc(loadmodel->mempool,
1685 meshvertices * sizeof(float[2])
1686 + loadmodel->num_surfaces * sizeof(int)
1687 + meshtriangles * sizeof(int[3])
1688 + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0));
1689 // Pointers must be taken in descending order of alignment requirement!
1690 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data; data += meshvertices * sizeof(float[2]);
1691 loadmodel->modelsurfaces_sorted = (int *)data; data += loadmodel->num_surfaces * sizeof(int);
1692 loadmodel->surfmesh.data_element3i = (int *)data; data += meshtriangles * sizeof(int[3]);
1693 if (meshvertices <= 65536)
1695 loadmodel->surfmesh.data_element3s = (unsigned short *)data; data += meshtriangles * sizeof(unsigned short[3]);
1697 // Struct alignment requirements could change so we can't assume them here
1698 // otherwise a safe-looking commit could introduce undefined behaviour!
1699 loadmodel->data_surfaces = Mem_AllocType(loadmodel->mempool, msurface_t, loadmodel->num_surfaces * sizeof(msurface_t));
1700 loadmodel->data_textures = Mem_AllocType(loadmodel->mempool, texture_t, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1701 loadmodel->surfmesh.data_morphmd3vertex = Mem_AllocType(loadmodel->mempool, md3vertex_t, meshvertices * loadmodel->numframes * sizeof(md3vertex_t));
1705 for (i = 0, pinmesh = (md3mesh_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_meshes));i < loadmodel->num_surfaces;i++, pinmesh = (md3mesh_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_end)))
1707 if (memcmp(pinmesh->identifier, "IDP3", 4))
1708 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1709 loadmodel->modelsurfaces_sorted[i] = i;
1710 surface = loadmodel->data_surfaces + i;
1711 surface->texture = loadmodel->data_textures + i;
1712 surface->num_firsttriangle = meshtriangles;
1713 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1714 surface->num_firstvertex = meshvertices;
1715 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1716 meshvertices += surface->num_vertices;
1717 meshtriangles += surface->num_triangles;
1719 for (j = 0;j < surface->num_triangles * 3;j++)
1721 int e = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1722 loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = e;
1723 if (loadmodel->surfmesh.data_element3s)
1724 loadmodel->surfmesh.data_element3s[j + surface->num_firsttriangle * 3] = e;
1726 for (j = 0;j < surface->num_vertices;j++)
1728 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1729 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1731 for (j = 0;j < loadmodel->numframes;j++)
1733 const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1734 md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1735 for (k = 0;k < surface->num_vertices;k++, in++, out++)
1737 out->origin[0] = LittleShort(in->origin[0]);
1738 out->origin[1] = LittleShort(in->origin[1]);
1739 out->origin[2] = LittleShort(in->origin[2]);
1740 out->pitch = in->pitch;
1745 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1747 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, loadmodel->surfmesh.data_element3s + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1749 Mod_Alias_MorphMesh_CompileFrames();
1750 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1751 Mod_FreeSkinFiles(skinfiles);
1752 Mod_MakeSortedSurfaces(loadmodel);
1753 if(mod_alias_force_animated.string[0])
1754 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1756 // Always make a BIH for the first frame, we can use it where possible.
1757 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1758 if (!loadmodel->surfmesh.isanimated)
1760 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1761 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1762 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1763 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1764 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1768 void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend)
1770 zymtype1header_t *pinmodel, *pheader;
1771 unsigned char *pbase;
1772 int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1773 float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1774 zymvertex_t *verts, *vertdata;
1778 skinfile_t *skinfiles;
1779 unsigned char *data;
1780 msurface_t *surface;
1782 pinmodel = (zymtype1header_t *)buffer;
1783 pbase = (unsigned char *)buffer;
1784 if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1785 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1786 if (BigLong(pinmodel->type) != 1)
1787 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1789 loadmodel->modeldatatypestring = "ZYM";
1791 loadmodel->type = mod_alias;
1792 loadmodel->synctype = ST_RAND;
1796 pheader->type = BigLong(pinmodel->type);
1797 pheader->filesize = BigLong(pinmodel->filesize);
1798 pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1799 pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1800 pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1801 pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1802 pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1803 pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1804 pheader->radius = BigFloat(pinmodel->radius);
1805 pheader->numverts = BigLong(pinmodel->numverts);
1806 pheader->numtris = BigLong(pinmodel->numtris);
1807 pheader->numshaders = BigLong(pinmodel->numshaders);
1808 pheader->numbones = BigLong(pinmodel->numbones);
1809 pheader->numscenes = BigLong(pinmodel->numscenes);
1810 pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1811 pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1812 pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1813 pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1814 pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1815 pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1816 pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1817 pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1818 pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1819 pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1820 pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1821 pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1822 pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1823 pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1824 pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1825 pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1826 pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1827 pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1829 if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1831 Con_Printf("%s has no geometry\n", loadmodel->name);
1834 if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1836 Con_Printf("%s has no animations\n", loadmodel->name);
1840 loadmodel->Draw = R_Mod_Draw;
1841 loadmodel->DrawDepth = R_Mod_DrawDepth;
1842 loadmodel->DrawDebug = R_Mod_DrawDebug;
1843 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1844 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1845 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1846 loadmodel->DrawLight = R_Mod_DrawLight;
1847 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1848 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1849 loadmodel->PointSuperContents = NULL;
1850 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1852 loadmodel->numframes = pheader->numscenes;
1853 loadmodel->num_surfaces = pheader->numshaders;
1855 skinfiles = Mod_LoadSkinFiles();
1856 if (loadmodel->numskins < 1)
1857 loadmodel->numskins = 1;
1859 // make skinscenes for the skins (no groups)
1860 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1861 for (i = 0;i < loadmodel->numskins;i++)
1863 loadmodel->skinscenes[i].firstframe = i;
1864 loadmodel->skinscenes[i].framecount = 1;
1865 loadmodel->skinscenes[i].loop = true;
1866 loadmodel->skinscenes[i].framerate = 10;
1870 // LadyHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
1871 modelradius = pheader->radius;
1872 for (i = 0;i < 3;i++)
1874 loadmodel->normalmins[i] = pheader->mins[i];
1875 loadmodel->normalmaxs[i] = pheader->maxs[i];
1876 loadmodel->rotatedmins[i] = -modelradius;
1877 loadmodel->rotatedmaxs[i] = modelradius;
1879 corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1880 corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1881 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1882 if (loadmodel->yawmaxs[0] > modelradius)
1883 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1884 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1885 loadmodel->yawmins[2] = loadmodel->normalmins[2];
1886 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1887 loadmodel->radius = modelradius;
1888 loadmodel->radius2 = modelradius * modelradius;
1890 // go through the lumps, swapping things
1892 //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1893 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1894 scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1895 numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1896 for (i = 0;i < pheader->numscenes;i++)
1898 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1899 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1900 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1901 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1902 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1903 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1904 Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1905 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1906 Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1907 if (loadmodel->animscenes[i].framerate < 0)
1908 Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1912 //zymlump_t lump_bones; // zymbone_t bone[numbones];
1913 loadmodel->num_bones = pheader->numbones;
1914 loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1915 bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1916 for (i = 0;i < pheader->numbones;i++)
1918 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1919 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1920 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1921 if (loadmodel->data_bones[i].parent >= i)
1922 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1925 //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1926 vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1927 bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1928 for (i = 0;i < pheader->numverts;i++)
1930 vertbonecounts[i] = BigLong(bonecount[i]);
1931 if (vertbonecounts[i] != 1)
1932 Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1935 loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1937 meshvertices = pheader->numverts;
1938 meshtriangles = pheader->numtris;
1940 loadmodel->submodelsurfaces_start = 0;
1941 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1942 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1943 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1944 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) + meshvertices * (sizeof(float[14]) + sizeof(unsigned short) + sizeof(unsigned char[2][4])) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]));
1945 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1946 loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1947 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1948 loadmodel->surfmesh.num_vertices = meshvertices;
1949 loadmodel->surfmesh.num_triangles = meshtriangles;
1950 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1951 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1952 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1953 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1954 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1955 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1956 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
1957 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
1958 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1959 loadmodel->surfmesh.num_blends = 0;
1960 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
1961 if (loadmodel->surfmesh.num_vertices <= 65536)
1963 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
1965 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
1966 loadmodel->surfmesh.data_blendweights = NULL;
1968 //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1969 poses = (float *) (pheader->lump_poses.start + pbase);
1970 // figure out scale of model from root bone, for compatibility with old zmodel versions
1971 tempvec[0] = BigFloat(poses[0]);
1972 tempvec[1] = BigFloat(poses[1]);
1973 tempvec[2] = BigFloat(poses[2]);
1974 modelscale = VectorLength(tempvec);
1976 for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
1978 f = fabs(BigFloat(poses[i]));
1979 biggestorigin = max(biggestorigin, f);
1981 loadmodel->num_posescale = biggestorigin / 32767.0f;
1982 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
1983 for (i = 0;i < numposes;i++)
1985 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
1986 for (j = 0;j < loadmodel->num_bones;j++)
1989 matrix4x4_t posematrix;
1990 for (k = 0;k < 12;k++)
1991 pose[k] = BigFloat(frameposes[j*12+k]);
1992 //if (j < loadmodel->num_bones)
1993 // 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));
1994 // scale child bones to match the root scale
1995 if (loadmodel->data_bones[j].parent >= 0)
1997 pose[3] *= modelscale;
1998 pose[7] *= modelscale;
1999 pose[11] *= modelscale;
2001 // normalize rotation matrix
2002 VectorNormalize(pose + 0);
2003 VectorNormalize(pose + 4);
2004 VectorNormalize(pose + 8);
2005 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2006 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2010 //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2011 verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2012 vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2013 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2014 // (converting from weight-blending skeletal animation to
2015 // deformation-based skeletal animation)
2016 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2017 for (i = 0;i < loadmodel->num_bones;i++)
2020 for (k = 0;k < 12;k++)
2021 m[k] = BigFloat(poses[i*12+k]);
2022 if (loadmodel->data_bones[i].parent >= 0)
2023 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2025 for (k = 0;k < 12;k++)
2026 bonepose[12*i+k] = m[k];
2028 for (j = 0;j < pheader->numverts;j++)
2030 // this format really should have had a per vertexweight weight value...
2031 // but since it does not, the weighting is completely ignored and
2032 // only one weight is allowed per vertex
2033 int boneindex = BigLong(vertdata[j].bonenum);
2034 const float *m = bonepose + 12 * boneindex;
2035 float relativeorigin[3];
2036 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2037 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2038 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2039 // transform the vertex bone weight into the base mesh
2040 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2041 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2042 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2043 // store the weight as the primary weight on this vertex
2044 loadmodel->surfmesh.blends[j] = boneindex;
2045 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = boneindex;
2046 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2047 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2048 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2049 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = 255;
2050 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2051 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2052 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2055 // normals and tangents are calculated after elements are loaded
2057 //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2058 outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2059 intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2060 for (i = 0;i < pheader->numverts;i++)
2062 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2063 // flip T coordinate for OpenGL
2064 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2067 //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2068 //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2069 //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2071 //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2072 //zymlump_t lump_render; // int renderlist[rendersize]; // sorted by shader with run lengths (int count), shaders are sequentially used, each run can be used with glDrawElements (each triangle is 3 int indices)
2073 // byteswap, validate, and swap winding order of tris
2074 count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2075 if (pheader->lump_render.length != count)
2076 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2077 renderlist = (int *) (pheader->lump_render.start + pbase);
2078 renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2080 for (i = 0;i < loadmodel->num_surfaces;i++)
2082 int firstvertex, lastvertex;
2083 if (renderlist >= renderlistend)
2084 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2085 count = BigLong(*renderlist);renderlist++;
2086 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2087 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2089 loadmodel->modelsurfaces_sorted[i] = i;
2090 surface = loadmodel->data_surfaces + i;
2091 surface->texture = loadmodel->data_textures + i;
2092 surface->num_firsttriangle = meshtriangles;
2093 surface->num_triangles = count;
2094 meshtriangles += surface->num_triangles;
2096 // load the elements
2097 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2098 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2100 outelements[j*3+2] = BigLong(renderlist[0]);
2101 outelements[j*3+1] = BigLong(renderlist[1]);
2102 outelements[j*3+0] = BigLong(renderlist[2]);
2104 // validate the elements and find the used vertex range
2105 firstvertex = meshvertices;
2107 for (j = 0;j < surface->num_triangles * 3;j++)
2109 if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2110 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2111 firstvertex = min(firstvertex, outelements[j]);
2112 lastvertex = max(lastvertex, outelements[j]);
2114 surface->num_firstvertex = firstvertex;
2115 surface->num_vertices = lastvertex + 1 - firstvertex;
2117 // since zym models do not have named sections, reuse their shader
2118 // name as the section name
2119 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2120 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2122 Mod_FreeSkinFiles(skinfiles);
2123 Mem_Free(vertbonecounts);
2125 Mod_MakeSortedSurfaces(loadmodel);
2127 // compute all the mesh information that was not loaded from the file
2128 if (loadmodel->surfmesh.data_element3s)
2129 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2130 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2131 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2132 Mod_BuildBaseBonePoses();
2133 Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, r_smoothnormals_areaweighting.integer != 0);
2134 Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
2135 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2136 if(mod_alias_force_animated.string[0])
2137 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2139 // Always make a BIH for the first frame, we can use it where possible.
2140 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2141 if (!loadmodel->surfmesh.isanimated)
2143 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2144 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2145 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2146 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2147 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2151 void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend)
2153 dpmheader_t *pheader;
2157 unsigned char *pbase;
2158 int i, j, k, meshvertices, meshtriangles;
2159 skinfile_t *skinfiles;
2160 unsigned char *data;
2162 float biggestorigin, tempvec[3], modelscale;
2166 pheader = (dpmheader_t *)buffer;
2167 pbase = (unsigned char *)buffer;
2168 if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2169 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2170 if (BigLong(pheader->type) != 2)
2171 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2173 loadmodel->modeldatatypestring = "DPM";
2175 loadmodel->type = mod_alias;
2176 loadmodel->synctype = ST_RAND;
2179 pheader->type = BigLong(pheader->type);
2180 pheader->filesize = BigLong(pheader->filesize);
2181 pheader->mins[0] = BigFloat(pheader->mins[0]);
2182 pheader->mins[1] = BigFloat(pheader->mins[1]);
2183 pheader->mins[2] = BigFloat(pheader->mins[2]);
2184 pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2185 pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2186 pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2187 pheader->yawradius = BigFloat(pheader->yawradius);
2188 pheader->allradius = BigFloat(pheader->allradius);
2189 pheader->num_bones = BigLong(pheader->num_bones);
2190 pheader->num_meshs = BigLong(pheader->num_meshs);
2191 pheader->num_frames = BigLong(pheader->num_frames);
2192 pheader->ofs_bones = BigLong(pheader->ofs_bones);
2193 pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2194 pheader->ofs_frames = BigLong(pheader->ofs_frames);
2196 if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2198 Con_Printf("%s has no geometry\n", loadmodel->name);
2201 if (pheader->num_frames < 1)
2203 Con_Printf("%s has no frames\n", loadmodel->name);
2207 loadmodel->Draw = R_Mod_Draw;
2208 loadmodel->DrawDepth = R_Mod_DrawDepth;
2209 loadmodel->DrawDebug = R_Mod_DrawDebug;
2210 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
2211 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
2212 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
2213 loadmodel->DrawLight = R_Mod_DrawLight;
2214 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2215 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2216 loadmodel->PointSuperContents = NULL;
2217 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2220 // LadyHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2221 for (i = 0;i < 3;i++)
2223 loadmodel->normalmins[i] = pheader->mins[i];
2224 loadmodel->normalmaxs[i] = pheader->maxs[i];
2225 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2226 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2227 loadmodel->rotatedmins[i] = -pheader->allradius;
2228 loadmodel->rotatedmaxs[i] = pheader->allradius;
2230 loadmodel->radius = pheader->allradius;
2231 loadmodel->radius2 = pheader->allradius * pheader->allradius;
2233 // load external .skin files if present
2234 skinfiles = Mod_LoadSkinFiles();
2235 if (loadmodel->numskins < 1)
2236 loadmodel->numskins = 1;
2241 // gather combined statistics from the meshes
2242 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2243 for (i = 0;i < (int)pheader->num_meshs;i++)
2245 int numverts = BigLong(dpmmesh->num_verts);
2246 meshvertices += numverts;
2247 meshtriangles += BigLong(dpmmesh->num_tris);
2251 loadmodel->numframes = pheader->num_frames;
2252 loadmodel->num_bones = pheader->num_bones;
2253 loadmodel->num_poses = loadmodel->numframes;
2254 loadmodel->submodelsurfaces_start = 0;
2255 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = pheader->num_meshs;
2256 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2257 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2258 // do most allocations as one merged chunk
2259 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) + meshvertices * (sizeof(float[14]) + sizeof(unsigned short) + sizeof(unsigned char[2][4])) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t));
2260 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2261 loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2262 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2263 loadmodel->surfmesh.num_vertices = meshvertices;
2264 loadmodel->surfmesh.num_triangles = meshtriangles;
2265 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2266 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2267 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2268 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2269 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2270 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2271 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2272 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2273 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2274 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2275 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2276 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2277 loadmodel->surfmesh.num_blends = 0;
2278 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2279 if (meshvertices <= 65536)
2281 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2283 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2284 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2286 for (i = 0;i < loadmodel->numskins;i++)
2288 loadmodel->skinscenes[i].firstframe = i;
2289 loadmodel->skinscenes[i].framecount = 1;
2290 loadmodel->skinscenes[i].loop = true;
2291 loadmodel->skinscenes[i].framerate = 10;
2294 // load the bone info
2295 bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2296 for (i = 0;i < loadmodel->num_bones;i++)
2298 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2299 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2300 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2301 if (loadmodel->data_bones[i].parent >= i)
2302 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2306 frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2307 // figure out scale of model from root bone, for compatibility with old dpmodel versions
2308 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2309 tempvec[0] = BigFloat(poses[0]);
2310 tempvec[1] = BigFloat(poses[1]);
2311 tempvec[2] = BigFloat(poses[2]);
2312 modelscale = VectorLength(tempvec);
2314 for (i = 0;i < loadmodel->numframes;i++)
2316 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2317 loadmodel->animscenes[i].firstframe = i;
2318 loadmodel->animscenes[i].framecount = 1;
2319 loadmodel->animscenes[i].loop = true;
2320 loadmodel->animscenes[i].framerate = 10;
2321 // load the bone poses for this frame
2322 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2323 for (j = 0;j < loadmodel->num_bones*12;j++)
2325 f = fabs(BigFloat(poses[j]));
2326 biggestorigin = max(biggestorigin, f);
2328 // stuff not processed here: mins, maxs, yawradius, allradius
2330 loadmodel->num_posescale = biggestorigin / 32767.0f;
2331 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2332 for (i = 0;i < loadmodel->numframes;i++)
2334 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2335 for (j = 0;j < loadmodel->num_bones;j++)
2338 matrix4x4_t posematrix;
2339 for (k = 0;k < 12;k++)
2340 pose[k] = BigFloat(frameposes[j*12+k]);
2341 // scale child bones to match the root scale
2342 if (loadmodel->data_bones[j].parent >= 0)
2344 pose[3] *= modelscale;
2345 pose[7] *= modelscale;
2346 pose[11] *= modelscale;
2348 // normalize rotation matrix
2349 VectorNormalize(pose + 0);
2350 VectorNormalize(pose + 4);
2351 VectorNormalize(pose + 8);
2352 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2353 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2357 // load the meshes now
2358 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2361 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2362 // (converting from weight-blending skeletal animation to
2363 // deformation-based skeletal animation)
2364 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2365 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2366 for (i = 0;i < loadmodel->num_bones;i++)
2369 for (k = 0;k < 12;k++)
2370 m[k] = BigFloat(poses[i*12+k]);
2371 if (loadmodel->data_bones[i].parent >= 0)
2372 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2374 for (k = 0;k < 12;k++)
2375 bonepose[12*i+k] = m[k];
2377 for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2379 const int *inelements;
2381 unsigned short *outelement3s;
2382 const float *intexcoord;
2383 msurface_t *surface;
2385 loadmodel->modelsurfaces_sorted[i] = i;
2386 surface = loadmodel->data_surfaces + i;
2387 surface->texture = loadmodel->data_textures + i;
2388 surface->num_firsttriangle = meshtriangles;
2389 surface->num_triangles = BigLong(dpmmesh->num_tris);
2390 surface->num_firstvertex = meshvertices;
2391 surface->num_vertices = BigLong(dpmmesh->num_verts);
2392 meshvertices += surface->num_vertices;
2393 meshtriangles += surface->num_triangles;
2395 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2396 outelement3i = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2397 outelement3s = loadmodel->surfmesh.data_element3s ? loadmodel->surfmesh.data_element3s + surface->num_firsttriangle * 3 : NULL;
2398 for (j = 0;j < surface->num_triangles;j++)
2400 // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2401 outelement3i[j * 3 + 0] = surface->num_firstvertex + BigLong(inelements[j * 3 + 2]);
2402 outelement3i[j * 3 + 1] = surface->num_firstvertex + BigLong(inelements[j * 3 + 1]);
2403 outelement3i[j * 3 + 2] = surface->num_firstvertex + BigLong(inelements[j * 3 + 0]);
2406 outelement3s[j * 3 + 0] = outelement3i[j * 3 + 0];
2407 outelement3s[j * 3 + 1] = outelement3i[j * 3 + 1];
2408 outelement3s[j * 3 + 2] = outelement3i[j * 3 + 2];
2412 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2413 for (j = 0;j < surface->num_vertices*2;j++)
2414 loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2416 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2417 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2419 int weightindex[4] = { 0, 0, 0, 0 };
2420 float weightinfluence[4] = { 0, 0, 0, 0 };
2422 int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2423 data += sizeof(dpmvertex_t);
2424 for (k = 0;k < numweights;k++)
2426 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2427 int boneindex = BigLong(vert->bonenum);
2428 const float *m = bonepose + 12 * boneindex;
2429 float influence = BigFloat(vert->influence);
2430 float relativeorigin[3], relativenormal[3];
2431 relativeorigin[0] = BigFloat(vert->origin[0]);
2432 relativeorigin[1] = BigFloat(vert->origin[1]);
2433 relativeorigin[2] = BigFloat(vert->origin[2]);
2434 relativenormal[0] = BigFloat(vert->normal[0]);
2435 relativenormal[1] = BigFloat(vert->normal[1]);
2436 relativenormal[2] = BigFloat(vert->normal[2]);
2437 // blend the vertex bone weights into the base mesh
2438 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2439 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2440 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2441 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2442 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2443 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2446 // store the first (and often only) weight
2447 weightinfluence[0] = influence;
2448 weightindex[0] = boneindex;
2452 // sort the new weight into this vertex's weight table
2453 // (which only accepts up to 4 bones per vertex)
2454 for (l = 0;l < 4;l++)
2456 if (weightinfluence[l] < influence)
2458 // move weaker influence weights out of the way first
2460 for (l2 = 3;l2 > l;l2--)
2462 weightinfluence[l2] = weightinfluence[l2-1];
2463 weightindex[l2] = weightindex[l2-1];
2465 // store the new weight
2466 weightinfluence[l] = influence;
2467 weightindex[l] = boneindex;
2472 data += sizeof(dpmbonevert_t);
2474 loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2475 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = weightindex[0];
2476 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2477 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2478 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2479 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
2480 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2481 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2482 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2485 // since dpm models do not have named sections, reuse their shader name as the section name
2486 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2488 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, loadmodel->surfmesh.data_element3s + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2490 if (loadmodel->surfmesh.num_blends < meshvertices)
2491 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2493 Mod_FreeSkinFiles(skinfiles);
2494 Mod_MakeSortedSurfaces(loadmodel);
2496 // compute all the mesh information that was not loaded from the file
2497 Mod_BuildBaseBonePoses();
2498 Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
2499 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2500 if(mod_alias_force_animated.string[0])
2501 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2503 // Always make a BIH for the first frame, we can use it where possible.
2504 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2505 if (!loadmodel->surfmesh.isanimated)
2507 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2508 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2509 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2510 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2511 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2515 // no idea why PSK/PSA files contain weird quaternions but they do...
2516 #define PSKQUATNEGATIONS
2517 void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
2519 int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2520 int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2521 fs_offset_t filesize;
2526 pskboneinfo_t *bones;
2527 pskrawweights_t *rawweights;
2528 //pskboneinfo_t *animbones;
2529 pskaniminfo_t *anims;
2530 pskanimkeys_t *animkeys;
2531 void *animfilebuffer, *animbuffer, *animbufferend;
2532 unsigned char *data;
2534 skinfile_t *skinfiles;
2535 char animname[MAX_QPATH];
2537 float biggestorigin;
2539 pchunk = (pskchunk_t *)buffer;
2540 if (strcmp(pchunk->id, "ACTRHEAD"))
2541 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2543 loadmodel->modeldatatypestring = "PSK";
2545 loadmodel->type = mod_alias;
2546 loadmodel->Draw = R_Mod_Draw;
2547 loadmodel->DrawDepth = R_Mod_DrawDepth;
2548 loadmodel->DrawDebug = R_Mod_DrawDebug;
2549 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
2550 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
2551 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
2552 loadmodel->DrawLight = R_Mod_DrawLight;
2553 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2554 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2555 loadmodel->PointSuperContents = NULL;
2556 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2557 loadmodel->synctype = ST_RAND;
2559 FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2560 dp_strlcat(animname, ".psa", sizeof(animname));
2561 animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2562 animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2564 animbufferend = animbuffer;
2583 while (buffer < bufferend)
2585 pchunk = (pskchunk_t *)buffer;
2586 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2587 version = LittleLong(pchunk->version);
2588 recordsize = LittleLong(pchunk->recordsize);
2589 numrecords = LittleLong(pchunk->numrecords);
2590 if (developer_extra.integer)
2591 Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2592 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2593 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);
2594 if (!strcmp(pchunk->id, "ACTRHEAD"))
2598 else if (!strcmp(pchunk->id, "PNTS0000"))
2601 if (recordsize != sizeof(*p))
2602 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2603 // byteswap in place and keep the pointer
2604 numpnts = numrecords;
2605 pnts = (pskpnts_t *)buffer;
2606 for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2608 p->origin[0] = LittleFloat(p->origin[0]);
2609 p->origin[1] = LittleFloat(p->origin[1]);
2610 p->origin[2] = LittleFloat(p->origin[2]);
2614 else if (!strcmp(pchunk->id, "VTXW0000"))
2617 if (recordsize != sizeof(*p))
2618 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2619 // byteswap in place and keep the pointer
2620 numvtxw = numrecords;
2621 vtxw = (pskvtxw_t *)buffer;
2622 for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2624 p->pntsindex = LittleShort(p->pntsindex);
2625 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2626 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2627 if (p->pntsindex >= numpnts)
2629 Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2635 else if (!strcmp(pchunk->id, "FACE0000"))
2638 if (recordsize != sizeof(*p))
2639 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2640 // byteswap in place and keep the pointer
2641 numfaces = numrecords;
2642 faces = (pskface_t *)buffer;
2643 for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2645 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2646 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2647 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2648 p->group = LittleLong(p->group);
2649 if (p->vtxwindex[0] >= numvtxw)
2651 Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2652 p->vtxwindex[0] = 0;
2654 if (p->vtxwindex[1] >= numvtxw)
2656 Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2657 p->vtxwindex[1] = 0;
2659 if (p->vtxwindex[2] >= numvtxw)
2661 Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2662 p->vtxwindex[2] = 0;
2667 else if (!strcmp(pchunk->id, "MATT0000"))
2670 if (recordsize != sizeof(*p))
2671 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2672 // byteswap in place and keep the pointer
2673 nummatts = numrecords;
2674 matts = (pskmatt_t *)buffer;
2675 for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2681 else if (!strcmp(pchunk->id, "REFSKELT"))
2684 if (recordsize != sizeof(*p))
2685 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2686 // byteswap in place and keep the pointer
2687 numbones = numrecords;
2688 bones = (pskboneinfo_t *)buffer;
2689 for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2691 p->numchildren = LittleLong(p->numchildren);
2692 p->parent = LittleLong(p->parent);
2693 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2694 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2695 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2696 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2697 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2698 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2699 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2700 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2701 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2702 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2703 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2704 #ifdef PSKQUATNEGATIONS
2707 p->basepose.quat[0] *= -1;
2708 p->basepose.quat[1] *= -1;
2709 p->basepose.quat[2] *= -1;
2713 p->basepose.quat[0] *= 1;
2714 p->basepose.quat[1] *= -1;
2715 p->basepose.quat[2] *= 1;
2718 if (p->parent < 0 || p->parent >= numbones)
2720 Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2726 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2729 if (recordsize != sizeof(*p))
2730 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2731 // byteswap in place and keep the pointer
2732 numrawweights = numrecords;
2733 rawweights = (pskrawweights_t *)buffer;
2734 for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2736 p->weight = LittleFloat(p->weight);
2737 p->pntsindex = LittleLong(p->pntsindex);
2738 p->boneindex = LittleLong(p->boneindex);
2739 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2741 Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2744 if (p->boneindex < 0 || p->boneindex >= numbones)
2746 Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2754 while (animbuffer < animbufferend)
2756 pchunk = (pskchunk_t *)animbuffer;
2757 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2758 version = LittleLong(pchunk->version);
2759 recordsize = LittleLong(pchunk->recordsize);
2760 numrecords = LittleLong(pchunk->numrecords);
2761 if (developer_extra.integer)
2762 Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2763 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2764 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);
2765 if (!strcmp(pchunk->id, "ANIMHEAD"))
2769 else if (!strcmp(pchunk->id, "BONENAMES"))
2772 if (recordsize != sizeof(*p))
2773 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2774 // byteswap in place and keep the pointer
2775 numanimbones = numrecords;
2776 //animbones = (pskboneinfo_t *)animbuffer;
2777 // NOTE: supposedly psa does not need to match the psk model, the
2778 // bones missing from the psa would simply use their base
2779 // positions from the psk, but this is hard for me to implement
2780 // and people can easily make animations that match.
2781 if (numanimbones != numbones)
2782 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2783 for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2785 p->numchildren = LittleLong(p->numchildren);
2786 p->parent = LittleLong(p->parent);
2787 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2788 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2789 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2790 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2791 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2792 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2793 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2794 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2795 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2796 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2797 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2798 #ifdef PSKQUATNEGATIONS
2801 p->basepose.quat[0] *= -1;
2802 p->basepose.quat[1] *= -1;
2803 p->basepose.quat[2] *= -1;
2807 p->basepose.quat[0] *= 1;
2808 p->basepose.quat[1] *= -1;
2809 p->basepose.quat[2] *= 1;
2812 if (p->parent < 0 || p->parent >= numanimbones)
2814 Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2817 // check that bones are the same as in the base
2818 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2819 Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2823 else if (!strcmp(pchunk->id, "ANIMINFO"))
2826 if (recordsize != sizeof(*p))
2827 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2828 // byteswap in place and keep the pointer
2829 numanims = numrecords;
2830 anims = (pskaniminfo_t *)animbuffer;
2831 for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2833 p->numbones = LittleLong(p->numbones);
2834 p->playtime = LittleFloat(p->playtime);
2835 p->fps = LittleFloat(p->fps);
2836 p->firstframe = LittleLong(p->firstframe);
2837 p->numframes = LittleLong(p->numframes);
2838 if (p->numbones != numbones)
2839 Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2843 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2846 if (recordsize != sizeof(*p))
2847 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2848 numanimkeys = numrecords;
2849 animkeys = (pskanimkeys_t *)animbuffer;
2850 for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2852 p->origin[0] = LittleFloat(p->origin[0]);
2853 p->origin[1] = LittleFloat(p->origin[1]);
2854 p->origin[2] = LittleFloat(p->origin[2]);
2855 p->quat[0] = LittleFloat(p->quat[0]);
2856 p->quat[1] = LittleFloat(p->quat[1]);
2857 p->quat[2] = LittleFloat(p->quat[2]);
2858 p->quat[3] = LittleFloat(p->quat[3]);
2859 p->frametime = LittleFloat(p->frametime);
2860 #ifdef PSKQUATNEGATIONS
2861 if (index % numbones)
2876 // TODO: allocate bonepose stuff
2879 Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2882 if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2883 Host_Error("%s: missing required chunks", loadmodel->name);
2887 loadmodel->numframes = 0;
2888 for (index = 0;index < numanims;index++)
2889 loadmodel->numframes += anims[index].numframes;
2890 if (numanimkeys != numbones * loadmodel->numframes)
2891 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2894 loadmodel->numframes = loadmodel->num_poses = 1;
2896 meshvertices = numvtxw;
2897 meshtriangles = numfaces;
2899 // load external .skin files if present
2900 skinfiles = Mod_LoadSkinFiles();
2901 if (loadmodel->numskins < 1)
2902 loadmodel->numskins = 1;
2903 loadmodel->num_bones = numbones;
2904 loadmodel->num_poses = loadmodel->numframes;
2905 loadmodel->submodelsurfaces_start = 0;
2906 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = nummatts;
2907 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2908 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2909 loadmodel->surfmesh.num_vertices = meshvertices;
2910 loadmodel->surfmesh.num_triangles = meshtriangles;
2911 // do most allocations as one merged chunk
2912 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_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned short) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t) + ((loadmodel->surfmesh.num_vertices <= 65536) ? (loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0);
2913 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2914 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2915 loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2916 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2917 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2918 loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2919 loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2920 loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2921 loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2922 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2923 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2924 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2925 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2926 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2927 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2928 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2929 loadmodel->surfmesh.num_blends = 0;
2930 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2931 if (loadmodel->surfmesh.num_vertices <= 65536)
2933 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2935 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2936 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
2938 for (i = 0;i < loadmodel->numskins;i++)
2940 loadmodel->skinscenes[i].firstframe = i;
2941 loadmodel->skinscenes[i].framecount = 1;
2942 loadmodel->skinscenes[i].loop = true;
2943 loadmodel->skinscenes[i].framerate = 10;
2947 for (index = 0, i = 0;index < nummatts;index++)
2949 // since psk models do not have named sections, reuse their shader name as the section name
2950 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2951 loadmodel->modelsurfaces_sorted[index] = index;
2952 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2953 loadmodel->data_surfaces[index].num_firstvertex = 0;
2954 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2957 // copy over the vertex locations and texcoords
2958 for (index = 0;index < numvtxw;index++)
2960 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
2961 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
2962 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
2963 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
2964 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
2967 // loading the faces is complicated because we need to sort them into surfaces by mattindex
2968 for (index = 0;index < numfaces;index++)
2969 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
2970 for (index = 0, i = 0;index < nummatts;index++)
2972 loadmodel->data_surfaces[index].num_firsttriangle = i;
2973 i += loadmodel->data_surfaces[index].num_triangles;
2974 loadmodel->data_surfaces[index].num_triangles = 0;
2976 for (index = 0;index < numfaces;index++)
2978 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
2979 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
2980 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
2981 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
2984 // copy over the bones
2985 for (index = 0;index < numbones;index++)
2987 dp_strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
2988 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
2989 if (loadmodel->data_bones[index].parent >= index)
2990 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
2993 // convert the basepose data
2994 if (loadmodel->num_bones)
2997 matrix4x4_t *basebonepose;
2998 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
2999 matrix4x4_t bonematrix;
3000 matrix4x4_t tempbonematrix;
3001 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
3002 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
3004 Matrix4x4_FromOriginQuat(&bonematrix, bones[boneindex].basepose.origin[0], bones[boneindex].basepose.origin[1], bones[boneindex].basepose.origin[2], bones[boneindex].basepose.quat[0], bones[boneindex].basepose.quat[1], bones[boneindex].basepose.quat[2], bones[boneindex].basepose.quat[3]);
3005 if (loadmodel->data_bones[boneindex].parent >= 0)
3007 tempbonematrix = bonematrix;
3008 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3010 basebonepose[boneindex] = bonematrix;
3011 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3012 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3014 Mem_Free(basebonepose);
3017 // sort the psk point weights into the vertex weight tables
3018 // (which only accept up to 4 bones per vertex)
3019 for (index = 0;index < numvtxw;index++)
3021 int weightindex[4] = { 0, 0, 0, 0 };
3022 float weightinfluence[4] = { 0, 0, 0, 0 };
3024 for (j = 0;j < numrawweights;j++)
3026 if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3028 int boneindex = rawweights[j].boneindex;
3029 float influence = rawweights[j].weight;
3030 for (l = 0;l < 4;l++)
3032 if (weightinfluence[l] < influence)
3034 // move lower influence weights out of the way first
3036 for (l2 = 3;l2 > l;l2--)
3038 weightinfluence[l2] = weightinfluence[l2-1];
3039 weightindex[l2] = weightindex[l2-1];
3041 // store the new weight
3042 weightinfluence[l] = influence;
3043 weightindex[l] = boneindex;
3049 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3050 loadmodel->surfmesh.data_skeletalindex4ub[index*4 ] = weightindex[0];
3051 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3052 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3053 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3054 loadmodel->surfmesh.data_skeletalweight4ub[index*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
3055 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3056 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3057 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3059 if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3060 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3062 // set up the animscenes based on the anims
3065 for (index = 0, i = 0;index < numanims;index++)
3067 for (j = 0;j < anims[index].numframes;j++, i++)
3069 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3070 loadmodel->animscenes[i].firstframe = i;
3071 loadmodel->animscenes[i].framecount = 1;
3072 loadmodel->animscenes[i].loop = true;
3073 loadmodel->animscenes[i].framerate = anims[index].fps;
3076 // calculate the scaling value for bone origins so they can be compressed to short
3078 for (index = 0;index < numanimkeys;index++)
3080 pskanimkeys_t *k = animkeys + index;
3081 biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3082 biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3083 biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3085 loadmodel->num_posescale = biggestorigin / 32767.0f;
3086 if (loadmodel->num_posescale == 0) // don't divide by zero
3087 loadmodel->num_posescale = 1.0;
3088 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3090 // load the poses from the animkeys
3091 for (index = 0;index < numanimkeys;index++)
3093 pskanimkeys_t *k = animkeys + index;
3095 Vector4Copy(k->quat, quat);
3097 Vector4Negate(quat, quat);
3098 Vector4Normalize2(quat, quat);
3099 // compress poses to the short[7] format for longterm storage
3100 loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3101 loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3102 loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3103 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3104 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3105 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3106 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3111 dp_strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3112 loadmodel->animscenes[0].firstframe = 0;
3113 loadmodel->animscenes[0].framecount = 1;
3114 loadmodel->animscenes[0].loop = true;
3115 loadmodel->animscenes[0].framerate = 10;
3117 // calculate the scaling value for bone origins so they can be compressed to short
3119 for (index = 0;index < numbones;index++)
3121 pskboneinfo_t *p = bones + index;
3122 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3123 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3124 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3126 loadmodel->num_posescale = biggestorigin / 32767.0f;
3127 if (loadmodel->num_posescale == 0) // don't divide by zero
3128 loadmodel->num_posescale = 1.0;
3129 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3131 // load the basepose as a frame
3132 for (index = 0;index < numbones;index++)
3134 pskboneinfo_t *p = bones + index;
3136 Vector4Copy(p->basepose.quat, quat);
3138 Vector4Negate(quat, quat);
3139 Vector4Normalize2(quat, quat);
3140 // compress poses to the short[7] format for longterm storage
3141 loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3142 loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3143 loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3144 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3145 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3146 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3147 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3151 Mod_FreeSkinFiles(skinfiles);
3153 Mem_Free(animfilebuffer);
3154 Mod_MakeSortedSurfaces(loadmodel);
3156 // compute all the mesh information that was not loaded from the file
3157 // TODO: honor smoothing groups somehow?
3158 if (loadmodel->surfmesh.data_element3s)
3159 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3160 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3161 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3162 Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, r_smoothnormals_areaweighting.integer != 0);
3163 Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
3164 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3165 if(mod_alias_force_animated.string[0])
3166 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3168 // Always make a BIH for the first frame, we can use it where possible.
3169 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3170 if (!loadmodel->surfmesh.isanimated)
3172 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3173 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3174 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3175 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3176 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3180 void Mod_INTERQUAKEMODEL_Load(model_t *mod, void *buffer, void *bufferend)
3182 unsigned char *data;
3184 const unsigned char *pbase, *pend;
3186 skinfile_t *skinfiles;
3188 float biggestorigin;
3189 const unsigned int *inelements;
3191 float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3192 // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3193 const float *vnormal = NULL;
3194 const float *vposition = NULL;
3195 const float *vtangent = NULL;
3196 const float *vtexcoord = NULL;
3197 const float *vcolor4f = NULL;
3198 const unsigned char *vblendindexes = NULL;
3199 const unsigned char *vblendweights = NULL;
3200 const unsigned char *vcolor4ub = NULL;
3201 const unsigned short *framedata = NULL;
3202 // temporary memory allocations (because the data in the file may be misaligned)
3203 iqmanim_t *anims = NULL;
3204 iqmbounds_t *bounds = NULL;
3205 iqmjoint1_t *joint1 = NULL;
3206 iqmjoint_t *joint = NULL;
3207 iqmmesh_t *meshes = NULL;
3208 iqmpose1_t *pose1 = NULL;
3209 iqmpose_t *pose = NULL;
3210 iqmvertexarray_t *vas = NULL;
3212 pbase = (unsigned char *)buffer;
3213 pend = (unsigned char *)bufferend;
3215 if (pbase + sizeof(iqmheader_t) > pend)
3216 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3218 // copy struct (otherwise it may be misaligned)
3219 // LadyHavoc: okay it's definitely not misaligned here, but for consistency...
3220 memcpy(&header, pbase, sizeof(iqmheader_t));
3222 if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3223 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3224 if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3225 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3227 loadmodel->modeldatatypestring = "IQM";
3229 loadmodel->type = mod_alias;
3230 loadmodel->synctype = ST_RAND;
3233 header.version = LittleLong(header.version);
3234 header.filesize = LittleLong(header.filesize);
3235 header.flags = LittleLong(header.flags);
3236 header.num_text = LittleLong(header.num_text);
3237 header.ofs_text = LittleLong(header.ofs_text);
3238 header.num_meshes = LittleLong(header.num_meshes);
3239 header.ofs_meshes = LittleLong(header.ofs_meshes);
3240 header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3241 header.num_vertexes = LittleLong(header.num_vertexes);
3242 header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3243 header.num_triangles = LittleLong(header.num_triangles);
3244 header.ofs_triangles = LittleLong(header.ofs_triangles);
3245 header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3246 header.num_joints = LittleLong(header.num_joints);
3247 header.ofs_joints = LittleLong(header.ofs_joints);
3248 header.num_poses = LittleLong(header.num_poses);
3249 header.ofs_poses = LittleLong(header.ofs_poses);
3250 header.num_anims = LittleLong(header.num_anims);
3251 header.ofs_anims = LittleLong(header.ofs_anims);
3252 header.num_frames = LittleLong(header.num_frames);
3253 header.num_framechannels = LittleLong(header.num_framechannels);
3254 header.ofs_frames = LittleLong(header.ofs_frames);
3255 header.ofs_bounds = LittleLong(header.ofs_bounds);
3256 header.num_comment = LittleLong(header.num_comment);
3257 header.ofs_comment = LittleLong(header.ofs_comment);
3258 header.num_extensions = LittleLong(header.num_extensions);
3259 header.ofs_extensions = LittleLong(header.ofs_extensions);
3261 if (header.version == 1)
3263 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3264 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3266 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3272 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3273 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3275 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3279 if (pbase + header.ofs_text + header.num_text > pend ||
3280 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3281 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3282 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3283 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3284 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3285 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3286 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3287 pbase + header.ofs_comment + header.num_comment > pend)
3289 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3293 // Structs will be copied for alignment in memory, otherwise we crash on Sparc, PowerPC and others
3294 // and get big spam from UBSan, because these offsets may not be aligned.
3295 if (header.num_vertexarrays)
3296 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3297 if (header.num_anims)
3298 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3299 if (header.ofs_bounds)
3300 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3301 if (header.num_meshes)
3302 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3304 for (i = 0;i < (int)header.num_vertexarrays;i++)
3306 iqmvertexarray_t va;
3309 memcpy(&va, &vas[i], sizeof(iqmvertexarray_t));
3310 va.type = LittleLong(va.type);
3311 va.flags = LittleLong(va.flags);
3312 va.format = LittleLong(va.format);
3313 va.size = LittleLong(va.size);
3314 va.offset = LittleLong(va.offset);
3315 vsize = header.num_vertexes*va.size;
3318 case IQM_FLOAT: vsize *= sizeof(float); break;
3319 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3322 if (pbase + va.offset + vsize > pend)
3324 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3328 if (va.format == IQM_FLOAT && va.size == 3)
3329 vposition = (const float *)(pbase + va.offset);
3332 if (va.format == IQM_FLOAT && va.size == 2)
3333 vtexcoord = (const float *)(pbase + va.offset);
3336 if (va.format == IQM_FLOAT && va.size == 3)
3337 vnormal = (const float *)(pbase + va.offset);
3340 if (va.format == IQM_FLOAT && va.size == 4)
3341 vtangent = (const float *)(pbase + va.offset);
3343 case IQM_BLENDINDEXES:
3344 if (va.format == IQM_UBYTE && va.size == 4)
3345 vblendindexes = (const unsigned char *)(pbase + va.offset);
3347 case IQM_BLENDWEIGHTS:
3348 if (va.format == IQM_UBYTE && va.size == 4)
3349 vblendweights = (const unsigned char *)(pbase + va.offset);
3352 if (va.format == IQM_FLOAT && va.size == 4)
3353 vcolor4f = (const float *)(pbase + va.offset);
3354 if (va.format == IQM_UBYTE && va.size == 4)
3355 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3359 if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3361 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3365 text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3367 loadmodel->Draw = R_Mod_Draw;
3368 loadmodel->DrawDepth = R_Mod_DrawDepth;
3369 loadmodel->DrawDebug = R_Mod_DrawDebug;
3370 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
3371 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
3372 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
3373 loadmodel->DrawLight = R_Mod_DrawLight;
3374 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3375 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3376 loadmodel->PointSuperContents = NULL;
3377 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3379 // load external .skin files if present
3380 skinfiles = Mod_LoadSkinFiles();
3381 if (loadmodel->numskins < 1)
3382 loadmodel->numskins = 1;
3384 loadmodel->numframes = max(header.num_anims, 1);
3385 loadmodel->num_bones = header.num_joints;
3386 loadmodel->num_poses = max(header.num_frames, 1);
3387 loadmodel->submodelsurfaces_start = 0;
3388 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = header.num_meshes;
3389 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3390 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3391 loadmodel->surfmesh.num_vertices = header.num_vertexes;
3392 loadmodel->surfmesh.num_triangles = header.num_triangles;
3394 // do most allocations as one merged chunk
3395 // This is only robust for C standard types!
3396 data = (unsigned char *)Mem_Alloc(loadmodel->mempool,
3397 loadmodel->surfmesh.num_vertices * (sizeof(float[14]) + (vcolor4f || vcolor4ub ? sizeof(float[4]) : 0))
3398 + loadmodel->num_bones * sizeof(float[12])
3399 + loadmodel->num_surfaces * sizeof(int)
3400 + loadmodel->surfmesh.num_triangles * sizeof(int[3])
3401 + (loadmodel->surfmesh.num_vertices <= 65536 ? loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]) : 0)
3402 + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7])
3403 + (vblendindexes && vblendweights ? loadmodel->surfmesh.num_vertices * (sizeof(unsigned short) + sizeof(unsigned char[2][4])) : 0));
3404 // Pointers must be taken in descending order of alignment requirement!
3405 loadmodel->surfmesh.data_vertex3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3406 loadmodel->surfmesh.data_svector3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3407 loadmodel->surfmesh.data_tvector3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3408 loadmodel->surfmesh.data_normal3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3409 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3410 if (vcolor4f || vcolor4ub)
3412 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[4]);
3414 loadmodel->data_baseboneposeinverse = (float *)data; data += loadmodel->num_bones * sizeof(float[12]);
3415 loadmodel->modelsurfaces_sorted = (int *)data; data += loadmodel->num_surfaces * sizeof(int);
3416 loadmodel->surfmesh.data_element3i = (int *)data; data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
3417 loadmodel->data_poses7s = (short *)data; data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3418 if (loadmodel->surfmesh.num_vertices <= 65536)
3420 loadmodel->surfmesh.data_element3s = (unsigned short *)data; data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
3422 if (vblendindexes && vblendweights)
3424 loadmodel->surfmesh.num_blends = 0;
3425 loadmodel->surfmesh.blends = (unsigned short *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned short);
3426 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3427 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3429 // Struct alignment requirements could change so we can't assume them here
3430 // otherwise a safe-looking commit could introduce undefined behaviour!
3431 loadmodel->data_surfaces = Mem_AllocType(loadmodel->mempool, msurface_t, loadmodel->num_surfaces * sizeof(msurface_t));
3432 loadmodel->data_textures = Mem_AllocType(loadmodel->mempool, texture_t, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
3433 loadmodel->skinscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numskins * sizeof(animscene_t));
3434 loadmodel->data_bones = Mem_AllocType(loadmodel->mempool, aliasbone_t, loadmodel->num_bones * sizeof(aliasbone_t));
3435 loadmodel->animscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numframes * sizeof(animscene_t));
3436 if (vblendindexes && vblendweights)
3437 loadmodel->surfmesh.data_blendweights = Mem_AllocType(loadmodel->mempool, blendweights_t, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
3439 for (i = 0;i < loadmodel->numskins;i++)
3441 loadmodel->skinscenes[i].firstframe = i;
3442 loadmodel->skinscenes[i].framecount = 1;
3443 loadmodel->skinscenes[i].loop = true;
3444 loadmodel->skinscenes[i].framerate = 10;
3447 // load the bone info
3448 if (header.version == 1)
3450 iqmjoint1_t *injoints1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3452 if (loadmodel->num_bones)
3453 joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3454 for (i = 0;i < loadmodel->num_bones;i++)
3456 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3457 iqmjoint1_t injoint1;
3459 memcpy(&injoint1, &injoints1[i], sizeof(iqmjoint1_t));
3460 joint1[i].name = LittleLong(injoint1.name);
3461 joint1[i].parent = LittleLong(injoint1.parent);
3462 for (j = 0;j < 3;j++)
3464 joint1[i].origin[j] = LittleFloat(injoint1.origin[j]);
3465 joint1[i].rotation[j] = LittleFloat(injoint1.rotation[j]);
3466 joint1[i].scale[j] = LittleFloat(injoint1.scale[j]);
3468 dp_strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3469 loadmodel->data_bones[i].parent = joint1[i].parent;
3470 if (loadmodel->data_bones[i].parent >= i)
3471 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3472 Matrix4x4_FromDoom3Joint(&relbase, joint1[i].origin[0], joint1[i].origin[1], joint1[i].origin[2], joint1[i].rotation[0], joint1[i].rotation[1], joint1[i].rotation[2]);
3473 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3474 if (loadmodel->data_bones[i].parent >= 0)
3476 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3477 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3478 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3480 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3485 iqmjoint_t *injoints = (iqmjoint_t *)(pbase + header.ofs_joints);
3487 if (header.num_joints)
3488 joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3489 for (i = 0;i < loadmodel->num_bones;i++)
3491 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3494 memcpy(&injoint, &injoints[i], sizeof(iqmjoint_t));
3495 joint[i].name = LittleLong(injoint.name);
3496 joint[i].parent = LittleLong(injoint.parent);
3497 for (j = 0;j < 3;j++)
3499 joint[i].origin[j] = LittleFloat(injoint.origin[j]);
3500 joint[i].rotation[j] = LittleFloat(injoint.rotation[j]);
3501 joint[i].scale[j] = LittleFloat(injoint.scale[j]);
3503 joint[i].rotation[3] = LittleFloat(injoint.rotation[3]);
3504 dp_strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3505 loadmodel->data_bones[i].parent = joint[i].parent;
3506 if (loadmodel->data_bones[i].parent >= i)
3507 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3508 if (joint[i].rotation[3] > 0)
3509 Vector4Negate(joint[i].rotation, joint[i].rotation);
3510 Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3511 Matrix4x4_FromDoom3Joint(&relbase, joint[i].origin[0], joint[i].origin[1], joint[i].origin[2], joint[i].rotation[0], joint[i].rotation[1], joint[i].rotation[2]);
3512 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3513 if (loadmodel->data_bones[i].parent >= 0)
3515 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3516 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3517 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3519 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3523 // set up the animscenes based on the anims
3524 for (i = 0;i < (int)header.num_anims;i++)
3528 memcpy(&anim, &anims[i], sizeof(iqmanim_t));
3529 anim.name = LittleLong(anim.name);
3530 anim.first_frame = LittleLong(anim.first_frame);
3531 anim.num_frames = LittleLong(anim.num_frames);
3532 anim.framerate = LittleFloat(anim.framerate);
3533 anim.flags = LittleLong(anim.flags);
3534 dp_strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3535 loadmodel->animscenes[i].firstframe = anim.first_frame;
3536 loadmodel->animscenes[i].framecount = anim.num_frames;
3537 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3538 loadmodel->animscenes[i].framerate = anim.framerate;
3540 if (header.num_anims <= 0)
3542 dp_strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3543 loadmodel->animscenes[0].firstframe = 0;
3544 loadmodel->animscenes[0].framecount = 1;
3545 loadmodel->animscenes[0].loop = true;
3546 loadmodel->animscenes[0].framerate = 10;
3549 loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3550 if(mod_alias_force_animated.string[0])
3551 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3554 if (header.version == 1)
3556 iqmpose1_t *inposes1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3558 if (header.num_poses)
3559 pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3560 for (i = 0;i < (int)header.num_poses;i++)
3565 memcpy(&inpose, &inposes1[i], sizeof(iqmpose1_t));
3566 pose1[i].parent = LittleLong(inpose.parent);
3567 pose1[i].channelmask = LittleLong(inpose.channelmask);
3568 for (j = 0;j < 9;j++)
3570 pose1[i].channeloffset[j] = LittleFloat(inpose.channeloffset[j]);
3571 pose1[i].channelscale[j] = LittleFloat(inpose.channelscale[j]);
3573 f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3574 f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3575 f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3576 f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3577 f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3578 f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3580 if (header.num_frames <= 0)
3582 for (i = 0;i < loadmodel->num_bones;i++)
3585 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3586 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3587 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3593 iqmpose_t *inposes = (iqmpose_t *)(pbase + header.ofs_poses);
3595 if (header.num_poses)
3596 pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3597 for (i = 0;i < (int)header.num_poses;i++)
3602 memcpy(&inpose, &inposes[i], sizeof(iqmpose_t));
3603 pose[i].parent = LittleLong(inpose.parent);
3604 pose[i].channelmask = LittleLong(inpose.channelmask);
3605 for (j = 0;j < 10;j++)
3607 pose[i].channeloffset[j] = LittleFloat(inpose.channeloffset[j]);
3608 pose[i].channelscale[j] = LittleFloat(inpose.channelscale[j]);
3610 f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3611 f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3612 f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3613 f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3614 f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3615 f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3617 if (header.num_frames <= 0)
3619 for (i = 0;i < loadmodel->num_bones;i++)
3622 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3623 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3624 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3628 loadmodel->num_posescale = biggestorigin / 32767.0f;
3629 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3631 // load the pose data
3632 // this unaligned memory access is safe (LittleShort reads as bytes)
3633 framedata = (const unsigned short *)(pbase + header.ofs_frames);
3634 if (header.version == 1)
3636 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3638 for (j = 0;j < (int)header.num_poses;j++, k++)
3640 float qx, qy, qz, qw;
3641 loadmodel->data_poses7s[k*7 + 0] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[0] + (pose1[j].channelmask&1 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[0] : 0));
3642 loadmodel->data_poses7s[k*7 + 1] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[1] + (pose1[j].channelmask&2 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[1] : 0));
3643 loadmodel->data_poses7s[k*7 + 2] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[2] + (pose1[j].channelmask&4 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[2] : 0));
3644 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3645 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3646 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3647 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3648 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3649 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3650 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3651 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3652 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3653 // skip scale data for now
3654 if(pose1[j].channelmask&64) framedata++;
3655 if(pose1[j].channelmask&128) framedata++;
3656 if(pose1[j].channelmask&256) framedata++;
3659 if (header.num_frames <= 0)
3661 for (i = 0;i < loadmodel->num_bones;i++)
3663 float qx, qy, qz, qw;
3664 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3665 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3666 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3667 qx = joint1[i].rotation[0];
3668 qy = joint1[i].rotation[1];
3669 qz = joint1[i].rotation[2];
3670 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3671 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3672 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3673 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3674 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3675 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3681 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3683 for (j = 0;j < (int)header.num_poses;j++, k++)
3686 loadmodel->data_poses7s[k*7 + 0] = loadmodel->num_poseinvscale * (pose[j].channeloffset[0] + (pose[j].channelmask&1 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[0] : 0));
3687 loadmodel->data_poses7s[k*7 + 1] = loadmodel->num_poseinvscale * (pose[j].channeloffset[1] + (pose[j].channelmask&2 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[1] : 0));
3688 loadmodel->data_poses7s[k*7 + 2] = loadmodel->num_poseinvscale * (pose[j].channeloffset[2] + (pose[j].channelmask&4 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[2] : 0));
3689 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3690 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3691 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3692 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3694 Vector4Negate(rot, rot);
3695 Vector4Normalize2(rot, rot);
3696 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3697 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3698 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3699 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3700 // skip scale data for now
3701 if(pose[j].channelmask&128) framedata++;
3702 if(pose[j].channelmask&256) framedata++;
3703 if(pose[j].channelmask&512) framedata++;
3706 if (header.num_frames <= 0)
3708 for (i = 0;i < loadmodel->num_bones;i++)
3710 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3711 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3712 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3713 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3714 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3715 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3716 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3721 // load bounding box data
3722 if (header.ofs_bounds)
3724 float xyradius = 0, radius = 0;
3725 VectorClear(loadmodel->normalmins);
3726 VectorClear(loadmodel->normalmaxs);
3727 for (i = 0; i < (int)header.num_frames;i++)
3730 bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3731 bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3732 bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3733 bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);
3734 bound.maxs[1] = LittleFloat(bounds[i].maxs[1]);
3735 bound.maxs[2] = LittleFloat(bounds[i].maxs[2]);
3736 bound.xyradius = LittleFloat(bounds[i].xyradius);
3737 bound.radius = LittleFloat(bounds[i].radius);
3740 VectorCopy(bound.mins, loadmodel->normalmins);
3741 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3745 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3746 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3747 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3748 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3749 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3750 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3752 if (bound.xyradius > xyradius)
3753 xyradius = bound.xyradius;
3754 if (bound.radius > radius)
3755 radius = bound.radius;
3757 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3758 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3759 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3760 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3761 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3762 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3763 loadmodel->radius = radius;
3764 loadmodel->radius2 = radius * radius;
3767 // load triangle data
3768 // this unaligned memory access is safe (LittleLong reads as bytes)
3769 inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3770 outelements = loadmodel->surfmesh.data_element3i;
3771 for (i = 0;i < (int)header.num_triangles;i++)
3773 outelements[0] = LittleLong(inelements[0]);
3774 outelements[1] = LittleLong(inelements[1]);
3775 outelements[2] = LittleLong(inelements[2]);
3779 if (loadmodel->surfmesh.data_element3s)
3780 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3781 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3782 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3785 // this unaligned memory access is safe (LittleFloat reads as bytes)
3786 outvertex = loadmodel->surfmesh.data_vertex3f;
3787 for (i = 0;i < (int)header.num_vertexes;i++)
3789 outvertex[0] = LittleFloat(vposition[0]);
3790 outvertex[1] = LittleFloat(vposition[1]);
3791 outvertex[2] = LittleFloat(vposition[2]);
3796 outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3797 // this unaligned memory access is safe (LittleFloat reads as bytes)
3798 for (i = 0;i < (int)header.num_vertexes;i++)
3800 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3801 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3806 // this unaligned memory access is safe (LittleFloat reads as bytes)
3809 outnormal = loadmodel->surfmesh.data_normal3f;
3810 for (i = 0;i < (int)header.num_vertexes;i++)
3812 outnormal[0] = LittleFloat(vnormal[0]);
3813 outnormal[1] = LittleFloat(vnormal[1]);
3814 outnormal[2] = LittleFloat(vnormal[2]);
3820 // this unaligned memory access is safe (LittleFloat reads as bytes)
3821 if(vnormal && vtangent)
3823 outnormal = loadmodel->surfmesh.data_normal3f;
3824 outsvector = loadmodel->surfmesh.data_svector3f;
3825 outtvector = loadmodel->surfmesh.data_tvector3f;
3826 for (i = 0;i < (int)header.num_vertexes;i++)
3828 outsvector[0] = LittleFloat(vtangent[0]);
3829 outsvector[1] = LittleFloat(vtangent[1]);
3830 outsvector[2] = LittleFloat(vtangent[2]);
3831 if(LittleFloat(vtangent[3]) < 0)
3832 CrossProduct(outsvector, outnormal, outtvector);
3834 CrossProduct(outnormal, outsvector, outtvector);
3842 // this unaligned memory access is safe (all bytes)
3843 if (vblendindexes && vblendweights)
3845 for (i = 0; i < (int)header.num_vertexes;i++)
3847 blendweights_t weights;
3848 memcpy(weights.index, vblendindexes + i*4, 4);
3849 memcpy(weights.influence, vblendweights + i*4, 4);
3850 loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3851 loadmodel->surfmesh.data_skeletalindex4ub[i*4 ] = weights.index[0];
3852 loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3853 loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3854 loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3855 loadmodel->surfmesh.data_skeletalweight4ub[i*4 ] = weights.influence[0];
3856 loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3857 loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3858 loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3864 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3865 // this unaligned memory access is safe (LittleFloat reads as bytes)
3866 for (i = 0;i < (int)header.num_vertexes;i++)
3868 outcolor[0] = LittleFloat(vcolor4f[0]);
3869 outcolor[1] = LittleFloat(vcolor4f[1]);
3870 outcolor[2] = LittleFloat(vcolor4f[2]);
3871 outcolor[3] = LittleFloat(vcolor4f[3]);
3878 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3879 // this unaligned memory access is safe (all bytes)
3880 for (i = 0;i < (int)header.num_vertexes;i++)
3882 outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3883 outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3884 outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3885 outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3892 for (i = 0;i < (int)header.num_meshes;i++)
3895 msurface_t *surface;
3897 memcpy(&mesh, &meshes[i], sizeof(iqmmesh_t));
3898 mesh.name = LittleLong(mesh.name);
3899 mesh.material = LittleLong(mesh.material);
3900 mesh.first_vertex = LittleLong(mesh.first_vertex);
3901 mesh.num_vertexes = LittleLong(mesh.num_vertexes);
3902 mesh.first_triangle = LittleLong(mesh.first_triangle);
3903 mesh.num_triangles = LittleLong(mesh.num_triangles);
3905 loadmodel->modelsurfaces_sorted[i] = i;
3906 surface = loadmodel->data_surfaces + i;
3907 surface->texture = loadmodel->data_textures + i;
3908 surface->num_firsttriangle = mesh.first_triangle;
3909 surface->num_triangles = mesh.num_triangles;
3910 surface->num_firstvertex = mesh.first_vertex;
3911 surface->num_vertices = mesh.num_vertexes;
3913 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
3916 Mod_FreeSkinFiles(skinfiles);
3917 Mod_MakeSortedSurfaces(loadmodel);
3919 // compute all the mesh information that was not loaded from the file
3921 Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, r_smoothnormals_areaweighting.integer != 0);
3922 if (!vnormal || !vtangent)
3923 Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
3924 if (!header.ofs_bounds)
3925 Mod_Alias_CalculateBoundingBox();
3927 // Always make a BIH for the first frame, we can use it where possible.
3928 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3929 if (!loadmodel->surfmesh.isanimated)
3931 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3932 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3933 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3934 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3935 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3938 if (joint) { Mem_Free(joint); joint = NULL; }
3939 if (joint1) { Mem_Free(joint1); joint1 = NULL; }
3940 if (pose) { Mem_Free(pose); pose = NULL; }
3941 if (pose1) { Mem_Free(pose1); pose1 = NULL; }