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 loadmodel->surfmesh.num_vertices = meshvertices;
1945 loadmodel->surfmesh.num_triangles = meshtriangles;
1946 loadmodel->surfmesh.num_blends = 0;
1947 loadmodel->surfmesh.data_blendweights = NULL;
1949 // do most allocations as one merged chunk
1950 // This is only robust for C standard types!
1951 data = (unsigned char *)Mem_Alloc(loadmodel->mempool,
1952 loadmodel->num_surfaces * sizeof(int)
1953 + meshtriangles * sizeof(int[3])
1954 + (meshvertices <= 65536 ? loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]) : 0)
1955 + meshvertices * (sizeof(float[14]) + sizeof(unsigned short) + sizeof(unsigned char[2][4]))
1956 + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7])
1957 + loadmodel->num_bones * sizeof(float[12]));
1958 // Pointers must be taken in descending order of alignment requirement!
1959 loadmodel->surfmesh.data_vertex3f = (float *)data; data += meshvertices * sizeof(float[3]);
1960 loadmodel->surfmesh.data_svector3f = (float *)data; data += meshvertices * sizeof(float[3]);
1961 loadmodel->surfmesh.data_tvector3f = (float *)data; data += meshvertices * sizeof(float[3]);
1962 loadmodel->surfmesh.data_normal3f = (float *)data; data += meshvertices * sizeof(float[3]);
1963 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data; data += meshvertices * sizeof(float[2]);
1964 loadmodel->data_baseboneposeinverse = (float *)data; data += loadmodel->num_bones * sizeof(float[12]);
1965 loadmodel->modelsurfaces_sorted = (int *)data; data += loadmodel->num_surfaces * sizeof(int);
1966 loadmodel->surfmesh.data_element3i = (int *)data; data += meshtriangles * sizeof(int[3]);
1967 loadmodel->surfmesh.blends = (unsigned short *)data; data += meshvertices * sizeof(unsigned short);
1968 if (loadmodel->surfmesh.num_vertices <= 65536)
1970 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
1972 loadmodel->data_poses7s = (short *)data; data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
1973 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data; data += meshvertices * sizeof(unsigned char[4]);
1974 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data; data += meshvertices * sizeof(unsigned char[4]);
1975 // Struct alignment requirements could change so we can't assume them here
1976 // otherwise a safe-looking commit could introduce undefined behaviour!
1977 loadmodel->data_surfaces = Mem_AllocType(loadmodel->mempool, msurface_t, loadmodel->num_surfaces * sizeof(msurface_t));
1978 loadmodel->data_textures = Mem_AllocType(loadmodel->mempool, texture_t, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1980 //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1981 poses = (float *) (pheader->lump_poses.start + pbase);
1982 // figure out scale of model from root bone, for compatibility with old zmodel versions
1983 tempvec[0] = BigFloat(poses[0]);
1984 tempvec[1] = BigFloat(poses[1]);
1985 tempvec[2] = BigFloat(poses[2]);
1986 modelscale = VectorLength(tempvec);
1988 for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
1990 f = fabs(BigFloat(poses[i]));
1991 biggestorigin = max(biggestorigin, f);
1993 loadmodel->num_posescale = biggestorigin / 32767.0f;
1994 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
1995 for (i = 0;i < numposes;i++)
1997 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
1998 for (j = 0;j < loadmodel->num_bones;j++)
2001 matrix4x4_t posematrix;
2002 for (k = 0;k < 12;k++)
2003 pose[k] = BigFloat(frameposes[j*12+k]);
2004 //if (j < loadmodel->num_bones)
2005 // 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));
2006 // scale child bones to match the root scale
2007 if (loadmodel->data_bones[j].parent >= 0)
2009 pose[3] *= modelscale;
2010 pose[7] *= modelscale;
2011 pose[11] *= modelscale;
2013 // normalize rotation matrix
2014 VectorNormalize(pose + 0);
2015 VectorNormalize(pose + 4);
2016 VectorNormalize(pose + 8);
2017 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2018 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2022 //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2023 verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2024 vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2025 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2026 // (converting from weight-blending skeletal animation to
2027 // deformation-based skeletal animation)
2028 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2029 for (i = 0;i < loadmodel->num_bones;i++)
2032 for (k = 0;k < 12;k++)
2033 m[k] = BigFloat(poses[i*12+k]);
2034 if (loadmodel->data_bones[i].parent >= 0)
2035 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2037 for (k = 0;k < 12;k++)
2038 bonepose[12*i+k] = m[k];
2040 for (j = 0;j < pheader->numverts;j++)
2042 // this format really should have had a per vertexweight weight value...
2043 // but since it does not, the weighting is completely ignored and
2044 // only one weight is allowed per vertex
2045 int boneindex = BigLong(vertdata[j].bonenum);
2046 const float *m = bonepose + 12 * boneindex;
2047 float relativeorigin[3];
2048 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2049 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2050 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2051 // transform the vertex bone weight into the base mesh
2052 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2053 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2054 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2055 // store the weight as the primary weight on this vertex
2056 loadmodel->surfmesh.blends[j] = boneindex;
2057 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = boneindex;
2058 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2059 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2060 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2061 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = 255;
2062 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2063 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2064 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2067 // normals and tangents are calculated after elements are loaded
2069 //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2070 outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2071 intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2072 for (i = 0;i < pheader->numverts;i++)
2074 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2075 // flip T coordinate for OpenGL
2076 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2079 //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2080 //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2081 //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2083 //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2084 //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)
2085 // byteswap, validate, and swap winding order of tris
2086 count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2087 if (pheader->lump_render.length != count)
2088 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2089 renderlist = (int *) (pheader->lump_render.start + pbase);
2090 renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2092 for (i = 0;i < loadmodel->num_surfaces;i++)
2094 int firstvertex, lastvertex;
2095 if (renderlist >= renderlistend)
2096 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2097 count = BigLong(*renderlist);renderlist++;
2098 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2099 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2101 loadmodel->modelsurfaces_sorted[i] = i;
2102 surface = loadmodel->data_surfaces + i;
2103 surface->texture = loadmodel->data_textures + i;
2104 surface->num_firsttriangle = meshtriangles;
2105 surface->num_triangles = count;
2106 meshtriangles += surface->num_triangles;
2108 // load the elements
2109 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2110 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2112 outelements[j*3+2] = BigLong(renderlist[0]);
2113 outelements[j*3+1] = BigLong(renderlist[1]);
2114 outelements[j*3+0] = BigLong(renderlist[2]);
2116 // validate the elements and find the used vertex range
2117 firstvertex = meshvertices;
2119 for (j = 0;j < surface->num_triangles * 3;j++)
2121 if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2122 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2123 firstvertex = min(firstvertex, outelements[j]);
2124 lastvertex = max(lastvertex, outelements[j]);
2126 surface->num_firstvertex = firstvertex;
2127 surface->num_vertices = lastvertex + 1 - firstvertex;
2129 // since zym models do not have named sections, reuse their shader
2130 // name as the section name
2131 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2132 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2134 Mod_FreeSkinFiles(skinfiles);
2135 Mem_Free(vertbonecounts);
2137 Mod_MakeSortedSurfaces(loadmodel);
2139 // compute all the mesh information that was not loaded from the file
2140 if (loadmodel->surfmesh.data_element3s)
2141 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2142 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2143 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2144 Mod_BuildBaseBonePoses();
2145 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);
2146 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);
2147 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2148 if(mod_alias_force_animated.string[0])
2149 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2151 // Always make a BIH for the first frame, we can use it where possible.
2152 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2153 if (!loadmodel->surfmesh.isanimated)
2155 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2156 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2157 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2158 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2159 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2163 void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend)
2165 dpmheader_t *pheader;
2169 unsigned char *pbase;
2170 int i, j, k, meshvertices, meshtriangles;
2171 skinfile_t *skinfiles;
2172 unsigned char *data;
2174 float biggestorigin, tempvec[3], modelscale;
2178 pheader = (dpmheader_t *)buffer;
2179 pbase = (unsigned char *)buffer;
2180 if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2181 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2182 if (BigLong(pheader->type) != 2)
2183 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2185 loadmodel->modeldatatypestring = "DPM";
2187 loadmodel->type = mod_alias;
2188 loadmodel->synctype = ST_RAND;
2191 pheader->type = BigLong(pheader->type);
2192 pheader->filesize = BigLong(pheader->filesize);
2193 pheader->mins[0] = BigFloat(pheader->mins[0]);
2194 pheader->mins[1] = BigFloat(pheader->mins[1]);
2195 pheader->mins[2] = BigFloat(pheader->mins[2]);
2196 pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2197 pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2198 pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2199 pheader->yawradius = BigFloat(pheader->yawradius);
2200 pheader->allradius = BigFloat(pheader->allradius);
2201 pheader->num_bones = BigLong(pheader->num_bones);
2202 pheader->num_meshs = BigLong(pheader->num_meshs);
2203 pheader->num_frames = BigLong(pheader->num_frames);
2204 pheader->ofs_bones = BigLong(pheader->ofs_bones);
2205 pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2206 pheader->ofs_frames = BigLong(pheader->ofs_frames);
2208 if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2210 Con_Printf("%s has no geometry\n", loadmodel->name);
2213 if (pheader->num_frames < 1)
2215 Con_Printf("%s has no frames\n", loadmodel->name);
2219 loadmodel->Draw = R_Mod_Draw;
2220 loadmodel->DrawDepth = R_Mod_DrawDepth;
2221 loadmodel->DrawDebug = R_Mod_DrawDebug;
2222 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
2223 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
2224 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
2225 loadmodel->DrawLight = R_Mod_DrawLight;
2226 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2227 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2228 loadmodel->PointSuperContents = NULL;
2229 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2232 // LadyHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2233 for (i = 0;i < 3;i++)
2235 loadmodel->normalmins[i] = pheader->mins[i];
2236 loadmodel->normalmaxs[i] = pheader->maxs[i];
2237 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2238 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2239 loadmodel->rotatedmins[i] = -pheader->allradius;
2240 loadmodel->rotatedmaxs[i] = pheader->allradius;
2242 loadmodel->radius = pheader->allradius;
2243 loadmodel->radius2 = pheader->allradius * pheader->allradius;
2245 // load external .skin files if present
2246 skinfiles = Mod_LoadSkinFiles();
2247 if (loadmodel->numskins < 1)
2248 loadmodel->numskins = 1;
2253 // gather combined statistics from the meshes
2254 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2255 for (i = 0;i < (int)pheader->num_meshs;i++)
2257 int numverts = BigLong(dpmmesh->num_verts);
2258 meshvertices += numverts;
2259 meshtriangles += BigLong(dpmmesh->num_tris);
2263 loadmodel->numframes = pheader->num_frames;
2264 loadmodel->num_bones = pheader->num_bones;
2265 loadmodel->num_poses = loadmodel->numframes;
2266 loadmodel->submodelsurfaces_start = 0;
2267 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = pheader->num_meshs;
2268 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2269 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2270 loadmodel->surfmesh.num_vertices = meshvertices;
2271 loadmodel->surfmesh.num_triangles = meshtriangles;
2272 loadmodel->surfmesh.num_blends = 0;
2274 // do most allocations as one merged chunk
2275 // This is only robust for C standard types!
2276 data = (unsigned char *)Mem_Alloc(loadmodel->mempool,
2277 loadmodel->num_surfaces * sizeof(int)
2278 + meshtriangles * sizeof(int[3])
2279 + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0)
2280 + meshvertices * (sizeof(float[14]) + sizeof(unsigned short) + sizeof(unsigned char[2][4]))
2281 + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7])
2282 + loadmodel->num_bones * sizeof(float[12]));
2283 // Pointers must be taken in descending order of alignment requirement!
2284 loadmodel->surfmesh.data_vertex3f = (float *)data; data += meshvertices * sizeof(float[3]);
2285 loadmodel->surfmesh.data_svector3f = (float *)data; data += meshvertices * sizeof(float[3]);
2286 loadmodel->surfmesh.data_tvector3f = (float *)data; data += meshvertices * sizeof(float[3]);
2287 loadmodel->surfmesh.data_normal3f = (float *)data; data += meshvertices * sizeof(float[3]);
2288 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data; data += meshvertices * sizeof(float[2]);
2289 loadmodel->data_baseboneposeinverse = (float *)data; data += loadmodel->num_bones * sizeof(float[12]);
2290 loadmodel->modelsurfaces_sorted = (int *)data; data += loadmodel->num_surfaces * sizeof(int);
2291 loadmodel->surfmesh.data_element3i = (int *)data; data += meshtriangles * sizeof(int[3]);
2292 loadmodel->surfmesh.blends = (unsigned short *)data; data += meshvertices * sizeof(unsigned short);
2293 if (meshvertices <= 65536)
2295 loadmodel->surfmesh.data_element3s = (unsigned short *)data; data += meshtriangles * sizeof(unsigned short[3]);
2297 loadmodel->data_poses7s = (short *)data; data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2298 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data; data += meshvertices * sizeof(unsigned char[4]);
2299 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data; data += meshvertices * sizeof(unsigned char[4]);
2300 // Struct alignment requirements could change so we can't assume them here
2301 // otherwise a safe-looking commit could introduce undefined behaviour!
2302 loadmodel->data_surfaces = Mem_AllocType(loadmodel->mempool, msurface_t, loadmodel->num_surfaces * sizeof(msurface_t));
2303 loadmodel->data_textures = Mem_AllocType(loadmodel->mempool, texture_t, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
2304 loadmodel->skinscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numskins * sizeof(animscene_t));
2305 loadmodel->data_bones = Mem_AllocType(loadmodel->mempool, aliasbone_t, loadmodel->num_bones * sizeof(aliasbone_t));
2306 loadmodel->animscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numframes * sizeof(animscene_t));
2307 loadmodel->surfmesh.data_blendweights = Mem_AllocType(loadmodel->mempool, blendweights_t, meshvertices * sizeof(blendweights_t));
2309 for (i = 0;i < loadmodel->numskins;i++)
2311 loadmodel->skinscenes[i].firstframe = i;
2312 loadmodel->skinscenes[i].framecount = 1;
2313 loadmodel->skinscenes[i].loop = true;
2314 loadmodel->skinscenes[i].framerate = 10;
2317 // load the bone info
2318 bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2319 for (i = 0;i < loadmodel->num_bones;i++)
2321 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2322 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2323 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2324 if (loadmodel->data_bones[i].parent >= i)
2325 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2329 frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2330 // figure out scale of model from root bone, for compatibility with old dpmodel versions
2331 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2332 tempvec[0] = BigFloat(poses[0]);
2333 tempvec[1] = BigFloat(poses[1]);
2334 tempvec[2] = BigFloat(poses[2]);
2335 modelscale = VectorLength(tempvec);
2337 for (i = 0;i < loadmodel->numframes;i++)
2339 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2340 loadmodel->animscenes[i].firstframe = i;
2341 loadmodel->animscenes[i].framecount = 1;
2342 loadmodel->animscenes[i].loop = true;
2343 loadmodel->animscenes[i].framerate = 10;
2344 // load the bone poses for this frame
2345 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2346 for (j = 0;j < loadmodel->num_bones*12;j++)
2348 f = fabs(BigFloat(poses[j]));
2349 biggestorigin = max(biggestorigin, f);
2351 // stuff not processed here: mins, maxs, yawradius, allradius
2353 loadmodel->num_posescale = biggestorigin / 32767.0f;
2354 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2355 for (i = 0;i < loadmodel->numframes;i++)
2357 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2358 for (j = 0;j < loadmodel->num_bones;j++)
2361 matrix4x4_t posematrix;
2362 for (k = 0;k < 12;k++)
2363 pose[k] = BigFloat(frameposes[j*12+k]);
2364 // scale child bones to match the root scale
2365 if (loadmodel->data_bones[j].parent >= 0)
2367 pose[3] *= modelscale;
2368 pose[7] *= modelscale;
2369 pose[11] *= modelscale;
2371 // normalize rotation matrix
2372 VectorNormalize(pose + 0);
2373 VectorNormalize(pose + 4);
2374 VectorNormalize(pose + 8);
2375 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2376 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2380 // load the meshes now
2381 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2384 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2385 // (converting from weight-blending skeletal animation to
2386 // deformation-based skeletal animation)
2387 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2388 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2389 for (i = 0;i < loadmodel->num_bones;i++)
2392 for (k = 0;k < 12;k++)
2393 m[k] = BigFloat(poses[i*12+k]);
2394 if (loadmodel->data_bones[i].parent >= 0)
2395 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2397 for (k = 0;k < 12;k++)
2398 bonepose[12*i+k] = m[k];
2400 for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2402 const int *inelements;
2404 unsigned short *outelement3s;
2405 const float *intexcoord;
2406 msurface_t *surface;
2408 loadmodel->modelsurfaces_sorted[i] = i;
2409 surface = loadmodel->data_surfaces + i;
2410 surface->texture = loadmodel->data_textures + i;
2411 surface->num_firsttriangle = meshtriangles;
2412 surface->num_triangles = BigLong(dpmmesh->num_tris);
2413 surface->num_firstvertex = meshvertices;
2414 surface->num_vertices = BigLong(dpmmesh->num_verts);
2415 meshvertices += surface->num_vertices;
2416 meshtriangles += surface->num_triangles;
2418 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2419 outelement3i = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2420 outelement3s = loadmodel->surfmesh.data_element3s ? loadmodel->surfmesh.data_element3s + surface->num_firsttriangle * 3 : NULL;
2421 for (j = 0;j < surface->num_triangles;j++)
2423 // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2424 outelement3i[j * 3 + 0] = surface->num_firstvertex + BigLong(inelements[j * 3 + 2]);
2425 outelement3i[j * 3 + 1] = surface->num_firstvertex + BigLong(inelements[j * 3 + 1]);
2426 outelement3i[j * 3 + 2] = surface->num_firstvertex + BigLong(inelements[j * 3 + 0]);
2429 outelement3s[j * 3 + 0] = outelement3i[j * 3 + 0];
2430 outelement3s[j * 3 + 1] = outelement3i[j * 3 + 1];
2431 outelement3s[j * 3 + 2] = outelement3i[j * 3 + 2];
2435 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2436 for (j = 0;j < surface->num_vertices*2;j++)
2437 loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2439 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2440 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2442 int weightindex[4] = { 0, 0, 0, 0 };
2443 float weightinfluence[4] = { 0, 0, 0, 0 };
2445 int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2446 data += sizeof(dpmvertex_t);
2447 for (k = 0;k < numweights;k++)
2449 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2450 int boneindex = BigLong(vert->bonenum);
2451 const float *m = bonepose + 12 * boneindex;
2452 float influence = BigFloat(vert->influence);
2453 float relativeorigin[3], relativenormal[3];
2454 relativeorigin[0] = BigFloat(vert->origin[0]);
2455 relativeorigin[1] = BigFloat(vert->origin[1]);
2456 relativeorigin[2] = BigFloat(vert->origin[2]);
2457 relativenormal[0] = BigFloat(vert->normal[0]);
2458 relativenormal[1] = BigFloat(vert->normal[1]);
2459 relativenormal[2] = BigFloat(vert->normal[2]);
2460 // blend the vertex bone weights into the base mesh
2461 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2462 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2463 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2464 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2465 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2466 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2469 // store the first (and often only) weight
2470 weightinfluence[0] = influence;
2471 weightindex[0] = boneindex;
2475 // sort the new weight into this vertex's weight table
2476 // (which only accepts up to 4 bones per vertex)
2477 for (l = 0;l < 4;l++)
2479 if (weightinfluence[l] < influence)
2481 // move weaker influence weights out of the way first
2483 for (l2 = 3;l2 > l;l2--)
2485 weightinfluence[l2] = weightinfluence[l2-1];
2486 weightindex[l2] = weightindex[l2-1];
2488 // store the new weight
2489 weightinfluence[l] = influence;
2490 weightindex[l] = boneindex;
2495 data += sizeof(dpmbonevert_t);
2497 loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2498 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = weightindex[0];
2499 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2500 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2501 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2502 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
2503 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2504 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2505 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2508 // since dpm models do not have named sections, reuse their shader name as the section name
2509 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2511 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__);
2513 if (loadmodel->surfmesh.num_blends < meshvertices)
2514 loadmodel->surfmesh.data_blendweights = Mem_ReallocType(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, blendweights_t, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2516 Mod_FreeSkinFiles(skinfiles);
2517 Mod_MakeSortedSurfaces(loadmodel);
2519 // compute all the mesh information that was not loaded from the file
2520 Mod_BuildBaseBonePoses();
2521 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);
2522 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2523 if(mod_alias_force_animated.string[0])
2524 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2526 // Always make a BIH for the first frame, we can use it where possible.
2527 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2528 if (!loadmodel->surfmesh.isanimated)
2530 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2531 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2532 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2533 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2534 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2538 // no idea why PSK/PSA files contain weird quaternions but they do...
2539 #define PSKQUATNEGATIONS
2540 void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
2542 int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2543 int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2544 fs_offset_t filesize;
2549 pskboneinfo_t *bones;
2550 pskrawweights_t *rawweights;
2551 //pskboneinfo_t *animbones;
2552 pskaniminfo_t *anims;
2553 pskanimkeys_t *animkeys;
2554 void *animfilebuffer, *animbuffer, *animbufferend;
2555 unsigned char *data;
2557 skinfile_t *skinfiles;
2558 char animname[MAX_QPATH];
2559 float biggestorigin;
2561 pchunk = (pskchunk_t *)buffer;
2562 if (strcmp(pchunk->id, "ACTRHEAD"))
2563 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2565 loadmodel->modeldatatypestring = "PSK";
2567 loadmodel->type = mod_alias;
2568 loadmodel->Draw = R_Mod_Draw;
2569 loadmodel->DrawDepth = R_Mod_DrawDepth;
2570 loadmodel->DrawDebug = R_Mod_DrawDebug;
2571 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
2572 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
2573 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
2574 loadmodel->DrawLight = R_Mod_DrawLight;
2575 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2576 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2577 loadmodel->PointSuperContents = NULL;
2578 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2579 loadmodel->synctype = ST_RAND;
2581 FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2582 dp_strlcat(animname, ".psa", sizeof(animname));
2583 animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2584 animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2586 animbufferend = animbuffer;
2605 while (buffer < bufferend)
2607 pchunk = (pskchunk_t *)buffer;
2608 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2609 version = LittleLong(pchunk->version);
2610 recordsize = LittleLong(pchunk->recordsize);
2611 numrecords = LittleLong(pchunk->numrecords);
2612 if (developer_extra.integer)
2613 Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2614 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2615 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);
2616 if (!strcmp(pchunk->id, "ACTRHEAD"))
2620 else if (!strcmp(pchunk->id, "PNTS0000"))
2623 if (recordsize != sizeof(*p))
2624 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2625 // byteswap in place and keep the pointer
2626 numpnts = numrecords;
2627 pnts = (pskpnts_t *)buffer;
2628 for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2630 p->origin[0] = LittleFloat(p->origin[0]);
2631 p->origin[1] = LittleFloat(p->origin[1]);
2632 p->origin[2] = LittleFloat(p->origin[2]);
2636 else if (!strcmp(pchunk->id, "VTXW0000"))
2639 if (recordsize != sizeof(*p))
2640 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2641 // byteswap in place and keep the pointer
2642 numvtxw = numrecords;
2643 vtxw = (pskvtxw_t *)buffer;
2644 for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2646 p->pntsindex = LittleShort(p->pntsindex);
2647 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2648 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2649 if (p->pntsindex >= numpnts)
2651 Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2657 else if (!strcmp(pchunk->id, "FACE0000"))
2660 if (recordsize != sizeof(*p))
2661 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2662 // byteswap in place and keep the pointer
2663 numfaces = numrecords;
2664 faces = (pskface_t *)buffer;
2665 for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2667 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2668 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2669 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2670 p->group = LittleLong(p->group);
2671 if (p->vtxwindex[0] >= numvtxw)
2673 Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2674 p->vtxwindex[0] = 0;
2676 if (p->vtxwindex[1] >= numvtxw)
2678 Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2679 p->vtxwindex[1] = 0;
2681 if (p->vtxwindex[2] >= numvtxw)
2683 Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2684 p->vtxwindex[2] = 0;
2689 else if (!strcmp(pchunk->id, "MATT0000"))
2692 if (recordsize != sizeof(*p))
2693 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2694 // byteswap in place and keep the pointer
2695 nummatts = numrecords;
2696 matts = (pskmatt_t *)buffer;
2697 for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2703 else if (!strcmp(pchunk->id, "REFSKELT"))
2706 if (recordsize != sizeof(*p))
2707 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2708 // byteswap in place and keep the pointer
2709 numbones = numrecords;
2710 bones = (pskboneinfo_t *)buffer;
2711 for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2713 p->numchildren = LittleLong(p->numchildren);
2714 p->parent = LittleLong(p->parent);
2715 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2716 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2717 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2718 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2719 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2720 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2721 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2722 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2723 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2724 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2725 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2726 #ifdef PSKQUATNEGATIONS
2729 p->basepose.quat[0] *= -1;
2730 p->basepose.quat[1] *= -1;
2731 p->basepose.quat[2] *= -1;
2735 p->basepose.quat[0] *= 1;
2736 p->basepose.quat[1] *= -1;
2737 p->basepose.quat[2] *= 1;
2740 if (p->parent < 0 || p->parent >= numbones)
2742 Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2748 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2751 if (recordsize != sizeof(*p))
2752 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2753 // byteswap in place and keep the pointer
2754 numrawweights = numrecords;
2755 rawweights = (pskrawweights_t *)buffer;
2756 for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2758 p->weight = LittleFloat(p->weight);
2759 p->pntsindex = LittleLong(p->pntsindex);
2760 p->boneindex = LittleLong(p->boneindex);
2761 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2763 Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2766 if (p->boneindex < 0 || p->boneindex >= numbones)
2768 Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2776 while (animbuffer < animbufferend)
2778 pchunk = (pskchunk_t *)animbuffer;
2779 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2780 version = LittleLong(pchunk->version);
2781 recordsize = LittleLong(pchunk->recordsize);
2782 numrecords = LittleLong(pchunk->numrecords);
2783 if (developer_extra.integer)
2784 Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2785 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2786 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);
2787 if (!strcmp(pchunk->id, "ANIMHEAD"))
2791 else if (!strcmp(pchunk->id, "BONENAMES"))
2794 if (recordsize != sizeof(*p))
2795 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2796 // byteswap in place and keep the pointer
2797 numanimbones = numrecords;
2798 //animbones = (pskboneinfo_t *)animbuffer;
2799 // NOTE: supposedly psa does not need to match the psk model, the
2800 // bones missing from the psa would simply use their base
2801 // positions from the psk, but this is hard for me to implement
2802 // and people can easily make animations that match.
2803 if (numanimbones != numbones)
2804 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2805 for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2807 p->numchildren = LittleLong(p->numchildren);
2808 p->parent = LittleLong(p->parent);
2809 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2810 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2811 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2812 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2813 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2814 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2815 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2816 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2817 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2818 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2819 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2820 #ifdef PSKQUATNEGATIONS
2823 p->basepose.quat[0] *= -1;
2824 p->basepose.quat[1] *= -1;
2825 p->basepose.quat[2] *= -1;
2829 p->basepose.quat[0] *= 1;
2830 p->basepose.quat[1] *= -1;
2831 p->basepose.quat[2] *= 1;
2834 if (p->parent < 0 || p->parent >= numanimbones)
2836 Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2839 // check that bones are the same as in the base
2840 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2841 Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2845 else if (!strcmp(pchunk->id, "ANIMINFO"))
2848 if (recordsize != sizeof(*p))
2849 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2850 // byteswap in place and keep the pointer
2851 numanims = numrecords;
2852 anims = (pskaniminfo_t *)animbuffer;
2853 for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2855 p->numbones = LittleLong(p->numbones);
2856 p->playtime = LittleFloat(p->playtime);
2857 p->fps = LittleFloat(p->fps);
2858 p->firstframe = LittleLong(p->firstframe);
2859 p->numframes = LittleLong(p->numframes);
2860 if (p->numbones != numbones)
2861 Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2865 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2868 if (recordsize != sizeof(*p))
2869 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2870 numanimkeys = numrecords;
2871 animkeys = (pskanimkeys_t *)animbuffer;
2872 for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2874 p->origin[0] = LittleFloat(p->origin[0]);
2875 p->origin[1] = LittleFloat(p->origin[1]);
2876 p->origin[2] = LittleFloat(p->origin[2]);
2877 p->quat[0] = LittleFloat(p->quat[0]);
2878 p->quat[1] = LittleFloat(p->quat[1]);
2879 p->quat[2] = LittleFloat(p->quat[2]);
2880 p->quat[3] = LittleFloat(p->quat[3]);
2881 p->frametime = LittleFloat(p->frametime);
2882 #ifdef PSKQUATNEGATIONS
2883 if (index % numbones)
2898 // TODO: allocate bonepose stuff
2901 Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2904 if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2905 Host_Error("%s: missing required chunks", loadmodel->name);
2909 loadmodel->numframes = 0;
2910 for (index = 0;index < numanims;index++)
2911 loadmodel->numframes += anims[index].numframes;
2912 if (numanimkeys != numbones * loadmodel->numframes)
2913 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2916 loadmodel->numframes = loadmodel->num_poses = 1;
2918 meshvertices = numvtxw;
2919 meshtriangles = numfaces;
2921 // load external .skin files if present
2922 skinfiles = Mod_LoadSkinFiles();
2923 if (loadmodel->numskins < 1)
2924 loadmodel->numskins = 1;
2925 loadmodel->num_bones = numbones;
2926 loadmodel->num_poses = loadmodel->numframes;
2927 loadmodel->submodelsurfaces_start = 0;
2928 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = nummatts;
2929 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2930 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2931 loadmodel->surfmesh.num_vertices = meshvertices;
2932 loadmodel->surfmesh.num_triangles = meshtriangles;
2934 // do most allocations as one merged chunk
2935 // This is only robust for C standard types!
2936 data = (unsigned char *)Mem_Alloc(loadmodel->mempool,
2937 loadmodel->surfmesh.num_vertices * sizeof(float[3])
2938 + loadmodel->surfmesh.num_vertices * sizeof(float[3])
2939 + loadmodel->surfmesh.num_vertices * sizeof(float[3])
2940 + loadmodel->surfmesh.num_vertices * sizeof(float[3])
2941 + loadmodel->surfmesh.num_vertices * sizeof(float[2])
2942 + loadmodel->num_bones * sizeof(float[12])
2943 + loadmodel->num_surfaces * sizeof(int)
2944 + loadmodel->surfmesh.num_triangles * sizeof(int[3])
2945 + loadmodel->surfmesh.num_vertices * sizeof(unsigned short)
2946 + ((loadmodel->surfmesh.num_vertices <= 65536) ? (loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0)
2947 + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7])
2948 + loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4])
2949 + loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
2950 // Pointers must be taken in descending order of alignment requirement!
2951 loadmodel->surfmesh.data_vertex3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2952 loadmodel->surfmesh.data_svector3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2953 loadmodel->surfmesh.data_tvector3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2954 loadmodel->surfmesh.data_normal3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2955 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2956 loadmodel->data_baseboneposeinverse = (float *)data; data += loadmodel->num_bones * sizeof(float[12]);
2957 loadmodel->modelsurfaces_sorted = (int *)data; data += loadmodel->num_surfaces * sizeof(int);
2958 loadmodel->surfmesh.data_element3i = (int *)data; data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2959 loadmodel->surfmesh.num_blends = 0;
2960 loadmodel->surfmesh.blends = (unsigned short *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned short);
2961 if (loadmodel->surfmesh.num_vertices <= 65536)
2963 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2965 loadmodel->data_poses7s = (short *)data; data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2966 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2967 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2968 // Struct alignment requirements could change so we can't assume them here
2969 // otherwise a safe-looking commit could introduce undefined behaviour!
2970 loadmodel->data_surfaces = Mem_AllocType(loadmodel->mempool, msurface_t, loadmodel->num_surfaces * sizeof(msurface_t));
2971 loadmodel->data_textures = Mem_AllocType(loadmodel->mempool, texture_t, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
2972 loadmodel->skinscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numskins * sizeof(animscene_t));
2973 loadmodel->data_bones = Mem_AllocType(loadmodel->mempool, aliasbone_t, loadmodel->num_bones * sizeof(aliasbone_t));
2974 loadmodel->animscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numframes * sizeof(animscene_t));
2975 loadmodel->surfmesh.data_blendweights = Mem_AllocType(loadmodel->mempool, blendweights_t, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
2977 for (i = 0;i < loadmodel->numskins;i++)
2979 loadmodel->skinscenes[i].firstframe = i;
2980 loadmodel->skinscenes[i].framecount = 1;
2981 loadmodel->skinscenes[i].loop = true;
2982 loadmodel->skinscenes[i].framerate = 10;
2986 for (index = 0, i = 0;index < nummatts;index++)
2988 // since psk models do not have named sections, reuse their shader name as the section name
2989 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2990 loadmodel->modelsurfaces_sorted[index] = index;
2991 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2992 loadmodel->data_surfaces[index].num_firstvertex = 0;
2993 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2996 // copy over the vertex locations and texcoords
2997 for (index = 0;index < numvtxw;index++)
2999 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
3000 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
3001 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
3002 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
3003 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
3006 // loading the faces is complicated because we need to sort them into surfaces by mattindex
3007 for (index = 0;index < numfaces;index++)
3008 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
3009 for (index = 0, i = 0;index < nummatts;index++)
3011 loadmodel->data_surfaces[index].num_firsttriangle = i;
3012 i += loadmodel->data_surfaces[index].num_triangles;
3013 loadmodel->data_surfaces[index].num_triangles = 0;
3015 for (index = 0;index < numfaces;index++)
3017 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
3018 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
3019 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
3020 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
3023 // copy over the bones
3024 for (index = 0;index < numbones;index++)
3026 dp_strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
3027 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
3028 if (loadmodel->data_bones[index].parent >= index)
3029 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
3032 // convert the basepose data
3033 if (loadmodel->num_bones)
3036 matrix4x4_t *basebonepose;
3037 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
3038 matrix4x4_t bonematrix;
3039 matrix4x4_t tempbonematrix;
3040 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
3041 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
3043 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]);
3044 if (loadmodel->data_bones[boneindex].parent >= 0)
3046 tempbonematrix = bonematrix;
3047 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3049 basebonepose[boneindex] = bonematrix;
3050 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3051 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3053 Mem_Free(basebonepose);
3056 // sort the psk point weights into the vertex weight tables
3057 // (which only accept up to 4 bones per vertex)
3058 for (index = 0;index < numvtxw;index++)
3060 int weightindex[4] = { 0, 0, 0, 0 };
3061 float weightinfluence[4] = { 0, 0, 0, 0 };
3063 for (j = 0;j < numrawweights;j++)
3065 if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3067 int boneindex = rawweights[j].boneindex;
3068 float influence = rawweights[j].weight;
3069 for (l = 0;l < 4;l++)
3071 if (weightinfluence[l] < influence)
3073 // move lower influence weights out of the way first
3075 for (l2 = 3;l2 > l;l2--)
3077 weightinfluence[l2] = weightinfluence[l2-1];
3078 weightindex[l2] = weightindex[l2-1];
3080 // store the new weight
3081 weightinfluence[l] = influence;
3082 weightindex[l] = boneindex;
3088 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3089 loadmodel->surfmesh.data_skeletalindex4ub[index*4 ] = weightindex[0];
3090 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3091 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3092 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3093 loadmodel->surfmesh.data_skeletalweight4ub[index*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
3094 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3095 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3096 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3098 if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3099 loadmodel->surfmesh.data_blendweights = Mem_ReallocType(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, blendweights_t, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3101 // set up the animscenes based on the anims
3104 for (index = 0, i = 0;index < numanims;index++)
3106 for (j = 0;j < anims[index].numframes;j++, i++)
3108 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3109 loadmodel->animscenes[i].firstframe = i;
3110 loadmodel->animscenes[i].framecount = 1;
3111 loadmodel->animscenes[i].loop = true;
3112 loadmodel->animscenes[i].framerate = anims[index].fps;
3115 // calculate the scaling value for bone origins so they can be compressed to short
3117 for (index = 0;index < numanimkeys;index++)
3119 pskanimkeys_t *k = animkeys + index;
3120 biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3121 biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3122 biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3124 loadmodel->num_posescale = biggestorigin / 32767.0f;
3125 if (loadmodel->num_posescale == 0) // don't divide by zero
3126 loadmodel->num_posescale = 1.0;
3127 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3129 // load the poses from the animkeys
3130 for (index = 0;index < numanimkeys;index++)
3132 pskanimkeys_t *k = animkeys + index;
3134 Vector4Copy(k->quat, quat);
3136 Vector4Negate(quat, quat);
3137 Vector4Normalize2(quat, quat);
3138 // compress poses to the short[7] format for longterm storage
3139 loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3140 loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3141 loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3142 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3143 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3144 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3145 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3150 dp_strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3151 loadmodel->animscenes[0].firstframe = 0;
3152 loadmodel->animscenes[0].framecount = 1;
3153 loadmodel->animscenes[0].loop = true;
3154 loadmodel->animscenes[0].framerate = 10;
3156 // calculate the scaling value for bone origins so they can be compressed to short
3158 for (index = 0;index < numbones;index++)
3160 pskboneinfo_t *p = bones + index;
3161 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3162 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3163 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3165 loadmodel->num_posescale = biggestorigin / 32767.0f;
3166 if (loadmodel->num_posescale == 0) // don't divide by zero
3167 loadmodel->num_posescale = 1.0;
3168 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3170 // load the basepose as a frame
3171 for (index = 0;index < numbones;index++)
3173 pskboneinfo_t *p = bones + index;
3175 Vector4Copy(p->basepose.quat, quat);
3177 Vector4Negate(quat, quat);
3178 Vector4Normalize2(quat, quat);
3179 // compress poses to the short[7] format for longterm storage
3180 loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3181 loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3182 loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3183 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3184 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3185 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3186 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3190 Mod_FreeSkinFiles(skinfiles);
3192 Mem_Free(animfilebuffer);
3193 Mod_MakeSortedSurfaces(loadmodel);
3195 // compute all the mesh information that was not loaded from the file
3196 // TODO: honor smoothing groups somehow?
3197 if (loadmodel->surfmesh.data_element3s)
3198 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3199 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3200 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3201 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);
3202 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);
3203 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3204 if(mod_alias_force_animated.string[0])
3205 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3207 // Always make a BIH for the first frame, we can use it where possible.
3208 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3209 if (!loadmodel->surfmesh.isanimated)
3211 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3212 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3213 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3214 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3215 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3219 void Mod_INTERQUAKEMODEL_Load(model_t *mod, void *buffer, void *bufferend)
3221 unsigned char *data;
3223 const unsigned char *pbase, *pend;
3225 skinfile_t *skinfiles;
3227 float biggestorigin;
3228 const unsigned int *inelements;
3230 float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3231 // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3232 const float *vnormal = NULL;
3233 const float *vposition = NULL;
3234 const float *vtangent = NULL;
3235 const float *vtexcoord = NULL;
3236 const float *vcolor4f = NULL;
3237 const unsigned char *vblendindexes = NULL;
3238 const unsigned char *vblendweights = NULL;
3239 const unsigned char *vcolor4ub = NULL;
3240 const unsigned short *framedata = NULL;
3241 // temporary memory allocations (because the data in the file may be misaligned)
3242 iqmanim_t *anims = NULL;
3243 iqmbounds_t *bounds = NULL;
3244 iqmjoint1_t *joint1 = NULL;
3245 iqmjoint_t *joint = NULL;
3246 iqmmesh_t *meshes = NULL;
3247 iqmpose1_t *pose1 = NULL;
3248 iqmpose_t *pose = NULL;
3249 iqmvertexarray_t *vas = NULL;
3251 pbase = (unsigned char *)buffer;
3252 pend = (unsigned char *)bufferend;
3254 if (pbase + sizeof(iqmheader_t) > pend)
3255 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3257 // copy struct (otherwise it may be misaligned)
3258 // LadyHavoc: okay it's definitely not misaligned here, but for consistency...
3259 memcpy(&header, pbase, sizeof(iqmheader_t));
3261 if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3262 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3263 if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3264 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3266 loadmodel->modeldatatypestring = "IQM";
3268 loadmodel->type = mod_alias;
3269 loadmodel->synctype = ST_RAND;
3272 header.version = LittleLong(header.version);
3273 header.filesize = LittleLong(header.filesize);
3274 header.flags = LittleLong(header.flags);
3275 header.num_text = LittleLong(header.num_text);
3276 header.ofs_text = LittleLong(header.ofs_text);
3277 header.num_meshes = LittleLong(header.num_meshes);
3278 header.ofs_meshes = LittleLong(header.ofs_meshes);
3279 header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3280 header.num_vertexes = LittleLong(header.num_vertexes);
3281 header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3282 header.num_triangles = LittleLong(header.num_triangles);
3283 header.ofs_triangles = LittleLong(header.ofs_triangles);
3284 header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3285 header.num_joints = LittleLong(header.num_joints);
3286 header.ofs_joints = LittleLong(header.ofs_joints);
3287 header.num_poses = LittleLong(header.num_poses);
3288 header.ofs_poses = LittleLong(header.ofs_poses);
3289 header.num_anims = LittleLong(header.num_anims);
3290 header.ofs_anims = LittleLong(header.ofs_anims);
3291 header.num_frames = LittleLong(header.num_frames);
3292 header.num_framechannels = LittleLong(header.num_framechannels);
3293 header.ofs_frames = LittleLong(header.ofs_frames);
3294 header.ofs_bounds = LittleLong(header.ofs_bounds);
3295 header.num_comment = LittleLong(header.num_comment);
3296 header.ofs_comment = LittleLong(header.ofs_comment);
3297 header.num_extensions = LittleLong(header.num_extensions);
3298 header.ofs_extensions = LittleLong(header.ofs_extensions);
3300 if (header.version == 1)
3302 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3303 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3305 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3311 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3312 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3314 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3318 if (pbase + header.ofs_text + header.num_text > pend ||
3319 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3320 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3321 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3322 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3323 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3324 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3325 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3326 pbase + header.ofs_comment + header.num_comment > pend)
3328 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3332 // Structs will be copied for alignment in memory, otherwise we crash on Sparc, PowerPC and others
3333 // and get big spam from UBSan, because these offsets may not be aligned.
3334 if (header.num_vertexarrays)
3335 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3336 if (header.num_anims)
3337 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3338 if (header.ofs_bounds)
3339 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3340 if (header.num_meshes)
3341 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3343 for (i = 0;i < (int)header.num_vertexarrays;i++)
3345 iqmvertexarray_t va;
3348 memcpy(&va, &vas[i], sizeof(iqmvertexarray_t));
3349 va.type = LittleLong(va.type);
3350 va.flags = LittleLong(va.flags);
3351 va.format = LittleLong(va.format);
3352 va.size = LittleLong(va.size);
3353 va.offset = LittleLong(va.offset);
3354 vsize = header.num_vertexes*va.size;
3357 case IQM_FLOAT: vsize *= sizeof(float); break;
3358 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3361 if (pbase + va.offset + vsize > pend)
3363 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3367 if (va.format == IQM_FLOAT && va.size == 3)
3368 vposition = (const float *)(pbase + va.offset);
3371 if (va.format == IQM_FLOAT && va.size == 2)
3372 vtexcoord = (const float *)(pbase + va.offset);
3375 if (va.format == IQM_FLOAT && va.size == 3)
3376 vnormal = (const float *)(pbase + va.offset);
3379 if (va.format == IQM_FLOAT && va.size == 4)
3380 vtangent = (const float *)(pbase + va.offset);
3382 case IQM_BLENDINDEXES:
3383 if (va.format == IQM_UBYTE && va.size == 4)
3384 vblendindexes = (const unsigned char *)(pbase + va.offset);
3386 case IQM_BLENDWEIGHTS:
3387 if (va.format == IQM_UBYTE && va.size == 4)
3388 vblendweights = (const unsigned char *)(pbase + va.offset);
3391 if (va.format == IQM_FLOAT && va.size == 4)
3392 vcolor4f = (const float *)(pbase + va.offset);
3393 if (va.format == IQM_UBYTE && va.size == 4)
3394 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3398 if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3400 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3404 text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3406 loadmodel->Draw = R_Mod_Draw;
3407 loadmodel->DrawDepth = R_Mod_DrawDepth;
3408 loadmodel->DrawDebug = R_Mod_DrawDebug;
3409 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
3410 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
3411 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
3412 loadmodel->DrawLight = R_Mod_DrawLight;
3413 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3414 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3415 loadmodel->PointSuperContents = NULL;
3416 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3418 // load external .skin files if present
3419 skinfiles = Mod_LoadSkinFiles();
3420 if (loadmodel->numskins < 1)
3421 loadmodel->numskins = 1;
3423 loadmodel->numframes = max(header.num_anims, 1);
3424 loadmodel->num_bones = header.num_joints;
3425 loadmodel->num_poses = max(header.num_frames, 1);
3426 loadmodel->submodelsurfaces_start = 0;
3427 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = header.num_meshes;
3428 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3429 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3430 loadmodel->surfmesh.num_vertices = header.num_vertexes;
3431 loadmodel->surfmesh.num_triangles = header.num_triangles;
3433 // do most allocations as one merged chunk
3434 // This is only robust for C standard types!
3435 data = (unsigned char *)Mem_Alloc(loadmodel->mempool,
3436 loadmodel->surfmesh.num_vertices * (sizeof(float[14]) + (vcolor4f || vcolor4ub ? sizeof(float[4]) : 0))
3437 + loadmodel->num_bones * sizeof(float[12])
3438 + loadmodel->num_surfaces * sizeof(int)
3439 + loadmodel->surfmesh.num_triangles * sizeof(int[3])
3440 + (loadmodel->surfmesh.num_vertices <= 65536 ? loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]) : 0)
3441 + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7])
3442 + (vblendindexes && vblendweights ? loadmodel->surfmesh.num_vertices * (sizeof(unsigned short) + sizeof(unsigned char[2][4])) : 0));
3443 // Pointers must be taken in descending order of alignment requirement!
3444 loadmodel->surfmesh.data_vertex3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3445 loadmodel->surfmesh.data_svector3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3446 loadmodel->surfmesh.data_tvector3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3447 loadmodel->surfmesh.data_normal3f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3448 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3449 if (vcolor4f || vcolor4ub)
3451 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data; data += loadmodel->surfmesh.num_vertices * sizeof(float[4]);
3453 loadmodel->data_baseboneposeinverse = (float *)data; data += loadmodel->num_bones * sizeof(float[12]);
3454 loadmodel->modelsurfaces_sorted = (int *)data; data += loadmodel->num_surfaces * sizeof(int);
3455 loadmodel->surfmesh.data_element3i = (int *)data; data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
3456 loadmodel->data_poses7s = (short *)data; data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3457 if (loadmodel->surfmesh.num_vertices <= 65536)
3459 loadmodel->surfmesh.data_element3s = (unsigned short *)data; data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
3461 if (vblendindexes && vblendweights)
3463 loadmodel->surfmesh.num_blends = 0;
3464 loadmodel->surfmesh.blends = (unsigned short *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned short);
3465 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3466 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data; data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3468 // Struct alignment requirements could change so we can't assume them here
3469 // otherwise a safe-looking commit could introduce undefined behaviour!
3470 loadmodel->data_surfaces = Mem_AllocType(loadmodel->mempool, msurface_t, loadmodel->num_surfaces * sizeof(msurface_t));
3471 loadmodel->data_textures = Mem_AllocType(loadmodel->mempool, texture_t, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
3472 loadmodel->skinscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numskins * sizeof(animscene_t));
3473 loadmodel->data_bones = Mem_AllocType(loadmodel->mempool, aliasbone_t, loadmodel->num_bones * sizeof(aliasbone_t));
3474 loadmodel->animscenes = Mem_AllocType(loadmodel->mempool, animscene_t, loadmodel->numframes * sizeof(animscene_t));
3475 if (vblendindexes && vblendweights)
3476 loadmodel->surfmesh.data_blendweights = Mem_AllocType(loadmodel->mempool, blendweights_t, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
3478 for (i = 0;i < loadmodel->numskins;i++)
3480 loadmodel->skinscenes[i].firstframe = i;
3481 loadmodel->skinscenes[i].framecount = 1;
3482 loadmodel->skinscenes[i].loop = true;
3483 loadmodel->skinscenes[i].framerate = 10;
3486 // load the bone info
3487 if (header.version == 1)
3489 iqmjoint1_t *injoints1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3491 if (loadmodel->num_bones)
3492 joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3493 for (i = 0;i < loadmodel->num_bones;i++)
3495 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3496 iqmjoint1_t injoint1;
3498 memcpy(&injoint1, &injoints1[i], sizeof(iqmjoint1_t));
3499 joint1[i].name = LittleLong(injoint1.name);
3500 joint1[i].parent = LittleLong(injoint1.parent);
3501 for (j = 0;j < 3;j++)
3503 joint1[i].origin[j] = LittleFloat(injoint1.origin[j]);
3504 joint1[i].rotation[j] = LittleFloat(injoint1.rotation[j]);
3505 joint1[i].scale[j] = LittleFloat(injoint1.scale[j]);
3507 dp_strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3508 loadmodel->data_bones[i].parent = joint1[i].parent;
3509 if (loadmodel->data_bones[i].parent >= i)
3510 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3511 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]);
3512 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3513 if (loadmodel->data_bones[i].parent >= 0)
3515 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3516 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3517 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3519 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3524 iqmjoint_t *injoints = (iqmjoint_t *)(pbase + header.ofs_joints);
3526 if (header.num_joints)
3527 joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3528 for (i = 0;i < loadmodel->num_bones;i++)
3530 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3533 memcpy(&injoint, &injoints[i], sizeof(iqmjoint_t));
3534 joint[i].name = LittleLong(injoint.name);
3535 joint[i].parent = LittleLong(injoint.parent);
3536 for (j = 0;j < 3;j++)
3538 joint[i].origin[j] = LittleFloat(injoint.origin[j]);
3539 joint[i].rotation[j] = LittleFloat(injoint.rotation[j]);
3540 joint[i].scale[j] = LittleFloat(injoint.scale[j]);
3542 joint[i].rotation[3] = LittleFloat(injoint.rotation[3]);
3543 dp_strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3544 loadmodel->data_bones[i].parent = joint[i].parent;
3545 if (loadmodel->data_bones[i].parent >= i)
3546 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3547 if (joint[i].rotation[3] > 0)
3548 Vector4Negate(joint[i].rotation, joint[i].rotation);
3549 Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3550 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]);
3551 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3552 if (loadmodel->data_bones[i].parent >= 0)
3554 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3555 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3556 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3558 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3562 // set up the animscenes based on the anims
3563 for (i = 0;i < (int)header.num_anims;i++)
3567 memcpy(&anim, &anims[i], sizeof(iqmanim_t));
3568 anim.name = LittleLong(anim.name);
3569 anim.first_frame = LittleLong(anim.first_frame);
3570 anim.num_frames = LittleLong(anim.num_frames);
3571 anim.framerate = LittleFloat(anim.framerate);
3572 anim.flags = LittleLong(anim.flags);
3573 dp_strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3574 loadmodel->animscenes[i].firstframe = anim.first_frame;
3575 loadmodel->animscenes[i].framecount = anim.num_frames;
3576 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3577 loadmodel->animscenes[i].framerate = anim.framerate;
3579 if (header.num_anims <= 0)
3581 dp_strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3582 loadmodel->animscenes[0].firstframe = 0;
3583 loadmodel->animscenes[0].framecount = 1;
3584 loadmodel->animscenes[0].loop = true;
3585 loadmodel->animscenes[0].framerate = 10;
3588 loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3589 if(mod_alias_force_animated.string[0])
3590 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3593 if (header.version == 1)
3595 iqmpose1_t *inposes1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3597 if (header.num_poses)
3598 pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3599 for (i = 0;i < (int)header.num_poses;i++)
3604 memcpy(&inpose, &inposes1[i], sizeof(iqmpose1_t));
3605 pose1[i].parent = LittleLong(inpose.parent);
3606 pose1[i].channelmask = LittleLong(inpose.channelmask);
3607 for (j = 0;j < 9;j++)
3609 pose1[i].channeloffset[j] = LittleFloat(inpose.channeloffset[j]);
3610 pose1[i].channelscale[j] = LittleFloat(inpose.channelscale[j]);
3612 f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3613 f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3614 f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3615 f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3616 f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3617 f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3619 if (header.num_frames <= 0)
3621 for (i = 0;i < loadmodel->num_bones;i++)
3624 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3625 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3626 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3632 iqmpose_t *inposes = (iqmpose_t *)(pbase + header.ofs_poses);
3634 if (header.num_poses)
3635 pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3636 for (i = 0;i < (int)header.num_poses;i++)
3641 memcpy(&inpose, &inposes[i], sizeof(iqmpose_t));
3642 pose[i].parent = LittleLong(inpose.parent);
3643 pose[i].channelmask = LittleLong(inpose.channelmask);
3644 for (j = 0;j < 10;j++)
3646 pose[i].channeloffset[j] = LittleFloat(inpose.channeloffset[j]);
3647 pose[i].channelscale[j] = LittleFloat(inpose.channelscale[j]);
3649 f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3650 f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3651 f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3652 f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3653 f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3654 f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3656 if (header.num_frames <= 0)
3658 for (i = 0;i < loadmodel->num_bones;i++)
3661 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3662 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3663 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3667 loadmodel->num_posescale = biggestorigin / 32767.0f;
3668 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3670 // load the pose data
3671 // this unaligned memory access is safe (LittleShort reads as bytes)
3672 framedata = (const unsigned short *)(pbase + header.ofs_frames);
3673 if (header.version == 1)
3675 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3677 for (j = 0;j < (int)header.num_poses;j++, k++)
3679 float qx, qy, qz, qw;
3680 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));
3681 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));
3682 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));
3683 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3684 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3685 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3686 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3687 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3688 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3689 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3690 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3691 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3692 // skip scale data for now
3693 if(pose1[j].channelmask&64) framedata++;
3694 if(pose1[j].channelmask&128) framedata++;
3695 if(pose1[j].channelmask&256) framedata++;
3698 if (header.num_frames <= 0)
3700 for (i = 0;i < loadmodel->num_bones;i++)
3702 float qx, qy, qz, qw;
3703 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3704 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3705 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3706 qx = joint1[i].rotation[0];
3707 qy = joint1[i].rotation[1];
3708 qz = joint1[i].rotation[2];
3709 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3710 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3711 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3712 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3713 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3714 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3720 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3722 for (j = 0;j < (int)header.num_poses;j++, k++)
3725 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));
3726 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));
3727 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));
3728 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3729 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3730 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3731 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3733 Vector4Negate(rot, rot);
3734 Vector4Normalize2(rot, rot);
3735 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3736 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3737 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3738 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3739 // skip scale data for now
3740 if(pose[j].channelmask&128) framedata++;
3741 if(pose[j].channelmask&256) framedata++;
3742 if(pose[j].channelmask&512) framedata++;
3745 if (header.num_frames <= 0)
3747 for (i = 0;i < loadmodel->num_bones;i++)
3749 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3750 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3751 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3752 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3753 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3754 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3755 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3760 // load bounding box data
3761 if (header.ofs_bounds)
3763 float xyradius = 0, radius = 0;
3764 VectorClear(loadmodel->normalmins);
3765 VectorClear(loadmodel->normalmaxs);
3766 for (i = 0; i < (int)header.num_frames;i++)
3769 bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3770 bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3771 bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3772 bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);
3773 bound.maxs[1] = LittleFloat(bounds[i].maxs[1]);
3774 bound.maxs[2] = LittleFloat(bounds[i].maxs[2]);
3775 bound.xyradius = LittleFloat(bounds[i].xyradius);
3776 bound.radius = LittleFloat(bounds[i].radius);
3779 VectorCopy(bound.mins, loadmodel->normalmins);
3780 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3784 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3785 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3786 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3787 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3788 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3789 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3791 if (bound.xyradius > xyradius)
3792 xyradius = bound.xyradius;
3793 if (bound.radius > radius)
3794 radius = bound.radius;
3796 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3797 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3798 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3799 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3800 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3801 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3802 loadmodel->radius = radius;
3803 loadmodel->radius2 = radius * radius;
3806 // load triangle data
3807 // this unaligned memory access is safe (LittleLong reads as bytes)
3808 inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3809 outelements = loadmodel->surfmesh.data_element3i;
3810 for (i = 0;i < (int)header.num_triangles;i++)
3812 outelements[0] = LittleLong(inelements[0]);
3813 outelements[1] = LittleLong(inelements[1]);
3814 outelements[2] = LittleLong(inelements[2]);
3818 if (loadmodel->surfmesh.data_element3s)
3819 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3820 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3821 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3824 // this unaligned memory access is safe (LittleFloat reads as bytes)
3825 outvertex = loadmodel->surfmesh.data_vertex3f;
3826 for (i = 0;i < (int)header.num_vertexes;i++)
3828 outvertex[0] = LittleFloat(vposition[0]);
3829 outvertex[1] = LittleFloat(vposition[1]);
3830 outvertex[2] = LittleFloat(vposition[2]);
3835 outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3836 // this unaligned memory access is safe (LittleFloat reads as bytes)
3837 for (i = 0;i < (int)header.num_vertexes;i++)
3839 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3840 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3845 // this unaligned memory access is safe (LittleFloat reads as bytes)
3848 outnormal = loadmodel->surfmesh.data_normal3f;
3849 for (i = 0;i < (int)header.num_vertexes;i++)
3851 outnormal[0] = LittleFloat(vnormal[0]);
3852 outnormal[1] = LittleFloat(vnormal[1]);
3853 outnormal[2] = LittleFloat(vnormal[2]);
3859 // this unaligned memory access is safe (LittleFloat reads as bytes)
3860 if(vnormal && vtangent)
3862 outnormal = loadmodel->surfmesh.data_normal3f;
3863 outsvector = loadmodel->surfmesh.data_svector3f;
3864 outtvector = loadmodel->surfmesh.data_tvector3f;
3865 for (i = 0;i < (int)header.num_vertexes;i++)
3867 outsvector[0] = LittleFloat(vtangent[0]);
3868 outsvector[1] = LittleFloat(vtangent[1]);
3869 outsvector[2] = LittleFloat(vtangent[2]);
3870 if(LittleFloat(vtangent[3]) < 0)
3871 CrossProduct(outsvector, outnormal, outtvector);
3873 CrossProduct(outnormal, outsvector, outtvector);
3881 // this unaligned memory access is safe (all bytes)
3882 if (vblendindexes && vblendweights)
3884 for (i = 0; i < (int)header.num_vertexes;i++)
3886 blendweights_t weights;
3887 memcpy(weights.index, vblendindexes + i*4, 4);
3888 memcpy(weights.influence, vblendweights + i*4, 4);
3889 loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3890 loadmodel->surfmesh.data_skeletalindex4ub[i*4 ] = weights.index[0];
3891 loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3892 loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3893 loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3894 loadmodel->surfmesh.data_skeletalweight4ub[i*4 ] = weights.influence[0];
3895 loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3896 loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3897 loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3903 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3904 // this unaligned memory access is safe (LittleFloat reads as bytes)
3905 for (i = 0;i < (int)header.num_vertexes;i++)
3907 outcolor[0] = LittleFloat(vcolor4f[0]);
3908 outcolor[1] = LittleFloat(vcolor4f[1]);
3909 outcolor[2] = LittleFloat(vcolor4f[2]);
3910 outcolor[3] = LittleFloat(vcolor4f[3]);
3917 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3918 // this unaligned memory access is safe (all bytes)
3919 for (i = 0;i < (int)header.num_vertexes;i++)
3921 outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3922 outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3923 outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3924 outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3931 for (i = 0;i < (int)header.num_meshes;i++)
3934 msurface_t *surface;
3936 memcpy(&mesh, &meshes[i], sizeof(iqmmesh_t));
3937 mesh.name = LittleLong(mesh.name);
3938 mesh.material = LittleLong(mesh.material);
3939 mesh.first_vertex = LittleLong(mesh.first_vertex);
3940 mesh.num_vertexes = LittleLong(mesh.num_vertexes);
3941 mesh.first_triangle = LittleLong(mesh.first_triangle);
3942 mesh.num_triangles = LittleLong(mesh.num_triangles);
3944 loadmodel->modelsurfaces_sorted[i] = i;
3945 surface = loadmodel->data_surfaces + i;
3946 surface->texture = loadmodel->data_textures + i;
3947 surface->num_firsttriangle = mesh.first_triangle;
3948 surface->num_triangles = mesh.num_triangles;
3949 surface->num_firstvertex = mesh.first_vertex;
3950 surface->num_vertices = mesh.num_vertexes;
3952 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
3955 Mod_FreeSkinFiles(skinfiles);
3956 Mod_MakeSortedSurfaces(loadmodel);
3958 // compute all the mesh information that was not loaded from the file
3960 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);
3961 if (!vnormal || !vtangent)
3962 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);
3963 if (!header.ofs_bounds)
3964 Mod_Alias_CalculateBoundingBox();
3966 // Always make a BIH for the first frame, we can use it where possible.
3967 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3968 if (!loadmodel->surfmesh.isanimated)
3970 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3971 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3972 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3973 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3974 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3977 if (joint) { Mem_Free(joint); joint = NULL; }
3978 if (joint1) { Mem_Free(joint1); joint1 = NULL; }
3979 if (pose) { Mem_Free(pose); pose = NULL; }
3980 if (pose1) { Mem_Free(pose1); pose1 = NULL; }