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];
2547 float biggestorigin;
2549 pchunk = (pskchunk_t *)buffer;
2550 if (strcmp(pchunk->id, "ACTRHEAD"))
2551 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2553 loadmodel->modeldatatypestring = "PSK";
2555 loadmodel->type = mod_alias;
2556 loadmodel->Draw = R_Mod_Draw;
2557 loadmodel->DrawDepth = R_Mod_DrawDepth;
2558 loadmodel->DrawDebug = R_Mod_DrawDebug;
2559 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
2560 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
2561 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
2562 loadmodel->DrawLight = R_Mod_DrawLight;
2563 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2564 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2565 loadmodel->PointSuperContents = NULL;
2566 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2567 loadmodel->synctype = ST_RAND;
2569 FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2570 dp_strlcat(animname, ".psa", sizeof(animname));
2571 animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2572 animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2574 animbufferend = animbuffer;
2593 while (buffer < bufferend)
2595 pchunk = (pskchunk_t *)buffer;
2596 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2597 version = LittleLong(pchunk->version);
2598 recordsize = LittleLong(pchunk->recordsize);
2599 numrecords = LittleLong(pchunk->numrecords);
2600 if (developer_extra.integer)
2601 Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2602 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2603 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);
2604 if (!strcmp(pchunk->id, "ACTRHEAD"))
2608 else if (!strcmp(pchunk->id, "PNTS0000"))
2611 if (recordsize != sizeof(*p))
2612 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2613 // byteswap in place and keep the pointer
2614 numpnts = numrecords;
2615 pnts = (pskpnts_t *)buffer;
2616 for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2618 p->origin[0] = LittleFloat(p->origin[0]);
2619 p->origin[1] = LittleFloat(p->origin[1]);
2620 p->origin[2] = LittleFloat(p->origin[2]);
2624 else if (!strcmp(pchunk->id, "VTXW0000"))
2627 if (recordsize != sizeof(*p))
2628 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2629 // byteswap in place and keep the pointer
2630 numvtxw = numrecords;
2631 vtxw = (pskvtxw_t *)buffer;
2632 for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2634 p->pntsindex = LittleShort(p->pntsindex);
2635 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2636 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2637 if (p->pntsindex >= numpnts)
2639 Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2645 else if (!strcmp(pchunk->id, "FACE0000"))
2648 if (recordsize != sizeof(*p))
2649 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2650 // byteswap in place and keep the pointer
2651 numfaces = numrecords;
2652 faces = (pskface_t *)buffer;
2653 for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2655 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2656 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2657 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2658 p->group = LittleLong(p->group);
2659 if (p->vtxwindex[0] >= numvtxw)
2661 Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2662 p->vtxwindex[0] = 0;
2664 if (p->vtxwindex[1] >= numvtxw)
2666 Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2667 p->vtxwindex[1] = 0;
2669 if (p->vtxwindex[2] >= numvtxw)
2671 Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2672 p->vtxwindex[2] = 0;
2677 else if (!strcmp(pchunk->id, "MATT0000"))
2680 if (recordsize != sizeof(*p))
2681 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2682 // byteswap in place and keep the pointer
2683 nummatts = numrecords;
2684 matts = (pskmatt_t *)buffer;
2685 for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2691 else if (!strcmp(pchunk->id, "REFSKELT"))
2694 if (recordsize != sizeof(*p))
2695 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2696 // byteswap in place and keep the pointer
2697 numbones = numrecords;
2698 bones = (pskboneinfo_t *)buffer;
2699 for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2701 p->numchildren = LittleLong(p->numchildren);
2702 p->parent = LittleLong(p->parent);
2703 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2704 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2705 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2706 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2707 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2708 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2709 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2710 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2711 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2712 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2713 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2714 #ifdef PSKQUATNEGATIONS
2717 p->basepose.quat[0] *= -1;
2718 p->basepose.quat[1] *= -1;
2719 p->basepose.quat[2] *= -1;
2723 p->basepose.quat[0] *= 1;
2724 p->basepose.quat[1] *= -1;
2725 p->basepose.quat[2] *= 1;
2728 if (p->parent < 0 || p->parent >= numbones)
2730 Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2736 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2739 if (recordsize != sizeof(*p))
2740 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2741 // byteswap in place and keep the pointer
2742 numrawweights = numrecords;
2743 rawweights = (pskrawweights_t *)buffer;
2744 for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2746 p->weight = LittleFloat(p->weight);
2747 p->pntsindex = LittleLong(p->pntsindex);
2748 p->boneindex = LittleLong(p->boneindex);
2749 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2751 Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2754 if (p->boneindex < 0 || p->boneindex >= numbones)
2756 Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2764 while (animbuffer < animbufferend)
2766 pchunk = (pskchunk_t *)animbuffer;
2767 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2768 version = LittleLong(pchunk->version);
2769 recordsize = LittleLong(pchunk->recordsize);
2770 numrecords = LittleLong(pchunk->numrecords);
2771 if (developer_extra.integer)
2772 Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2773 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2774 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);
2775 if (!strcmp(pchunk->id, "ANIMHEAD"))
2779 else if (!strcmp(pchunk->id, "BONENAMES"))
2782 if (recordsize != sizeof(*p))
2783 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2784 // byteswap in place and keep the pointer
2785 numanimbones = numrecords;
2786 //animbones = (pskboneinfo_t *)animbuffer;
2787 // NOTE: supposedly psa does not need to match the psk model, the
2788 // bones missing from the psa would simply use their base
2789 // positions from the psk, but this is hard for me to implement
2790 // and people can easily make animations that match.
2791 if (numanimbones != numbones)
2792 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2793 for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2795 p->numchildren = LittleLong(p->numchildren);
2796 p->parent = LittleLong(p->parent);
2797 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2798 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2799 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2800 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2801 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2802 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2803 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2804 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2805 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2806 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2807 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2808 #ifdef PSKQUATNEGATIONS
2811 p->basepose.quat[0] *= -1;
2812 p->basepose.quat[1] *= -1;
2813 p->basepose.quat[2] *= -1;
2817 p->basepose.quat[0] *= 1;
2818 p->basepose.quat[1] *= -1;
2819 p->basepose.quat[2] *= 1;
2822 if (p->parent < 0 || p->parent >= numanimbones)
2824 Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2827 // check that bones are the same as in the base
2828 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2829 Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2833 else if (!strcmp(pchunk->id, "ANIMINFO"))
2836 if (recordsize != sizeof(*p))
2837 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2838 // byteswap in place and keep the pointer
2839 numanims = numrecords;
2840 anims = (pskaniminfo_t *)animbuffer;
2841 for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2843 p->numbones = LittleLong(p->numbones);
2844 p->playtime = LittleFloat(p->playtime);
2845 p->fps = LittleFloat(p->fps);
2846 p->firstframe = LittleLong(p->firstframe);
2847 p->numframes = LittleLong(p->numframes);
2848 if (p->numbones != numbones)
2849 Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2853 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2856 if (recordsize != sizeof(*p))
2857 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2858 numanimkeys = numrecords;
2859 animkeys = (pskanimkeys_t *)animbuffer;
2860 for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2862 p->origin[0] = LittleFloat(p->origin[0]);
2863 p->origin[1] = LittleFloat(p->origin[1]);
2864 p->origin[2] = LittleFloat(p->origin[2]);
2865 p->quat[0] = LittleFloat(p->quat[0]);
2866 p->quat[1] = LittleFloat(p->quat[1]);
2867 p->quat[2] = LittleFloat(p->quat[2]);
2868 p->quat[3] = LittleFloat(p->quat[3]);
2869 p->frametime = LittleFloat(p->frametime);
2870 #ifdef PSKQUATNEGATIONS
2871 if (index % numbones)
2886 // TODO: allocate bonepose stuff
2889 Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2892 if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2893 Host_Error("%s: missing required chunks", loadmodel->name);
2897 loadmodel->numframes = 0;
2898 for (index = 0;index < numanims;index++)
2899 loadmodel->numframes += anims[index].numframes;
2900 if (numanimkeys != numbones * loadmodel->numframes)
2901 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2904 loadmodel->numframes = loadmodel->num_poses = 1;
2906 meshvertices = numvtxw;
2907 meshtriangles = numfaces;
2909 // load external .skin files if present
2910 skinfiles = Mod_LoadSkinFiles();
2911 if (loadmodel->numskins < 1)
2912 loadmodel->numskins = 1;
2913 loadmodel->num_bones = numbones;
2914 loadmodel->num_poses = loadmodel->numframes;
2915 loadmodel->submodelsurfaces_start = 0;
2916 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = nummatts;
2917 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2918 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2919 loadmodel->surfmesh.num_vertices = meshvertices;
2920 loadmodel->surfmesh.num_triangles = meshtriangles;
2922 // do most allocations as one merged chunk
2923 // This is only robust for C standard types!
2924 data = (unsigned char *)Mem_Alloc(loadmodel->mempool,
2925 loadmodel->surfmesh.num_vertices * sizeof(float[3])
2926 + loadmodel->surfmesh.num_vertices * sizeof(float[3])
2927 + loadmodel->surfmesh.num_vertices * sizeof(float[3])
2928 + loadmodel->surfmesh.num_vertices * sizeof(float[3])
2929 + loadmodel->surfmesh.num_vertices * sizeof(float[2])
2930 + loadmodel->num_bones * sizeof(float[12])
2931 + loadmodel->num_surfaces * sizeof(int)
2932 + loadmodel->surfmesh.num_triangles * sizeof(int[3])
2933 + loadmodel->surfmesh.num_vertices * sizeof(unsigned short)
2934 + ((loadmodel->surfmesh.num_vertices <= 65536) ? (loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0)
2935 + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7])
2936 + loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4])
2937 + loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
2938 // Pointers must be taken in descending order of alignment requirement!
2939 loadmodel->surfmesh.data_vertex3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2940 loadmodel->surfmesh.data_svector3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2941 loadmodel->surfmesh.data_tvector3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2942 loadmodel->surfmesh.data_normal3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2943 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2944 loadmodel->data_baseboneposeinverse = (float *)data; data += loadmodel->num_bones * sizeof(float[12]);
2945 loadmodel->modelsurfaces_sorted = (int *)data; data += loadmodel->num_surfaces * sizeof(int);
2946 loadmodel->surfmesh.data_element3i = (int *)data; data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2947 loadmodel->surfmesh.num_blends = 0;
2948 loadmodel->surfmesh.blends = (unsigned short *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned short);
2949 if (loadmodel->surfmesh.num_vertices <= 65536)
2951 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2953 loadmodel->data_poses7s = (short *)data; data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2954 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2955 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2956 // Struct alignment requirements could change so we can't assume them here
2957 // otherwise a safe-looking commit could introduce undefined behaviour!
2958 loadmodel->data_surfaces = Mem_AllocType(loadmodel->mempool, msurface_t, loadmodel->num_surfaces * sizeof(msurface_t));
2959 loadmodel->data_textures = Mem_AllocType(loadmodel->mempool, texture_t, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
2960 loadmodel->skinscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numskins * sizeof(animscene_t));
2961 loadmodel->data_bones = Mem_AllocType(loadmodel->mempool, aliasbone_t, loadmodel->num_bones * sizeof(aliasbone_t));
2962 loadmodel->animscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numframes * sizeof(animscene_t));
2963 loadmodel->surfmesh.data_blendweights = Mem_AllocType(loadmodel->mempool, blendweights_t, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
2965 for (i = 0;i < loadmodel->numskins;i++)
2967 loadmodel->skinscenes[i].firstframe = i;
2968 loadmodel->skinscenes[i].framecount = 1;
2969 loadmodel->skinscenes[i].loop = true;
2970 loadmodel->skinscenes[i].framerate = 10;
2974 for (index = 0, i = 0;index < nummatts;index++)
2976 // since psk models do not have named sections, reuse their shader name as the section name
2977 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2978 loadmodel->modelsurfaces_sorted[index] = index;
2979 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2980 loadmodel->data_surfaces[index].num_firstvertex = 0;
2981 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2984 // copy over the vertex locations and texcoords
2985 for (index = 0;index < numvtxw;index++)
2987 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
2988 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
2989 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
2990 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
2991 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
2994 // loading the faces is complicated because we need to sort them into surfaces by mattindex
2995 for (index = 0;index < numfaces;index++)
2996 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
2997 for (index = 0, i = 0;index < nummatts;index++)
2999 loadmodel->data_surfaces[index].num_firsttriangle = i;
3000 i += loadmodel->data_surfaces[index].num_triangles;
3001 loadmodel->data_surfaces[index].num_triangles = 0;
3003 for (index = 0;index < numfaces;index++)
3005 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
3006 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
3007 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
3008 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
3011 // copy over the bones
3012 for (index = 0;index < numbones;index++)
3014 dp_strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
3015 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
3016 if (loadmodel->data_bones[index].parent >= index)
3017 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
3020 // convert the basepose data
3021 if (loadmodel->num_bones)
3024 matrix4x4_t *basebonepose;
3025 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
3026 matrix4x4_t bonematrix;
3027 matrix4x4_t tempbonematrix;
3028 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
3029 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
3031 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]);
3032 if (loadmodel->data_bones[boneindex].parent >= 0)
3034 tempbonematrix = bonematrix;
3035 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3037 basebonepose[boneindex] = bonematrix;
3038 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3039 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3041 Mem_Free(basebonepose);
3044 // sort the psk point weights into the vertex weight tables
3045 // (which only accept up to 4 bones per vertex)
3046 for (index = 0;index < numvtxw;index++)
3048 int weightindex[4] = { 0, 0, 0, 0 };
3049 float weightinfluence[4] = { 0, 0, 0, 0 };
3051 for (j = 0;j < numrawweights;j++)
3053 if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3055 int boneindex = rawweights[j].boneindex;
3056 float influence = rawweights[j].weight;
3057 for (l = 0;l < 4;l++)
3059 if (weightinfluence[l] < influence)
3061 // move lower influence weights out of the way first
3063 for (l2 = 3;l2 > l;l2--)
3065 weightinfluence[l2] = weightinfluence[l2-1];
3066 weightindex[l2] = weightindex[l2-1];
3068 // store the new weight
3069 weightinfluence[l] = influence;
3070 weightindex[l] = boneindex;
3076 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3077 loadmodel->surfmesh.data_skeletalindex4ub[index*4 ] = weightindex[0];
3078 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3079 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3080 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3081 loadmodel->surfmesh.data_skeletalweight4ub[index*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
3082 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3083 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3084 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3086 if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3087 loadmodel->surfmesh.data_blendweights = Mem_ReallocType(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, blendweights_t, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3089 // set up the animscenes based on the anims
3092 for (index = 0, i = 0;index < numanims;index++)
3094 for (j = 0;j < anims[index].numframes;j++, i++)
3096 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3097 loadmodel->animscenes[i].firstframe = i;
3098 loadmodel->animscenes[i].framecount = 1;
3099 loadmodel->animscenes[i].loop = true;
3100 loadmodel->animscenes[i].framerate = anims[index].fps;
3103 // calculate the scaling value for bone origins so they can be compressed to short
3105 for (index = 0;index < numanimkeys;index++)
3107 pskanimkeys_t *k = animkeys + index;
3108 biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3109 biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3110 biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3112 loadmodel->num_posescale = biggestorigin / 32767.0f;
3113 if (loadmodel->num_posescale == 0) // don't divide by zero
3114 loadmodel->num_posescale = 1.0;
3115 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3117 // load the poses from the animkeys
3118 for (index = 0;index < numanimkeys;index++)
3120 pskanimkeys_t *k = animkeys + index;
3122 Vector4Copy(k->quat, quat);
3124 Vector4Negate(quat, quat);
3125 Vector4Normalize2(quat, quat);
3126 // compress poses to the short[7] format for longterm storage
3127 loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3128 loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3129 loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3130 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3131 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3132 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3133 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3138 dp_strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3139 loadmodel->animscenes[0].firstframe = 0;
3140 loadmodel->animscenes[0].framecount = 1;
3141 loadmodel->animscenes[0].loop = true;
3142 loadmodel->animscenes[0].framerate = 10;
3144 // calculate the scaling value for bone origins so they can be compressed to short
3146 for (index = 0;index < numbones;index++)
3148 pskboneinfo_t *p = bones + index;
3149 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3150 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3151 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3153 loadmodel->num_posescale = biggestorigin / 32767.0f;
3154 if (loadmodel->num_posescale == 0) // don't divide by zero
3155 loadmodel->num_posescale = 1.0;
3156 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3158 // load the basepose as a frame
3159 for (index = 0;index < numbones;index++)
3161 pskboneinfo_t *p = bones + index;
3163 Vector4Copy(p->basepose.quat, quat);
3165 Vector4Negate(quat, quat);
3166 Vector4Normalize2(quat, quat);
3167 // compress poses to the short[7] format for longterm storage
3168 loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3169 loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3170 loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3171 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3172 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3173 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3174 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3178 Mod_FreeSkinFiles(skinfiles);
3180 Mem_Free(animfilebuffer);
3181 Mod_MakeSortedSurfaces(loadmodel);
3183 // compute all the mesh information that was not loaded from the file
3184 // TODO: honor smoothing groups somehow?
3185 if (loadmodel->surfmesh.data_element3s)
3186 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3187 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3188 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3189 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);
3190 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);
3191 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3192 if(mod_alias_force_animated.string[0])
3193 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3195 // Always make a BIH for the first frame, we can use it where possible.
3196 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3197 if (!loadmodel->surfmesh.isanimated)
3199 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3200 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3201 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3202 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3203 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3207 void Mod_INTERQUAKEMODEL_Load(model_t *mod, void *buffer, void *bufferend)
3209 unsigned char *data;
3211 const unsigned char *pbase, *pend;
3213 skinfile_t *skinfiles;
3215 float biggestorigin;
3216 const unsigned int *inelements;
3218 float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3219 // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3220 const float *vnormal = NULL;
3221 const float *vposition = NULL;
3222 const float *vtangent = NULL;
3223 const float *vtexcoord = NULL;
3224 const float *vcolor4f = NULL;
3225 const unsigned char *vblendindexes = NULL;
3226 const unsigned char *vblendweights = NULL;
3227 const unsigned char *vcolor4ub = NULL;
3228 const unsigned short *framedata = NULL;
3229 // temporary memory allocations (because the data in the file may be misaligned)
3230 iqmanim_t *anims = NULL;
3231 iqmbounds_t *bounds = NULL;
3232 iqmjoint1_t *joint1 = NULL;
3233 iqmjoint_t *joint = NULL;
3234 iqmmesh_t *meshes = NULL;
3235 iqmpose1_t *pose1 = NULL;
3236 iqmpose_t *pose = NULL;
3237 iqmvertexarray_t *vas = NULL;
3239 pbase = (unsigned char *)buffer;
3240 pend = (unsigned char *)bufferend;
3242 if (pbase + sizeof(iqmheader_t) > pend)
3243 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3245 // copy struct (otherwise it may be misaligned)
3246 // LadyHavoc: okay it's definitely not misaligned here, but for consistency...
3247 memcpy(&header, pbase, sizeof(iqmheader_t));
3249 if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3250 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3251 if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3252 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3254 loadmodel->modeldatatypestring = "IQM";
3256 loadmodel->type = mod_alias;
3257 loadmodel->synctype = ST_RAND;
3260 header.version = LittleLong(header.version);
3261 header.filesize = LittleLong(header.filesize);
3262 header.flags = LittleLong(header.flags);
3263 header.num_text = LittleLong(header.num_text);
3264 header.ofs_text = LittleLong(header.ofs_text);
3265 header.num_meshes = LittleLong(header.num_meshes);
3266 header.ofs_meshes = LittleLong(header.ofs_meshes);
3267 header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3268 header.num_vertexes = LittleLong(header.num_vertexes);
3269 header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3270 header.num_triangles = LittleLong(header.num_triangles);
3271 header.ofs_triangles = LittleLong(header.ofs_triangles);
3272 header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3273 header.num_joints = LittleLong(header.num_joints);
3274 header.ofs_joints = LittleLong(header.ofs_joints);
3275 header.num_poses = LittleLong(header.num_poses);
3276 header.ofs_poses = LittleLong(header.ofs_poses);
3277 header.num_anims = LittleLong(header.num_anims);
3278 header.ofs_anims = LittleLong(header.ofs_anims);
3279 header.num_frames = LittleLong(header.num_frames);
3280 header.num_framechannels = LittleLong(header.num_framechannels);
3281 header.ofs_frames = LittleLong(header.ofs_frames);
3282 header.ofs_bounds = LittleLong(header.ofs_bounds);
3283 header.num_comment = LittleLong(header.num_comment);
3284 header.ofs_comment = LittleLong(header.ofs_comment);
3285 header.num_extensions = LittleLong(header.num_extensions);
3286 header.ofs_extensions = LittleLong(header.ofs_extensions);
3288 if (header.version == 1)
3290 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3291 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3293 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3299 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3300 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3302 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3306 if (pbase + header.ofs_text + header.num_text > pend ||
3307 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3308 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3309 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3310 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3311 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3312 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3313 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3314 pbase + header.ofs_comment + header.num_comment > pend)
3316 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3320 // Structs will be copied for alignment in memory, otherwise we crash on Sparc, PowerPC and others
3321 // and get big spam from UBSan, because these offsets may not be aligned.
3322 if (header.num_vertexarrays)
3323 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3324 if (header.num_anims)
3325 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3326 if (header.ofs_bounds)
3327 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3328 if (header.num_meshes)
3329 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3331 for (i = 0;i < (int)header.num_vertexarrays;i++)
3333 iqmvertexarray_t va;
3336 memcpy(&va, &vas[i], sizeof(iqmvertexarray_t));
3337 va.type = LittleLong(va.type);
3338 va.flags = LittleLong(va.flags);
3339 va.format = LittleLong(va.format);
3340 va.size = LittleLong(va.size);
3341 va.offset = LittleLong(va.offset);
3342 vsize = header.num_vertexes*va.size;
3345 case IQM_FLOAT: vsize *= sizeof(float); break;
3346 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3349 if (pbase + va.offset + vsize > pend)
3351 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3355 if (va.format == IQM_FLOAT && va.size == 3)
3356 vposition = (const float *)(pbase + va.offset);
3359 if (va.format == IQM_FLOAT && va.size == 2)
3360 vtexcoord = (const float *)(pbase + va.offset);
3363 if (va.format == IQM_FLOAT && va.size == 3)
3364 vnormal = (const float *)(pbase + va.offset);
3367 if (va.format == IQM_FLOAT && va.size == 4)
3368 vtangent = (const float *)(pbase + va.offset);
3370 case IQM_BLENDINDEXES:
3371 if (va.format == IQM_UBYTE && va.size == 4)
3372 vblendindexes = (const unsigned char *)(pbase + va.offset);
3374 case IQM_BLENDWEIGHTS:
3375 if (va.format == IQM_UBYTE && va.size == 4)
3376 vblendweights = (const unsigned char *)(pbase + va.offset);
3379 if (va.format == IQM_FLOAT && va.size == 4)
3380 vcolor4f = (const float *)(pbase + va.offset);
3381 if (va.format == IQM_UBYTE && va.size == 4)
3382 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3386 if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3388 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3392 text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3394 loadmodel->Draw = R_Mod_Draw;
3395 loadmodel->DrawDepth = R_Mod_DrawDepth;
3396 loadmodel->DrawDebug = R_Mod_DrawDebug;
3397 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
3398 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
3399 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
3400 loadmodel->DrawLight = R_Mod_DrawLight;
3401 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3402 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3403 loadmodel->PointSuperContents = NULL;
3404 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3406 // load external .skin files if present
3407 skinfiles = Mod_LoadSkinFiles();
3408 if (loadmodel->numskins < 1)
3409 loadmodel->numskins = 1;
3411 loadmodel->numframes = max(header.num_anims, 1);
3412 loadmodel->num_bones = header.num_joints;
3413 loadmodel->num_poses = max(header.num_frames, 1);
3414 loadmodel->submodelsurfaces_start = 0;
3415 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = header.num_meshes;
3416 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3417 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3418 loadmodel->surfmesh.num_vertices = header.num_vertexes;
3419 loadmodel->surfmesh.num_triangles = header.num_triangles;
3421 // do most allocations as one merged chunk
3422 // This is only robust for C standard types!
3423 data = (unsigned char *)Mem_Alloc(loadmodel->mempool,
3424 loadmodel->surfmesh.num_vertices * (sizeof(float[14]) + (vcolor4f || vcolor4ub ? sizeof(float[4]) : 0))
3425 + loadmodel->num_bones * sizeof(float[12])
3426 + loadmodel->num_surfaces * sizeof(int)
3427 + loadmodel->surfmesh.num_triangles * sizeof(int[3])
3428 + (loadmodel->surfmesh.num_vertices <= 65536 ? loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]) : 0)
3429 + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7])
3430 + (vblendindexes && vblendweights ? loadmodel->surfmesh.num_vertices * (sizeof(unsigned short) + sizeof(unsigned char[2][4])) : 0));
3431 // Pointers must be taken in descending order of alignment requirement!
3432 loadmodel->surfmesh.data_vertex3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3433 loadmodel->surfmesh.data_svector3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3434 loadmodel->surfmesh.data_tvector3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3435 loadmodel->surfmesh.data_normal3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3436 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3437 if (vcolor4f || vcolor4ub)
3439 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[4]);
3441 loadmodel->data_baseboneposeinverse = (float *)data; data += loadmodel->num_bones * sizeof(float[12]);
3442 loadmodel->modelsurfaces_sorted = (int *)data; data += loadmodel->num_surfaces * sizeof(int);
3443 loadmodel->surfmesh.data_element3i = (int *)data; data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
3444 loadmodel->data_poses7s = (short *)data; data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3445 if (loadmodel->surfmesh.num_vertices <= 65536)
3447 loadmodel->surfmesh.data_element3s = (unsigned short *)data; data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
3449 if (vblendindexes && vblendweights)
3451 loadmodel->surfmesh.num_blends = 0;
3452 loadmodel->surfmesh.blends = (unsigned short *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned short);
3453 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3454 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3456 // Struct alignment requirements could change so we can't assume them here
3457 // otherwise a safe-looking commit could introduce undefined behaviour!
3458 loadmodel->data_surfaces = Mem_AllocType(loadmodel->mempool, msurface_t, loadmodel->num_surfaces * sizeof(msurface_t));
3459 loadmodel->data_textures = Mem_AllocType(loadmodel->mempool, texture_t, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
3460 loadmodel->skinscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numskins * sizeof(animscene_t));
3461 loadmodel->data_bones = Mem_AllocType(loadmodel->mempool, aliasbone_t, loadmodel->num_bones * sizeof(aliasbone_t));
3462 loadmodel->animscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numframes * sizeof(animscene_t));
3463 if (vblendindexes && vblendweights)
3464 loadmodel->surfmesh.data_blendweights = Mem_AllocType(loadmodel->mempool, blendweights_t, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
3466 for (i = 0;i < loadmodel->numskins;i++)
3468 loadmodel->skinscenes[i].firstframe = i;
3469 loadmodel->skinscenes[i].framecount = 1;
3470 loadmodel->skinscenes[i].loop = true;
3471 loadmodel->skinscenes[i].framerate = 10;
3474 // load the bone info
3475 if (header.version == 1)
3477 iqmjoint1_t *injoints1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3479 if (loadmodel->num_bones)
3480 joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3481 for (i = 0;i < loadmodel->num_bones;i++)
3483 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3484 iqmjoint1_t injoint1;
3486 memcpy(&injoint1, &injoints1[i], sizeof(iqmjoint1_t));
3487 joint1[i].name = LittleLong(injoint1.name);
3488 joint1[i].parent = LittleLong(injoint1.parent);
3489 for (j = 0;j < 3;j++)
3491 joint1[i].origin[j] = LittleFloat(injoint1.origin[j]);
3492 joint1[i].rotation[j] = LittleFloat(injoint1.rotation[j]);
3493 joint1[i].scale[j] = LittleFloat(injoint1.scale[j]);
3495 dp_strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3496 loadmodel->data_bones[i].parent = joint1[i].parent;
3497 if (loadmodel->data_bones[i].parent >= i)
3498 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3499 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]);
3500 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3501 if (loadmodel->data_bones[i].parent >= 0)
3503 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3504 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3505 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3507 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3512 iqmjoint_t *injoints = (iqmjoint_t *)(pbase + header.ofs_joints);
3514 if (header.num_joints)
3515 joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3516 for (i = 0;i < loadmodel->num_bones;i++)
3518 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3521 memcpy(&injoint, &injoints[i], sizeof(iqmjoint_t));
3522 joint[i].name = LittleLong(injoint.name);
3523 joint[i].parent = LittleLong(injoint.parent);
3524 for (j = 0;j < 3;j++)
3526 joint[i].origin[j] = LittleFloat(injoint.origin[j]);
3527 joint[i].rotation[j] = LittleFloat(injoint.rotation[j]);
3528 joint[i].scale[j] = LittleFloat(injoint.scale[j]);
3530 joint[i].rotation[3] = LittleFloat(injoint.rotation[3]);
3531 dp_strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3532 loadmodel->data_bones[i].parent = joint[i].parent;
3533 if (loadmodel->data_bones[i].parent >= i)
3534 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3535 if (joint[i].rotation[3] > 0)
3536 Vector4Negate(joint[i].rotation, joint[i].rotation);
3537 Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3538 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]);
3539 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3540 if (loadmodel->data_bones[i].parent >= 0)
3542 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3543 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3544 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3546 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3550 // set up the animscenes based on the anims
3551 for (i = 0;i < (int)header.num_anims;i++)
3555 memcpy(&anim, &anims[i], sizeof(iqmanim_t));
3556 anim.name = LittleLong(anim.name);
3557 anim.first_frame = LittleLong(anim.first_frame);
3558 anim.num_frames = LittleLong(anim.num_frames);
3559 anim.framerate = LittleFloat(anim.framerate);
3560 anim.flags = LittleLong(anim.flags);
3561 dp_strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3562 loadmodel->animscenes[i].firstframe = anim.first_frame;
3563 loadmodel->animscenes[i].framecount = anim.num_frames;
3564 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3565 loadmodel->animscenes[i].framerate = anim.framerate;
3567 if (header.num_anims <= 0)
3569 dp_strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3570 loadmodel->animscenes[0].firstframe = 0;
3571 loadmodel->animscenes[0].framecount = 1;
3572 loadmodel->animscenes[0].loop = true;
3573 loadmodel->animscenes[0].framerate = 10;
3576 loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3577 if(mod_alias_force_animated.string[0])
3578 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3581 if (header.version == 1)
3583 iqmpose1_t *inposes1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3585 if (header.num_poses)
3586 pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3587 for (i = 0;i < (int)header.num_poses;i++)
3592 memcpy(&inpose, &inposes1[i], sizeof(iqmpose1_t));
3593 pose1[i].parent = LittleLong(inpose.parent);
3594 pose1[i].channelmask = LittleLong(inpose.channelmask);
3595 for (j = 0;j < 9;j++)
3597 pose1[i].channeloffset[j] = LittleFloat(inpose.channeloffset[j]);
3598 pose1[i].channelscale[j] = LittleFloat(inpose.channelscale[j]);
3600 f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3601 f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3602 f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3603 f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3604 f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3605 f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3607 if (header.num_frames <= 0)
3609 for (i = 0;i < loadmodel->num_bones;i++)
3612 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3613 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3614 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3620 iqmpose_t *inposes = (iqmpose_t *)(pbase + header.ofs_poses);
3622 if (header.num_poses)
3623 pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3624 for (i = 0;i < (int)header.num_poses;i++)
3629 memcpy(&inpose, &inposes[i], sizeof(iqmpose_t));
3630 pose[i].parent = LittleLong(inpose.parent);
3631 pose[i].channelmask = LittleLong(inpose.channelmask);
3632 for (j = 0;j < 10;j++)
3634 pose[i].channeloffset[j] = LittleFloat(inpose.channeloffset[j]);
3635 pose[i].channelscale[j] = LittleFloat(inpose.channelscale[j]);
3637 f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3638 f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3639 f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3640 f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3641 f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3642 f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3644 if (header.num_frames <= 0)
3646 for (i = 0;i < loadmodel->num_bones;i++)
3649 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3650 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3651 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3655 loadmodel->num_posescale = biggestorigin / 32767.0f;
3656 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3658 // load the pose data
3659 // this unaligned memory access is safe (LittleShort reads as bytes)
3660 framedata = (const unsigned short *)(pbase + header.ofs_frames);
3661 if (header.version == 1)
3663 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3665 for (j = 0;j < (int)header.num_poses;j++, k++)
3667 float qx, qy, qz, qw;
3668 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));
3669 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));
3670 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));
3671 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3672 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3673 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3674 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3675 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3676 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3677 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3678 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3679 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3680 // skip scale data for now
3681 if(pose1[j].channelmask&64) framedata++;
3682 if(pose1[j].channelmask&128) framedata++;
3683 if(pose1[j].channelmask&256) framedata++;
3686 if (header.num_frames <= 0)
3688 for (i = 0;i < loadmodel->num_bones;i++)
3690 float qx, qy, qz, qw;
3691 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3692 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3693 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3694 qx = joint1[i].rotation[0];
3695 qy = joint1[i].rotation[1];
3696 qz = joint1[i].rotation[2];
3697 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3698 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3699 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3700 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3701 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3702 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3708 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3710 for (j = 0;j < (int)header.num_poses;j++, k++)
3713 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));
3714 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));
3715 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));
3716 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3717 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3718 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3719 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3721 Vector4Negate(rot, rot);
3722 Vector4Normalize2(rot, rot);
3723 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3724 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3725 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3726 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3727 // skip scale data for now
3728 if(pose[j].channelmask&128) framedata++;
3729 if(pose[j].channelmask&256) framedata++;
3730 if(pose[j].channelmask&512) framedata++;
3733 if (header.num_frames <= 0)
3735 for (i = 0;i < loadmodel->num_bones;i++)
3737 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3738 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3739 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3740 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3741 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3742 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3743 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3748 // load bounding box data
3749 if (header.ofs_bounds)
3751 float xyradius = 0, radius = 0;
3752 VectorClear(loadmodel->normalmins);
3753 VectorClear(loadmodel->normalmaxs);
3754 for (i = 0; i < (int)header.num_frames;i++)
3757 bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3758 bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3759 bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3760 bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);
3761 bound.maxs[1] = LittleFloat(bounds[i].maxs[1]);
3762 bound.maxs[2] = LittleFloat(bounds[i].maxs[2]);
3763 bound.xyradius = LittleFloat(bounds[i].xyradius);
3764 bound.radius = LittleFloat(bounds[i].radius);
3767 VectorCopy(bound.mins, loadmodel->normalmins);
3768 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3772 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3773 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3774 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3775 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3776 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3777 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3779 if (bound.xyradius > xyradius)
3780 xyradius = bound.xyradius;
3781 if (bound.radius > radius)
3782 radius = bound.radius;
3784 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3785 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3786 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3787 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3788 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3789 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3790 loadmodel->radius = radius;
3791 loadmodel->radius2 = radius * radius;
3794 // load triangle data
3795 // this unaligned memory access is safe (LittleLong reads as bytes)
3796 inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3797 outelements = loadmodel->surfmesh.data_element3i;
3798 for (i = 0;i < (int)header.num_triangles;i++)
3800 outelements[0] = LittleLong(inelements[0]);
3801 outelements[1] = LittleLong(inelements[1]);
3802 outelements[2] = LittleLong(inelements[2]);
3806 if (loadmodel->surfmesh.data_element3s)
3807 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3808 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3809 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3812 // this unaligned memory access is safe (LittleFloat reads as bytes)
3813 outvertex = loadmodel->surfmesh.data_vertex3f;
3814 for (i = 0;i < (int)header.num_vertexes;i++)
3816 outvertex[0] = LittleFloat(vposition[0]);
3817 outvertex[1] = LittleFloat(vposition[1]);
3818 outvertex[2] = LittleFloat(vposition[2]);
3823 outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3824 // this unaligned memory access is safe (LittleFloat reads as bytes)
3825 for (i = 0;i < (int)header.num_vertexes;i++)
3827 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3828 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3833 // this unaligned memory access is safe (LittleFloat reads as bytes)
3836 outnormal = loadmodel->surfmesh.data_normal3f;
3837 for (i = 0;i < (int)header.num_vertexes;i++)
3839 outnormal[0] = LittleFloat(vnormal[0]);
3840 outnormal[1] = LittleFloat(vnormal[1]);
3841 outnormal[2] = LittleFloat(vnormal[2]);
3847 // this unaligned memory access is safe (LittleFloat reads as bytes)
3848 if(vnormal && vtangent)
3850 outnormal = loadmodel->surfmesh.data_normal3f;
3851 outsvector = loadmodel->surfmesh.data_svector3f;
3852 outtvector = loadmodel->surfmesh.data_tvector3f;
3853 for (i = 0;i < (int)header.num_vertexes;i++)
3855 outsvector[0] = LittleFloat(vtangent[0]);
3856 outsvector[1] = LittleFloat(vtangent[1]);
3857 outsvector[2] = LittleFloat(vtangent[2]);
3858 if(LittleFloat(vtangent[3]) < 0)
3859 CrossProduct(outsvector, outnormal, outtvector);
3861 CrossProduct(outnormal, outsvector, outtvector);
3869 // this unaligned memory access is safe (all bytes)
3870 if (vblendindexes && vblendweights)
3872 for (i = 0; i < (int)header.num_vertexes;i++)
3874 blendweights_t weights;
3875 memcpy(weights.index, vblendindexes + i*4, 4);
3876 memcpy(weights.influence, vblendweights + i*4, 4);
3877 loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3878 loadmodel->surfmesh.data_skeletalindex4ub[i*4 ] = weights.index[0];
3879 loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3880 loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3881 loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3882 loadmodel->surfmesh.data_skeletalweight4ub[i*4 ] = weights.influence[0];
3883 loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3884 loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3885 loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3891 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3892 // this unaligned memory access is safe (LittleFloat reads as bytes)
3893 for (i = 0;i < (int)header.num_vertexes;i++)
3895 outcolor[0] = LittleFloat(vcolor4f[0]);
3896 outcolor[1] = LittleFloat(vcolor4f[1]);
3897 outcolor[2] = LittleFloat(vcolor4f[2]);
3898 outcolor[3] = LittleFloat(vcolor4f[3]);
3905 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3906 // this unaligned memory access is safe (all bytes)
3907 for (i = 0;i < (int)header.num_vertexes;i++)
3909 outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3910 outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3911 outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3912 outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3919 for (i = 0;i < (int)header.num_meshes;i++)
3922 msurface_t *surface;
3924 memcpy(&mesh, &meshes[i], sizeof(iqmmesh_t));
3925 mesh.name = LittleLong(mesh.name);
3926 mesh.material = LittleLong(mesh.material);
3927 mesh.first_vertex = LittleLong(mesh.first_vertex);
3928 mesh.num_vertexes = LittleLong(mesh.num_vertexes);
3929 mesh.first_triangle = LittleLong(mesh.first_triangle);
3930 mesh.num_triangles = LittleLong(mesh.num_triangles);
3932 loadmodel->modelsurfaces_sorted[i] = i;
3933 surface = loadmodel->data_surfaces + i;
3934 surface->texture = loadmodel->data_textures + i;
3935 surface->num_firsttriangle = mesh.first_triangle;
3936 surface->num_triangles = mesh.num_triangles;
3937 surface->num_firstvertex = mesh.first_vertex;
3938 surface->num_vertices = mesh.num_vertexes;
3940 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
3943 Mod_FreeSkinFiles(skinfiles);
3944 Mod_MakeSortedSurfaces(loadmodel);
3946 // compute all the mesh information that was not loaded from the file
3948 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);
3949 if (!vnormal || !vtangent)
3950 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);
3951 if (!header.ofs_bounds)
3952 Mod_Alias_CalculateBoundingBox();
3954 // Always make a BIH for the first frame, we can use it where possible.
3955 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3956 if (!loadmodel->surfmesh.isanimated)
3958 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3959 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3960 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3961 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3962 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3965 if (joint) { Mem_Free(joint); joint = NULL; }
3966 if (joint1) { Mem_Free(joint1); joint1 = NULL; }
3967 if (pose) { Mem_Free(pose); pose = NULL; }
3968 if (pose1) { Mem_Free(pose1); pose1 = NULL; }