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 loadmodel->surfmesh.num_vertices = meshvertices;
2259 loadmodel->surfmesh.num_triangles = meshtriangles;
2260 loadmodel->surfmesh.num_blends = 0;
2262 // do most allocations as one merged chunk
2263 // This is only robust for C standard types!
2264 data = (unsigned char *)Mem_Alloc(loadmodel->mempool,
2265 loadmodel->num_surfaces * sizeof(int)
2266 + meshtriangles * sizeof(int[3])
2267 + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0)
2268 + meshvertices * (sizeof(float[14]) + sizeof(unsigned short) + sizeof(unsigned char[2][4]))
2269 + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7])
2270 + loadmodel->num_bones * sizeof(float[12]));
2271 // Pointers must be taken in descending order of alignment requirement!
2272 loadmodel->surfmesh.data_vertex3f = (float *)data; data += meshvertices * sizeof(float[3]);
2273 loadmodel->surfmesh.data_svector3f = (float *)data; data += meshvertices * sizeof(float[3]);
2274 loadmodel->surfmesh.data_tvector3f = (float *)data; data += meshvertices * sizeof(float[3]);
2275 loadmodel->surfmesh.data_normal3f = (float *)data; data += meshvertices * sizeof(float[3]);
2276 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data; data += meshvertices * sizeof(float[2]);
2277 loadmodel->data_baseboneposeinverse = (float *)data; data += loadmodel->num_bones * sizeof(float[12]);
2278 loadmodel->modelsurfaces_sorted = (int *)data; data += loadmodel->num_surfaces * sizeof(int);
2279 loadmodel->surfmesh.data_element3i = (int *)data; data += meshtriangles * sizeof(int[3]);
2280 loadmodel->surfmesh.blends = (unsigned short *)data; data += meshvertices * sizeof(unsigned short);
2281 if (meshvertices <= 65536)
2283 loadmodel->surfmesh.data_element3s = (unsigned short *)data; data += meshtriangles * sizeof(unsigned short[3]);
2285 loadmodel->data_poses7s = (short *)data; data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2286 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data; data += meshvertices * sizeof(unsigned char[4]);
2287 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data; data += meshvertices * sizeof(unsigned char[4]);
2288 // Struct alignment requirements could change so we can't assume them here
2289 // otherwise a safe-looking commit could introduce undefined behaviour!
2290 loadmodel->data_surfaces = Mem_AllocType(loadmodel->mempool, msurface_t, loadmodel->num_surfaces * sizeof(msurface_t));
2291 loadmodel->data_textures = Mem_AllocType(loadmodel->mempool, texture_t, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
2292 loadmodel->skinscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numskins * sizeof(animscene_t));
2293 loadmodel->data_bones = Mem_AllocType(loadmodel->mempool, aliasbone_t, loadmodel->num_bones * sizeof(aliasbone_t));
2294 loadmodel->animscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numframes * sizeof(animscene_t));
2295 loadmodel->surfmesh.data_blendweights = Mem_AllocType(loadmodel->mempool, blendweights_t, meshvertices * sizeof(blendweights_t));
2297 for (i = 0;i < loadmodel->numskins;i++)
2299 loadmodel->skinscenes[i].firstframe = i;
2300 loadmodel->skinscenes[i].framecount = 1;
2301 loadmodel->skinscenes[i].loop = true;
2302 loadmodel->skinscenes[i].framerate = 10;
2305 // load the bone info
2306 bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2307 for (i = 0;i < loadmodel->num_bones;i++)
2309 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2310 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2311 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2312 if (loadmodel->data_bones[i].parent >= i)
2313 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2317 frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2318 // figure out scale of model from root bone, for compatibility with old dpmodel versions
2319 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2320 tempvec[0] = BigFloat(poses[0]);
2321 tempvec[1] = BigFloat(poses[1]);
2322 tempvec[2] = BigFloat(poses[2]);
2323 modelscale = VectorLength(tempvec);
2325 for (i = 0;i < loadmodel->numframes;i++)
2327 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2328 loadmodel->animscenes[i].firstframe = i;
2329 loadmodel->animscenes[i].framecount = 1;
2330 loadmodel->animscenes[i].loop = true;
2331 loadmodel->animscenes[i].framerate = 10;
2332 // load the bone poses for this frame
2333 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2334 for (j = 0;j < loadmodel->num_bones*12;j++)
2336 f = fabs(BigFloat(poses[j]));
2337 biggestorigin = max(biggestorigin, f);
2339 // stuff not processed here: mins, maxs, yawradius, allradius
2341 loadmodel->num_posescale = biggestorigin / 32767.0f;
2342 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2343 for (i = 0;i < loadmodel->numframes;i++)
2345 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2346 for (j = 0;j < loadmodel->num_bones;j++)
2349 matrix4x4_t posematrix;
2350 for (k = 0;k < 12;k++)
2351 pose[k] = BigFloat(frameposes[j*12+k]);
2352 // scale child bones to match the root scale
2353 if (loadmodel->data_bones[j].parent >= 0)
2355 pose[3] *= modelscale;
2356 pose[7] *= modelscale;
2357 pose[11] *= modelscale;
2359 // normalize rotation matrix
2360 VectorNormalize(pose + 0);
2361 VectorNormalize(pose + 4);
2362 VectorNormalize(pose + 8);
2363 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2364 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2368 // load the meshes now
2369 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2372 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2373 // (converting from weight-blending skeletal animation to
2374 // deformation-based skeletal animation)
2375 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2376 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2377 for (i = 0;i < loadmodel->num_bones;i++)
2380 for (k = 0;k < 12;k++)
2381 m[k] = BigFloat(poses[i*12+k]);
2382 if (loadmodel->data_bones[i].parent >= 0)
2383 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2385 for (k = 0;k < 12;k++)
2386 bonepose[12*i+k] = m[k];
2388 for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2390 const int *inelements;
2392 unsigned short *outelement3s;
2393 const float *intexcoord;
2394 msurface_t *surface;
2396 loadmodel->modelsurfaces_sorted[i] = i;
2397 surface = loadmodel->data_surfaces + i;
2398 surface->texture = loadmodel->data_textures + i;
2399 surface->num_firsttriangle = meshtriangles;
2400 surface->num_triangles = BigLong(dpmmesh->num_tris);
2401 surface->num_firstvertex = meshvertices;
2402 surface->num_vertices = BigLong(dpmmesh->num_verts);
2403 meshvertices += surface->num_vertices;
2404 meshtriangles += surface->num_triangles;
2406 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2407 outelement3i = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2408 outelement3s = loadmodel->surfmesh.data_element3s ? loadmodel->surfmesh.data_element3s + surface->num_firsttriangle * 3 : NULL;
2409 for (j = 0;j < surface->num_triangles;j++)
2411 // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2412 outelement3i[j * 3 + 0] = surface->num_firstvertex + BigLong(inelements[j * 3 + 2]);
2413 outelement3i[j * 3 + 1] = surface->num_firstvertex + BigLong(inelements[j * 3 + 1]);
2414 outelement3i[j * 3 + 2] = surface->num_firstvertex + BigLong(inelements[j * 3 + 0]);
2417 outelement3s[j * 3 + 0] = outelement3i[j * 3 + 0];
2418 outelement3s[j * 3 + 1] = outelement3i[j * 3 + 1];
2419 outelement3s[j * 3 + 2] = outelement3i[j * 3 + 2];
2423 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2424 for (j = 0;j < surface->num_vertices*2;j++)
2425 loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2427 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2428 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2430 int weightindex[4] = { 0, 0, 0, 0 };
2431 float weightinfluence[4] = { 0, 0, 0, 0 };
2433 int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2434 data += sizeof(dpmvertex_t);
2435 for (k = 0;k < numweights;k++)
2437 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2438 int boneindex = BigLong(vert->bonenum);
2439 const float *m = bonepose + 12 * boneindex;
2440 float influence = BigFloat(vert->influence);
2441 float relativeorigin[3], relativenormal[3];
2442 relativeorigin[0] = BigFloat(vert->origin[0]);
2443 relativeorigin[1] = BigFloat(vert->origin[1]);
2444 relativeorigin[2] = BigFloat(vert->origin[2]);
2445 relativenormal[0] = BigFloat(vert->normal[0]);
2446 relativenormal[1] = BigFloat(vert->normal[1]);
2447 relativenormal[2] = BigFloat(vert->normal[2]);
2448 // blend the vertex bone weights into the base mesh
2449 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2450 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2451 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2452 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2453 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2454 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2457 // store the first (and often only) weight
2458 weightinfluence[0] = influence;
2459 weightindex[0] = boneindex;
2463 // sort the new weight into this vertex's weight table
2464 // (which only accepts up to 4 bones per vertex)
2465 for (l = 0;l < 4;l++)
2467 if (weightinfluence[l] < influence)
2469 // move weaker influence weights out of the way first
2471 for (l2 = 3;l2 > l;l2--)
2473 weightinfluence[l2] = weightinfluence[l2-1];
2474 weightindex[l2] = weightindex[l2-1];
2476 // store the new weight
2477 weightinfluence[l] = influence;
2478 weightindex[l] = boneindex;
2483 data += sizeof(dpmbonevert_t);
2485 loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2486 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = weightindex[0];
2487 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2488 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2489 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2490 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
2491 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2492 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2493 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2496 // since dpm models do not have named sections, reuse their shader name as the section name
2497 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2499 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__);
2501 if (loadmodel->surfmesh.num_blends < meshvertices)
2502 loadmodel->surfmesh.data_blendweights = Mem_ReallocType(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, blendweights_t, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2504 Mod_FreeSkinFiles(skinfiles);
2505 Mod_MakeSortedSurfaces(loadmodel);
2507 // compute all the mesh information that was not loaded from the file
2508 Mod_BuildBaseBonePoses();
2509 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);
2510 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2511 if(mod_alias_force_animated.string[0])
2512 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2514 // Always make a BIH for the first frame, we can use it where possible.
2515 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2516 if (!loadmodel->surfmesh.isanimated)
2518 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2519 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2520 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2521 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2522 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2526 // no idea why PSK/PSA files contain weird quaternions but they do...
2527 #define PSKQUATNEGATIONS
2528 void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
2530 int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2531 int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2532 fs_offset_t filesize;
2537 pskboneinfo_t *bones;
2538 pskrawweights_t *rawweights;
2539 //pskboneinfo_t *animbones;
2540 pskaniminfo_t *anims;
2541 pskanimkeys_t *animkeys;
2542 void *animfilebuffer, *animbuffer, *animbufferend;
2543 unsigned char *data;
2545 skinfile_t *skinfiles;
2546 char animname[MAX_QPATH];
2548 float biggestorigin;
2550 pchunk = (pskchunk_t *)buffer;
2551 if (strcmp(pchunk->id, "ACTRHEAD"))
2552 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2554 loadmodel->modeldatatypestring = "PSK";
2556 loadmodel->type = mod_alias;
2557 loadmodel->Draw = R_Mod_Draw;
2558 loadmodel->DrawDepth = R_Mod_DrawDepth;
2559 loadmodel->DrawDebug = R_Mod_DrawDebug;
2560 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
2561 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
2562 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
2563 loadmodel->DrawLight = R_Mod_DrawLight;
2564 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2565 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2566 loadmodel->PointSuperContents = NULL;
2567 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2568 loadmodel->synctype = ST_RAND;
2570 FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2571 dp_strlcat(animname, ".psa", sizeof(animname));
2572 animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2573 animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2575 animbufferend = animbuffer;
2594 while (buffer < bufferend)
2596 pchunk = (pskchunk_t *)buffer;
2597 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2598 version = LittleLong(pchunk->version);
2599 recordsize = LittleLong(pchunk->recordsize);
2600 numrecords = LittleLong(pchunk->numrecords);
2601 if (developer_extra.integer)
2602 Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2603 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2604 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);
2605 if (!strcmp(pchunk->id, "ACTRHEAD"))
2609 else if (!strcmp(pchunk->id, "PNTS0000"))
2612 if (recordsize != sizeof(*p))
2613 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2614 // byteswap in place and keep the pointer
2615 numpnts = numrecords;
2616 pnts = (pskpnts_t *)buffer;
2617 for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2619 p->origin[0] = LittleFloat(p->origin[0]);
2620 p->origin[1] = LittleFloat(p->origin[1]);
2621 p->origin[2] = LittleFloat(p->origin[2]);
2625 else if (!strcmp(pchunk->id, "VTXW0000"))
2628 if (recordsize != sizeof(*p))
2629 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2630 // byteswap in place and keep the pointer
2631 numvtxw = numrecords;
2632 vtxw = (pskvtxw_t *)buffer;
2633 for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2635 p->pntsindex = LittleShort(p->pntsindex);
2636 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2637 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2638 if (p->pntsindex >= numpnts)
2640 Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2646 else if (!strcmp(pchunk->id, "FACE0000"))
2649 if (recordsize != sizeof(*p))
2650 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2651 // byteswap in place and keep the pointer
2652 numfaces = numrecords;
2653 faces = (pskface_t *)buffer;
2654 for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2656 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2657 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2658 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2659 p->group = LittleLong(p->group);
2660 if (p->vtxwindex[0] >= numvtxw)
2662 Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2663 p->vtxwindex[0] = 0;
2665 if (p->vtxwindex[1] >= numvtxw)
2667 Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2668 p->vtxwindex[1] = 0;
2670 if (p->vtxwindex[2] >= numvtxw)
2672 Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2673 p->vtxwindex[2] = 0;
2678 else if (!strcmp(pchunk->id, "MATT0000"))
2681 if (recordsize != sizeof(*p))
2682 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2683 // byteswap in place and keep the pointer
2684 nummatts = numrecords;
2685 matts = (pskmatt_t *)buffer;
2686 for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2692 else if (!strcmp(pchunk->id, "REFSKELT"))
2695 if (recordsize != sizeof(*p))
2696 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2697 // byteswap in place and keep the pointer
2698 numbones = numrecords;
2699 bones = (pskboneinfo_t *)buffer;
2700 for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2702 p->numchildren = LittleLong(p->numchildren);
2703 p->parent = LittleLong(p->parent);
2704 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2705 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2706 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2707 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2708 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2709 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2710 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2711 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2712 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2713 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2714 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2715 #ifdef PSKQUATNEGATIONS
2718 p->basepose.quat[0] *= -1;
2719 p->basepose.quat[1] *= -1;
2720 p->basepose.quat[2] *= -1;
2724 p->basepose.quat[0] *= 1;
2725 p->basepose.quat[1] *= -1;
2726 p->basepose.quat[2] *= 1;
2729 if (p->parent < 0 || p->parent >= numbones)
2731 Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2737 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2740 if (recordsize != sizeof(*p))
2741 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2742 // byteswap in place and keep the pointer
2743 numrawweights = numrecords;
2744 rawweights = (pskrawweights_t *)buffer;
2745 for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2747 p->weight = LittleFloat(p->weight);
2748 p->pntsindex = LittleLong(p->pntsindex);
2749 p->boneindex = LittleLong(p->boneindex);
2750 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2752 Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2755 if (p->boneindex < 0 || p->boneindex >= numbones)
2757 Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2765 while (animbuffer < animbufferend)
2767 pchunk = (pskchunk_t *)animbuffer;
2768 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2769 version = LittleLong(pchunk->version);
2770 recordsize = LittleLong(pchunk->recordsize);
2771 numrecords = LittleLong(pchunk->numrecords);
2772 if (developer_extra.integer)
2773 Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2774 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2775 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);
2776 if (!strcmp(pchunk->id, "ANIMHEAD"))
2780 else if (!strcmp(pchunk->id, "BONENAMES"))
2783 if (recordsize != sizeof(*p))
2784 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2785 // byteswap in place and keep the pointer
2786 numanimbones = numrecords;
2787 //animbones = (pskboneinfo_t *)animbuffer;
2788 // NOTE: supposedly psa does not need to match the psk model, the
2789 // bones missing from the psa would simply use their base
2790 // positions from the psk, but this is hard for me to implement
2791 // and people can easily make animations that match.
2792 if (numanimbones != numbones)
2793 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2794 for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2796 p->numchildren = LittleLong(p->numchildren);
2797 p->parent = LittleLong(p->parent);
2798 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2799 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2800 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2801 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2802 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2803 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2804 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2805 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2806 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2807 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2808 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2809 #ifdef PSKQUATNEGATIONS
2812 p->basepose.quat[0] *= -1;
2813 p->basepose.quat[1] *= -1;
2814 p->basepose.quat[2] *= -1;
2818 p->basepose.quat[0] *= 1;
2819 p->basepose.quat[1] *= -1;
2820 p->basepose.quat[2] *= 1;
2823 if (p->parent < 0 || p->parent >= numanimbones)
2825 Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2828 // check that bones are the same as in the base
2829 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2830 Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2834 else if (!strcmp(pchunk->id, "ANIMINFO"))
2837 if (recordsize != sizeof(*p))
2838 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2839 // byteswap in place and keep the pointer
2840 numanims = numrecords;
2841 anims = (pskaniminfo_t *)animbuffer;
2842 for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2844 p->numbones = LittleLong(p->numbones);
2845 p->playtime = LittleFloat(p->playtime);
2846 p->fps = LittleFloat(p->fps);
2847 p->firstframe = LittleLong(p->firstframe);
2848 p->numframes = LittleLong(p->numframes);
2849 if (p->numbones != numbones)
2850 Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2854 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2857 if (recordsize != sizeof(*p))
2858 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2859 numanimkeys = numrecords;
2860 animkeys = (pskanimkeys_t *)animbuffer;
2861 for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2863 p->origin[0] = LittleFloat(p->origin[0]);
2864 p->origin[1] = LittleFloat(p->origin[1]);
2865 p->origin[2] = LittleFloat(p->origin[2]);
2866 p->quat[0] = LittleFloat(p->quat[0]);
2867 p->quat[1] = LittleFloat(p->quat[1]);
2868 p->quat[2] = LittleFloat(p->quat[2]);
2869 p->quat[3] = LittleFloat(p->quat[3]);
2870 p->frametime = LittleFloat(p->frametime);
2871 #ifdef PSKQUATNEGATIONS
2872 if (index % numbones)
2887 // TODO: allocate bonepose stuff
2890 Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2893 if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2894 Host_Error("%s: missing required chunks", loadmodel->name);
2898 loadmodel->numframes = 0;
2899 for (index = 0;index < numanims;index++)
2900 loadmodel->numframes += anims[index].numframes;
2901 if (numanimkeys != numbones * loadmodel->numframes)
2902 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2905 loadmodel->numframes = loadmodel->num_poses = 1;
2907 meshvertices = numvtxw;
2908 meshtriangles = numfaces;
2910 // load external .skin files if present
2911 skinfiles = Mod_LoadSkinFiles();
2912 if (loadmodel->numskins < 1)
2913 loadmodel->numskins = 1;
2914 loadmodel->num_bones = numbones;
2915 loadmodel->num_poses = loadmodel->numframes;
2916 loadmodel->submodelsurfaces_start = 0;
2917 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = nummatts;
2918 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2919 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2920 loadmodel->surfmesh.num_vertices = meshvertices;
2921 loadmodel->surfmesh.num_triangles = meshtriangles;
2922 // do most allocations as one merged chunk
2923 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);
2924 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2925 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2926 loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2927 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2928 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2929 loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2930 loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2931 loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2932 loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2933 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2934 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2935 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2936 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2937 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2938 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2939 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2940 loadmodel->surfmesh.num_blends = 0;
2941 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2942 if (loadmodel->surfmesh.num_vertices <= 65536)
2944 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2946 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2947 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
2949 for (i = 0;i < loadmodel->numskins;i++)
2951 loadmodel->skinscenes[i].firstframe = i;
2952 loadmodel->skinscenes[i].framecount = 1;
2953 loadmodel->skinscenes[i].loop = true;
2954 loadmodel->skinscenes[i].framerate = 10;
2958 for (index = 0, i = 0;index < nummatts;index++)
2960 // since psk models do not have named sections, reuse their shader name as the section name
2961 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2962 loadmodel->modelsurfaces_sorted[index] = index;
2963 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2964 loadmodel->data_surfaces[index].num_firstvertex = 0;
2965 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2968 // copy over the vertex locations and texcoords
2969 for (index = 0;index < numvtxw;index++)
2971 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
2972 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
2973 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
2974 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
2975 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
2978 // loading the faces is complicated because we need to sort them into surfaces by mattindex
2979 for (index = 0;index < numfaces;index++)
2980 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
2981 for (index = 0, i = 0;index < nummatts;index++)
2983 loadmodel->data_surfaces[index].num_firsttriangle = i;
2984 i += loadmodel->data_surfaces[index].num_triangles;
2985 loadmodel->data_surfaces[index].num_triangles = 0;
2987 for (index = 0;index < numfaces;index++)
2989 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
2990 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
2991 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
2992 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
2995 // copy over the bones
2996 for (index = 0;index < numbones;index++)
2998 dp_strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
2999 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
3000 if (loadmodel->data_bones[index].parent >= index)
3001 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
3004 // convert the basepose data
3005 if (loadmodel->num_bones)
3008 matrix4x4_t *basebonepose;
3009 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
3010 matrix4x4_t bonematrix;
3011 matrix4x4_t tempbonematrix;
3012 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
3013 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
3015 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]);
3016 if (loadmodel->data_bones[boneindex].parent >= 0)
3018 tempbonematrix = bonematrix;
3019 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3021 basebonepose[boneindex] = bonematrix;
3022 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3023 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3025 Mem_Free(basebonepose);
3028 // sort the psk point weights into the vertex weight tables
3029 // (which only accept up to 4 bones per vertex)
3030 for (index = 0;index < numvtxw;index++)
3032 int weightindex[4] = { 0, 0, 0, 0 };
3033 float weightinfluence[4] = { 0, 0, 0, 0 };
3035 for (j = 0;j < numrawweights;j++)
3037 if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3039 int boneindex = rawweights[j].boneindex;
3040 float influence = rawweights[j].weight;
3041 for (l = 0;l < 4;l++)
3043 if (weightinfluence[l] < influence)
3045 // move lower influence weights out of the way first
3047 for (l2 = 3;l2 > l;l2--)
3049 weightinfluence[l2] = weightinfluence[l2-1];
3050 weightindex[l2] = weightindex[l2-1];
3052 // store the new weight
3053 weightinfluence[l] = influence;
3054 weightindex[l] = boneindex;
3060 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3061 loadmodel->surfmesh.data_skeletalindex4ub[index*4 ] = weightindex[0];
3062 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3063 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3064 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3065 loadmodel->surfmesh.data_skeletalweight4ub[index*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
3066 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3067 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3068 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3070 if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3071 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3073 // set up the animscenes based on the anims
3076 for (index = 0, i = 0;index < numanims;index++)
3078 for (j = 0;j < anims[index].numframes;j++, i++)
3080 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3081 loadmodel->animscenes[i].firstframe = i;
3082 loadmodel->animscenes[i].framecount = 1;
3083 loadmodel->animscenes[i].loop = true;
3084 loadmodel->animscenes[i].framerate = anims[index].fps;
3087 // calculate the scaling value for bone origins so they can be compressed to short
3089 for (index = 0;index < numanimkeys;index++)
3091 pskanimkeys_t *k = animkeys + index;
3092 biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3093 biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3094 biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3096 loadmodel->num_posescale = biggestorigin / 32767.0f;
3097 if (loadmodel->num_posescale == 0) // don't divide by zero
3098 loadmodel->num_posescale = 1.0;
3099 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3101 // load the poses from the animkeys
3102 for (index = 0;index < numanimkeys;index++)
3104 pskanimkeys_t *k = animkeys + index;
3106 Vector4Copy(k->quat, quat);
3108 Vector4Negate(quat, quat);
3109 Vector4Normalize2(quat, quat);
3110 // compress poses to the short[7] format for longterm storage
3111 loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3112 loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3113 loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3114 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3115 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3116 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3117 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3122 dp_strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3123 loadmodel->animscenes[0].firstframe = 0;
3124 loadmodel->animscenes[0].framecount = 1;
3125 loadmodel->animscenes[0].loop = true;
3126 loadmodel->animscenes[0].framerate = 10;
3128 // calculate the scaling value for bone origins so they can be compressed to short
3130 for (index = 0;index < numbones;index++)
3132 pskboneinfo_t *p = bones + index;
3133 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3134 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3135 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3137 loadmodel->num_posescale = biggestorigin / 32767.0f;
3138 if (loadmodel->num_posescale == 0) // don't divide by zero
3139 loadmodel->num_posescale = 1.0;
3140 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3142 // load the basepose as a frame
3143 for (index = 0;index < numbones;index++)
3145 pskboneinfo_t *p = bones + index;
3147 Vector4Copy(p->basepose.quat, quat);
3149 Vector4Negate(quat, quat);
3150 Vector4Normalize2(quat, quat);
3151 // compress poses to the short[7] format for longterm storage
3152 loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3153 loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3154 loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3155 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3156 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3157 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3158 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3162 Mod_FreeSkinFiles(skinfiles);
3164 Mem_Free(animfilebuffer);
3165 Mod_MakeSortedSurfaces(loadmodel);
3167 // compute all the mesh information that was not loaded from the file
3168 // TODO: honor smoothing groups somehow?
3169 if (loadmodel->surfmesh.data_element3s)
3170 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3171 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3172 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3173 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);
3174 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);
3175 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3176 if(mod_alias_force_animated.string[0])
3177 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3179 // Always make a BIH for the first frame, we can use it where possible.
3180 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3181 if (!loadmodel->surfmesh.isanimated)
3183 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3184 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3185 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3186 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3187 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3191 void Mod_INTERQUAKEMODEL_Load(model_t *mod, void *buffer, void *bufferend)
3193 unsigned char *data;
3195 const unsigned char *pbase, *pend;
3197 skinfile_t *skinfiles;
3199 float biggestorigin;
3200 const unsigned int *inelements;
3202 float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3203 // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3204 const float *vnormal = NULL;
3205 const float *vposition = NULL;
3206 const float *vtangent = NULL;
3207 const float *vtexcoord = NULL;
3208 const float *vcolor4f = NULL;
3209 const unsigned char *vblendindexes = NULL;
3210 const unsigned char *vblendweights = NULL;
3211 const unsigned char *vcolor4ub = NULL;
3212 const unsigned short *framedata = NULL;
3213 // temporary memory allocations (because the data in the file may be misaligned)
3214 iqmanim_t *anims = NULL;
3215 iqmbounds_t *bounds = NULL;
3216 iqmjoint1_t *joint1 = NULL;
3217 iqmjoint_t *joint = NULL;
3218 iqmmesh_t *meshes = NULL;
3219 iqmpose1_t *pose1 = NULL;
3220 iqmpose_t *pose = NULL;
3221 iqmvertexarray_t *vas = NULL;
3223 pbase = (unsigned char *)buffer;
3224 pend = (unsigned char *)bufferend;
3226 if (pbase + sizeof(iqmheader_t) > pend)
3227 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3229 // copy struct (otherwise it may be misaligned)
3230 // LadyHavoc: okay it's definitely not misaligned here, but for consistency...
3231 memcpy(&header, pbase, sizeof(iqmheader_t));
3233 if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3234 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3235 if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3236 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3238 loadmodel->modeldatatypestring = "IQM";
3240 loadmodel->type = mod_alias;
3241 loadmodel->synctype = ST_RAND;
3244 header.version = LittleLong(header.version);
3245 header.filesize = LittleLong(header.filesize);
3246 header.flags = LittleLong(header.flags);
3247 header.num_text = LittleLong(header.num_text);
3248 header.ofs_text = LittleLong(header.ofs_text);
3249 header.num_meshes = LittleLong(header.num_meshes);
3250 header.ofs_meshes = LittleLong(header.ofs_meshes);
3251 header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3252 header.num_vertexes = LittleLong(header.num_vertexes);
3253 header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3254 header.num_triangles = LittleLong(header.num_triangles);
3255 header.ofs_triangles = LittleLong(header.ofs_triangles);
3256 header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3257 header.num_joints = LittleLong(header.num_joints);
3258 header.ofs_joints = LittleLong(header.ofs_joints);
3259 header.num_poses = LittleLong(header.num_poses);
3260 header.ofs_poses = LittleLong(header.ofs_poses);
3261 header.num_anims = LittleLong(header.num_anims);
3262 header.ofs_anims = LittleLong(header.ofs_anims);
3263 header.num_frames = LittleLong(header.num_frames);
3264 header.num_framechannels = LittleLong(header.num_framechannels);
3265 header.ofs_frames = LittleLong(header.ofs_frames);
3266 header.ofs_bounds = LittleLong(header.ofs_bounds);
3267 header.num_comment = LittleLong(header.num_comment);
3268 header.ofs_comment = LittleLong(header.ofs_comment);
3269 header.num_extensions = LittleLong(header.num_extensions);
3270 header.ofs_extensions = LittleLong(header.ofs_extensions);
3272 if (header.version == 1)
3274 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3275 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3277 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3283 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3284 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3286 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3290 if (pbase + header.ofs_text + header.num_text > pend ||
3291 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3292 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3293 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3294 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3295 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3296 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3297 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3298 pbase + header.ofs_comment + header.num_comment > pend)
3300 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3304 // Structs will be copied for alignment in memory, otherwise we crash on Sparc, PowerPC and others
3305 // and get big spam from UBSan, because these offsets may not be aligned.
3306 if (header.num_vertexarrays)
3307 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3308 if (header.num_anims)
3309 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3310 if (header.ofs_bounds)
3311 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3312 if (header.num_meshes)
3313 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3315 for (i = 0;i < (int)header.num_vertexarrays;i++)
3317 iqmvertexarray_t va;
3320 memcpy(&va, &vas[i], sizeof(iqmvertexarray_t));
3321 va.type = LittleLong(va.type);
3322 va.flags = LittleLong(va.flags);
3323 va.format = LittleLong(va.format);
3324 va.size = LittleLong(va.size);
3325 va.offset = LittleLong(va.offset);
3326 vsize = header.num_vertexes*va.size;
3329 case IQM_FLOAT: vsize *= sizeof(float); break;
3330 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3333 if (pbase + va.offset + vsize > pend)
3335 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3339 if (va.format == IQM_FLOAT && va.size == 3)
3340 vposition = (const float *)(pbase + va.offset);
3343 if (va.format == IQM_FLOAT && va.size == 2)
3344 vtexcoord = (const float *)(pbase + va.offset);
3347 if (va.format == IQM_FLOAT && va.size == 3)
3348 vnormal = (const float *)(pbase + va.offset);
3351 if (va.format == IQM_FLOAT && va.size == 4)
3352 vtangent = (const float *)(pbase + va.offset);
3354 case IQM_BLENDINDEXES:
3355 if (va.format == IQM_UBYTE && va.size == 4)
3356 vblendindexes = (const unsigned char *)(pbase + va.offset);
3358 case IQM_BLENDWEIGHTS:
3359 if (va.format == IQM_UBYTE && va.size == 4)
3360 vblendweights = (const unsigned char *)(pbase + va.offset);
3363 if (va.format == IQM_FLOAT && va.size == 4)
3364 vcolor4f = (const float *)(pbase + va.offset);
3365 if (va.format == IQM_UBYTE && va.size == 4)
3366 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3370 if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3372 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3376 text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3378 loadmodel->Draw = R_Mod_Draw;
3379 loadmodel->DrawDepth = R_Mod_DrawDepth;
3380 loadmodel->DrawDebug = R_Mod_DrawDebug;
3381 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
3382 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
3383 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
3384 loadmodel->DrawLight = R_Mod_DrawLight;
3385 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3386 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3387 loadmodel->PointSuperContents = NULL;
3388 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3390 // load external .skin files if present
3391 skinfiles = Mod_LoadSkinFiles();
3392 if (loadmodel->numskins < 1)
3393 loadmodel->numskins = 1;
3395 loadmodel->numframes = max(header.num_anims, 1);
3396 loadmodel->num_bones = header.num_joints;
3397 loadmodel->num_poses = max(header.num_frames, 1);
3398 loadmodel->submodelsurfaces_start = 0;
3399 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = header.num_meshes;
3400 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3401 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3402 loadmodel->surfmesh.num_vertices = header.num_vertexes;
3403 loadmodel->surfmesh.num_triangles = header.num_triangles;
3405 // do most allocations as one merged chunk
3406 // This is only robust for C standard types!
3407 data = (unsigned char *)Mem_Alloc(loadmodel->mempool,
3408 loadmodel->surfmesh.num_vertices * (sizeof(float[14]) + (vcolor4f || vcolor4ub ? sizeof(float[4]) : 0))
3409 + loadmodel->num_bones * sizeof(float[12])
3410 + loadmodel->num_surfaces * sizeof(int)
3411 + loadmodel->surfmesh.num_triangles * sizeof(int[3])
3412 + (loadmodel->surfmesh.num_vertices <= 65536 ? loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]) : 0)
3413 + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7])
3414 + (vblendindexes && vblendweights ? loadmodel->surfmesh.num_vertices * (sizeof(unsigned short) + sizeof(unsigned char[2][4])) : 0));
3415 // Pointers must be taken in descending order of alignment requirement!
3416 loadmodel->surfmesh.data_vertex3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3417 loadmodel->surfmesh.data_svector3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3418 loadmodel->surfmesh.data_tvector3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3419 loadmodel->surfmesh.data_normal3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3420 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3421 if (vcolor4f || vcolor4ub)
3423 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[4]);
3425 loadmodel->data_baseboneposeinverse = (float *)data; data += loadmodel->num_bones * sizeof(float[12]);
3426 loadmodel->modelsurfaces_sorted = (int *)data; data += loadmodel->num_surfaces * sizeof(int);
3427 loadmodel->surfmesh.data_element3i = (int *)data; data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
3428 loadmodel->data_poses7s = (short *)data; data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3429 if (loadmodel->surfmesh.num_vertices <= 65536)
3431 loadmodel->surfmesh.data_element3s = (unsigned short *)data; data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
3433 if (vblendindexes && vblendweights)
3435 loadmodel->surfmesh.num_blends = 0;
3436 loadmodel->surfmesh.blends = (unsigned short *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned short);
3437 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3438 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3440 // Struct alignment requirements could change so we can't assume them here
3441 // otherwise a safe-looking commit could introduce undefined behaviour!
3442 loadmodel->data_surfaces = Mem_AllocType(loadmodel->mempool, msurface_t, loadmodel->num_surfaces * sizeof(msurface_t));
3443 loadmodel->data_textures = Mem_AllocType(loadmodel->mempool, texture_t, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
3444 loadmodel->skinscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numskins * sizeof(animscene_t));
3445 loadmodel->data_bones = Mem_AllocType(loadmodel->mempool, aliasbone_t, loadmodel->num_bones * sizeof(aliasbone_t));
3446 loadmodel->animscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numframes * sizeof(animscene_t));
3447 if (vblendindexes && vblendweights)
3448 loadmodel->surfmesh.data_blendweights = Mem_AllocType(loadmodel->mempool, blendweights_t, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
3450 for (i = 0;i < loadmodel->numskins;i++)
3452 loadmodel->skinscenes[i].firstframe = i;
3453 loadmodel->skinscenes[i].framecount = 1;
3454 loadmodel->skinscenes[i].loop = true;
3455 loadmodel->skinscenes[i].framerate = 10;
3458 // load the bone info
3459 if (header.version == 1)
3461 iqmjoint1_t *injoints1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3463 if (loadmodel->num_bones)
3464 joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3465 for (i = 0;i < loadmodel->num_bones;i++)
3467 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3468 iqmjoint1_t injoint1;
3470 memcpy(&injoint1, &injoints1[i], sizeof(iqmjoint1_t));
3471 joint1[i].name = LittleLong(injoint1.name);
3472 joint1[i].parent = LittleLong(injoint1.parent);
3473 for (j = 0;j < 3;j++)
3475 joint1[i].origin[j] = LittleFloat(injoint1.origin[j]);
3476 joint1[i].rotation[j] = LittleFloat(injoint1.rotation[j]);
3477 joint1[i].scale[j] = LittleFloat(injoint1.scale[j]);
3479 dp_strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3480 loadmodel->data_bones[i].parent = joint1[i].parent;
3481 if (loadmodel->data_bones[i].parent >= i)
3482 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3483 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]);
3484 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3485 if (loadmodel->data_bones[i].parent >= 0)
3487 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3488 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3489 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3491 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3496 iqmjoint_t *injoints = (iqmjoint_t *)(pbase + header.ofs_joints);
3498 if (header.num_joints)
3499 joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3500 for (i = 0;i < loadmodel->num_bones;i++)
3502 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3505 memcpy(&injoint, &injoints[i], sizeof(iqmjoint_t));
3506 joint[i].name = LittleLong(injoint.name);
3507 joint[i].parent = LittleLong(injoint.parent);
3508 for (j = 0;j < 3;j++)
3510 joint[i].origin[j] = LittleFloat(injoint.origin[j]);
3511 joint[i].rotation[j] = LittleFloat(injoint.rotation[j]);
3512 joint[i].scale[j] = LittleFloat(injoint.scale[j]);
3514 joint[i].rotation[3] = LittleFloat(injoint.rotation[3]);
3515 dp_strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3516 loadmodel->data_bones[i].parent = joint[i].parent;
3517 if (loadmodel->data_bones[i].parent >= i)
3518 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3519 if (joint[i].rotation[3] > 0)
3520 Vector4Negate(joint[i].rotation, joint[i].rotation);
3521 Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3522 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]);
3523 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3524 if (loadmodel->data_bones[i].parent >= 0)
3526 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3527 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3528 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3530 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3534 // set up the animscenes based on the anims
3535 for (i = 0;i < (int)header.num_anims;i++)
3539 memcpy(&anim, &anims[i], sizeof(iqmanim_t));
3540 anim.name = LittleLong(anim.name);
3541 anim.first_frame = LittleLong(anim.first_frame);
3542 anim.num_frames = LittleLong(anim.num_frames);
3543 anim.framerate = LittleFloat(anim.framerate);
3544 anim.flags = LittleLong(anim.flags);
3545 dp_strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3546 loadmodel->animscenes[i].firstframe = anim.first_frame;
3547 loadmodel->animscenes[i].framecount = anim.num_frames;
3548 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3549 loadmodel->animscenes[i].framerate = anim.framerate;
3551 if (header.num_anims <= 0)
3553 dp_strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3554 loadmodel->animscenes[0].firstframe = 0;
3555 loadmodel->animscenes[0].framecount = 1;
3556 loadmodel->animscenes[0].loop = true;
3557 loadmodel->animscenes[0].framerate = 10;
3560 loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3561 if(mod_alias_force_animated.string[0])
3562 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3565 if (header.version == 1)
3567 iqmpose1_t *inposes1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3569 if (header.num_poses)
3570 pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3571 for (i = 0;i < (int)header.num_poses;i++)
3576 memcpy(&inpose, &inposes1[i], sizeof(iqmpose1_t));
3577 pose1[i].parent = LittleLong(inpose.parent);
3578 pose1[i].channelmask = LittleLong(inpose.channelmask);
3579 for (j = 0;j < 9;j++)
3581 pose1[i].channeloffset[j] = LittleFloat(inpose.channeloffset[j]);
3582 pose1[i].channelscale[j] = LittleFloat(inpose.channelscale[j]);
3584 f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3585 f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3586 f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3587 f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3588 f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3589 f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3591 if (header.num_frames <= 0)
3593 for (i = 0;i < loadmodel->num_bones;i++)
3596 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3597 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3598 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3604 iqmpose_t *inposes = (iqmpose_t *)(pbase + header.ofs_poses);
3606 if (header.num_poses)
3607 pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3608 for (i = 0;i < (int)header.num_poses;i++)
3613 memcpy(&inpose, &inposes[i], sizeof(iqmpose_t));
3614 pose[i].parent = LittleLong(inpose.parent);
3615 pose[i].channelmask = LittleLong(inpose.channelmask);
3616 for (j = 0;j < 10;j++)
3618 pose[i].channeloffset[j] = LittleFloat(inpose.channeloffset[j]);
3619 pose[i].channelscale[j] = LittleFloat(inpose.channelscale[j]);
3621 f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3622 f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3623 f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3624 f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3625 f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3626 f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3628 if (header.num_frames <= 0)
3630 for (i = 0;i < loadmodel->num_bones;i++)
3633 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3634 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3635 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3639 loadmodel->num_posescale = biggestorigin / 32767.0f;
3640 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3642 // load the pose data
3643 // this unaligned memory access is safe (LittleShort reads as bytes)
3644 framedata = (const unsigned short *)(pbase + header.ofs_frames);
3645 if (header.version == 1)
3647 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3649 for (j = 0;j < (int)header.num_poses;j++, k++)
3651 float qx, qy, qz, qw;
3652 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));
3653 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));
3654 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));
3655 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3656 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3657 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3658 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3659 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3660 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3661 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3662 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3663 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3664 // skip scale data for now
3665 if(pose1[j].channelmask&64) framedata++;
3666 if(pose1[j].channelmask&128) framedata++;
3667 if(pose1[j].channelmask&256) framedata++;
3670 if (header.num_frames <= 0)
3672 for (i = 0;i < loadmodel->num_bones;i++)
3674 float qx, qy, qz, qw;
3675 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3676 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3677 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3678 qx = joint1[i].rotation[0];
3679 qy = joint1[i].rotation[1];
3680 qz = joint1[i].rotation[2];
3681 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3682 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3683 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3684 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3685 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3686 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3692 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3694 for (j = 0;j < (int)header.num_poses;j++, k++)
3697 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));
3698 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));
3699 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));
3700 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3701 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3702 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3703 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3705 Vector4Negate(rot, rot);
3706 Vector4Normalize2(rot, rot);
3707 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3708 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3709 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3710 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3711 // skip scale data for now
3712 if(pose[j].channelmask&128) framedata++;
3713 if(pose[j].channelmask&256) framedata++;
3714 if(pose[j].channelmask&512) framedata++;
3717 if (header.num_frames <= 0)
3719 for (i = 0;i < loadmodel->num_bones;i++)
3721 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3722 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3723 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3724 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3725 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3726 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3727 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3732 // load bounding box data
3733 if (header.ofs_bounds)
3735 float xyradius = 0, radius = 0;
3736 VectorClear(loadmodel->normalmins);
3737 VectorClear(loadmodel->normalmaxs);
3738 for (i = 0; i < (int)header.num_frames;i++)
3741 bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3742 bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3743 bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3744 bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);
3745 bound.maxs[1] = LittleFloat(bounds[i].maxs[1]);
3746 bound.maxs[2] = LittleFloat(bounds[i].maxs[2]);
3747 bound.xyradius = LittleFloat(bounds[i].xyradius);
3748 bound.radius = LittleFloat(bounds[i].radius);
3751 VectorCopy(bound.mins, loadmodel->normalmins);
3752 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3756 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3757 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3758 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3759 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3760 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3761 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3763 if (bound.xyradius > xyradius)
3764 xyradius = bound.xyradius;
3765 if (bound.radius > radius)
3766 radius = bound.radius;
3768 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3769 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3770 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3771 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3772 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3773 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3774 loadmodel->radius = radius;
3775 loadmodel->radius2 = radius * radius;
3778 // load triangle data
3779 // this unaligned memory access is safe (LittleLong reads as bytes)
3780 inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3781 outelements = loadmodel->surfmesh.data_element3i;
3782 for (i = 0;i < (int)header.num_triangles;i++)
3784 outelements[0] = LittleLong(inelements[0]);
3785 outelements[1] = LittleLong(inelements[1]);
3786 outelements[2] = LittleLong(inelements[2]);
3790 if (loadmodel->surfmesh.data_element3s)
3791 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3792 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3793 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3796 // this unaligned memory access is safe (LittleFloat reads as bytes)
3797 outvertex = loadmodel->surfmesh.data_vertex3f;
3798 for (i = 0;i < (int)header.num_vertexes;i++)
3800 outvertex[0] = LittleFloat(vposition[0]);
3801 outvertex[1] = LittleFloat(vposition[1]);
3802 outvertex[2] = LittleFloat(vposition[2]);
3807 outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3808 // this unaligned memory access is safe (LittleFloat reads as bytes)
3809 for (i = 0;i < (int)header.num_vertexes;i++)
3811 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3812 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3817 // this unaligned memory access is safe (LittleFloat reads as bytes)
3820 outnormal = loadmodel->surfmesh.data_normal3f;
3821 for (i = 0;i < (int)header.num_vertexes;i++)
3823 outnormal[0] = LittleFloat(vnormal[0]);
3824 outnormal[1] = LittleFloat(vnormal[1]);
3825 outnormal[2] = LittleFloat(vnormal[2]);
3831 // this unaligned memory access is safe (LittleFloat reads as bytes)
3832 if(vnormal && vtangent)
3834 outnormal = loadmodel->surfmesh.data_normal3f;
3835 outsvector = loadmodel->surfmesh.data_svector3f;
3836 outtvector = loadmodel->surfmesh.data_tvector3f;
3837 for (i = 0;i < (int)header.num_vertexes;i++)
3839 outsvector[0] = LittleFloat(vtangent[0]);
3840 outsvector[1] = LittleFloat(vtangent[1]);
3841 outsvector[2] = LittleFloat(vtangent[2]);
3842 if(LittleFloat(vtangent[3]) < 0)
3843 CrossProduct(outsvector, outnormal, outtvector);
3845 CrossProduct(outnormal, outsvector, outtvector);
3853 // this unaligned memory access is safe (all bytes)
3854 if (vblendindexes && vblendweights)
3856 for (i = 0; i < (int)header.num_vertexes;i++)
3858 blendweights_t weights;
3859 memcpy(weights.index, vblendindexes + i*4, 4);
3860 memcpy(weights.influence, vblendweights + i*4, 4);
3861 loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3862 loadmodel->surfmesh.data_skeletalindex4ub[i*4 ] = weights.index[0];
3863 loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3864 loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3865 loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3866 loadmodel->surfmesh.data_skeletalweight4ub[i*4 ] = weights.influence[0];
3867 loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3868 loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3869 loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3875 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3876 // this unaligned memory access is safe (LittleFloat reads as bytes)
3877 for (i = 0;i < (int)header.num_vertexes;i++)
3879 outcolor[0] = LittleFloat(vcolor4f[0]);
3880 outcolor[1] = LittleFloat(vcolor4f[1]);
3881 outcolor[2] = LittleFloat(vcolor4f[2]);
3882 outcolor[3] = LittleFloat(vcolor4f[3]);
3889 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3890 // this unaligned memory access is safe (all bytes)
3891 for (i = 0;i < (int)header.num_vertexes;i++)
3893 outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3894 outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3895 outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3896 outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3903 for (i = 0;i < (int)header.num_meshes;i++)
3906 msurface_t *surface;
3908 memcpy(&mesh, &meshes[i], sizeof(iqmmesh_t));
3909 mesh.name = LittleLong(mesh.name);
3910 mesh.material = LittleLong(mesh.material);
3911 mesh.first_vertex = LittleLong(mesh.first_vertex);
3912 mesh.num_vertexes = LittleLong(mesh.num_vertexes);
3913 mesh.first_triangle = LittleLong(mesh.first_triangle);
3914 mesh.num_triangles = LittleLong(mesh.num_triangles);
3916 loadmodel->modelsurfaces_sorted[i] = i;
3917 surface = loadmodel->data_surfaces + i;
3918 surface->texture = loadmodel->data_textures + i;
3919 surface->num_firsttriangle = mesh.first_triangle;
3920 surface->num_triangles = mesh.num_triangles;
3921 surface->num_firstvertex = mesh.first_vertex;
3922 surface->num_vertices = mesh.num_vertexes;
3924 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
3927 Mod_FreeSkinFiles(skinfiles);
3928 Mod_MakeSortedSurfaces(loadmodel);
3930 // compute all the mesh information that was not loaded from the file
3932 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);
3933 if (!vnormal || !vtangent)
3934 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);
3935 if (!header.ofs_bounds)
3936 Mod_Alias_CalculateBoundingBox();
3938 // Always make a BIH for the first frame, we can use it where possible.
3939 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3940 if (!loadmodel->surfmesh.isanimated)
3942 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3943 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3944 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3945 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3946 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3949 if (joint) { Mem_Free(joint); joint = NULL; }
3950 if (joint1) { Mem_Free(joint1); joint1 = NULL; }
3951 if (pose) { Mem_Free(pose); pose = NULL; }
3952 if (pose1) { Mem_Free(pose1); pose1 = NULL; }