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 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->DrawSky = NULL;
1008 loadmodel->DrawAddWaterPlanes = NULL;
1009 loadmodel->Draw = R_Mod_Draw;
1010 loadmodel->DrawDepth = R_Mod_DrawDepth;
1011 loadmodel->DrawDebug = R_Mod_DrawDebug;
1012 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1013 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1014 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1015 loadmodel->DrawLight = R_Mod_DrawLight;
1016 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1017 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1018 // FIXME add TraceBrush!
1019 loadmodel->PointSuperContents = NULL;
1020 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1022 loadmodel->num_surfaces = 1;
1023 loadmodel->submodelsurfaces_start = 0;
1024 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1025 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
1026 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1027 loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1028 loadmodel->modelsurfaces_sorted[0] = 0;
1030 loadmodel->numskins = LittleLong(pinmodel->numskins);
1031 BOUNDI(loadmodel->numskins,0,65536);
1032 skinwidth = LittleLong (pinmodel->skinwidth);
1033 BOUNDI(skinwidth,0,65536);
1034 skinheight = LittleLong (pinmodel->skinheight);
1035 BOUNDI(skinheight,0,65536);
1036 numverts = LittleLong(pinmodel->numverts);
1037 BOUNDI(numverts,0,65536);
1038 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
1039 BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
1040 loadmodel->numframes = LittleLong(pinmodel->numframes);
1041 BOUNDI(loadmodel->numframes,0,65536);
1042 loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
1043 BOUNDI((int)loadmodel->synctype,0,2);
1044 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1045 i = LittleLong (pinmodel->flags);
1046 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1048 if (strstr(r_nolerp_list.string, loadmodel->name))
1049 loadmodel->nolerp = true;
1051 for (i = 0;i < 3;i++)
1053 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
1054 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
1057 startskins = datapointer;
1059 for (i = 0;i < loadmodel->numskins;i++)
1061 pinskintype = (daliasskintype_t *)datapointer;
1062 datapointer += sizeof(daliasskintype_t);
1063 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
1067 pinskingroup = (daliasskingroup_t *)datapointer;
1068 datapointer += sizeof(daliasskingroup_t);
1069 groupskins = LittleLong(pinskingroup->numskins);
1070 datapointer += sizeof(daliasskininterval_t) * groupskins;
1073 for (j = 0;j < groupskins;j++)
1075 datapointer += skinwidth * skinheight;
1080 pinstverts = (stvert_t *)datapointer;
1081 datapointer += sizeof(stvert_t) * numverts;
1083 pintriangles = (dtriangle_t *)datapointer;
1084 datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
1086 startframes = datapointer;
1087 loadmodel->surfmesh.num_morphframes = 0;
1088 for (i = 0;i < loadmodel->numframes;i++)
1090 pinframetype = (daliasframetype_t *)datapointer;
1091 datapointer += sizeof(daliasframetype_t);
1092 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1096 pinframegroup = (daliasgroup_t *)datapointer;
1097 datapointer += sizeof(daliasgroup_t);
1098 groupframes = LittleLong(pinframegroup->numframes);
1099 datapointer += sizeof(daliasinterval_t) * groupframes;
1102 for (j = 0;j < groupframes;j++)
1104 datapointer += sizeof(daliasframe_t);
1105 datapointer += sizeof(trivertx_t) * numverts;
1106 loadmodel->surfmesh.num_morphframes++;
1109 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1111 // store texture coordinates into temporary array, they will be stored
1112 // after usage is determined (triangle data)
1113 vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1114 vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1115 vertonseam = vertremap + numverts * 2;
1117 scales = 1.0 / skinwidth;
1118 scalet = 1.0 / skinheight;
1119 for (i = 0;i < numverts;i++)
1121 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1122 vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales;
1123 vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet;
1124 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1125 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1128 // load triangle data
1129 loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1131 // read the triangle elements
1132 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1133 for (j = 0;j < 3;j++)
1134 loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1135 // validate (note numverts is used because this is the original data)
1136 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, NULL, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1137 // now butcher the elements according to vertonseam and tri->facesfront
1138 // and then compact the vertex set to remove duplicates
1139 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1140 if (!LittleLong(pintriangles[i].facesfront)) // backface
1141 for (j = 0;j < 3;j++)
1142 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1143 loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1145 // (this uses vertremap to count usage to save some memory)
1146 for (i = 0;i < numverts*2;i++)
1148 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1149 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1150 // build remapping table and compact array
1151 loadmodel->surfmesh.num_vertices = 0;
1152 for (i = 0;i < numverts*2;i++)
1156 vertremap[i] = loadmodel->surfmesh.num_vertices;
1157 vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1158 vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1159 loadmodel->surfmesh.num_vertices++;
1162 vertremap[i] = -1; // not used at all
1164 // remap the elements to the new vertex set
1165 for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1166 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1167 // store the texture coordinates
1168 loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1169 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1171 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1172 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1175 // generate ushort elements array if possible
1176 if (loadmodel->surfmesh.num_vertices <= 65536)
1177 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1178 if (loadmodel->surfmesh.data_element3s)
1179 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1180 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1183 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1184 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1185 Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1186 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1187 Mod_Alias_MorphMesh_CompileFrames();
1190 Mem_Free(vertremap);
1193 skinfiles = Mod_LoadSkinFiles();
1196 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1197 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1198 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1199 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1200 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1201 Mod_FreeSkinFiles(skinfiles);
1202 for (i = 0;i < loadmodel->numskins;i++)
1204 loadmodel->skinscenes[i].firstframe = i;
1205 loadmodel->skinscenes[i].framecount = 1;
1206 loadmodel->skinscenes[i].loop = true;
1207 loadmodel->skinscenes[i].framerate = 10;
1212 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1213 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1214 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1215 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1217 datapointer = startskins;
1218 for (i = 0;i < loadmodel->numskins;i++)
1220 pinskintype = (daliasskintype_t *)datapointer;
1221 datapointer += sizeof(daliasskintype_t);
1223 if (pinskintype->type == ALIAS_SKIN_SINGLE)
1230 pinskingroup = (daliasskingroup_t *)datapointer;
1231 datapointer += sizeof(daliasskingroup_t);
1233 groupskins = LittleLong (pinskingroup->numskins);
1235 pinskinintervals = (daliasskininterval_t *)datapointer;
1236 datapointer += sizeof(daliasskininterval_t) * groupskins;
1238 interval = LittleFloat(pinskinintervals[0].interval);
1239 if (interval < 0.01f)
1241 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1246 dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1247 loadmodel->skinscenes[i].firstframe = totalskins;
1248 loadmodel->skinscenes[i].framecount = groupskins;
1249 loadmodel->skinscenes[i].framerate = 1.0f / interval;
1250 loadmodel->skinscenes[i].loop = true;
1252 for (j = 0;j < groupskins;j++)
1255 dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1257 dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1258 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))
1259 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));
1260 datapointer += skinwidth * skinheight;
1264 // check for skins that don't exist in the model, but do exist as external images
1265 // (this was added because yummyluv kept pestering me about support for it)
1266 // TODO: support shaders here?
1269 dpsnprintf(name, sizeof(name), "%s_%i", loadmodel->name, loadmodel->numskins);
1270 tempskinframe = R_SkinFrame_LoadExternal(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false, false);
1273 // expand the arrays to make room
1274 tempskinscenes = loadmodel->skinscenes;
1275 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1276 memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1277 Mem_Free(tempskinscenes);
1279 tempaliasskins = loadmodel->data_textures;
1280 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1281 memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1282 Mem_Free(tempaliasskins);
1284 // store the info about the new skin
1285 Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, tempskinframe);
1286 strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1287 loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1288 loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1289 loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1290 loadmodel->skinscenes[loadmodel->numskins].loop = true;
1292 //increase skin counts
1293 loadmodel->num_textures++;
1294 loadmodel->numskins++;
1297 // fix up the pointers since they are pointing at the old textures array
1298 // FIXME: this is a hack!
1299 for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1300 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1304 surface = loadmodel->data_surfaces;
1305 surface->texture = loadmodel->data_textures;
1306 surface->num_firsttriangle = 0;
1307 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1308 surface->num_firstvertex = 0;
1309 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1311 if(mod_alias_force_animated.string[0])
1312 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1314 // Always make a BIH for the first frame, we can use it where possible.
1315 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1316 if (!loadmodel->surfmesh.isanimated)
1318 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1319 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1320 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1321 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1322 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1325 // because shaders can do somewhat unexpected things, check for unusual features now
1326 for (i = 0;i < loadmodel->num_textures;i++)
1328 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1329 mod->DrawSky = R_Mod_DrawSky;
1330 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1331 mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
1335 void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend)
1337 int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1338 float iskinwidth, iskinheight;
1339 unsigned char *data;
1340 msurface_t *surface;
1342 unsigned char *base, *datapointer;
1343 md2frame_t *pinframe;
1345 md2triangle_t *intri;
1346 unsigned short *inst;
1347 struct md2verthash_s
1349 struct md2verthash_s *next;
1353 *hash, **md2verthash, *md2verthashdata;
1354 skinfile_t *skinfiles;
1356 pinmodel = (md2_t *)buffer;
1357 base = (unsigned char *)buffer;
1359 version = LittleLong (pinmodel->version);
1360 if (version != MD2ALIAS_VERSION)
1361 Host_Error ("%s has wrong version number (%i should be %i)",
1362 loadmodel->name, version, MD2ALIAS_VERSION);
1364 loadmodel->modeldatatypestring = "MD2";
1366 loadmodel->type = mod_alias;
1367 loadmodel->DrawSky = NULL;
1368 loadmodel->DrawAddWaterPlanes = NULL;
1369 loadmodel->Draw = R_Mod_Draw;
1370 loadmodel->DrawDepth = R_Mod_DrawDepth;
1371 loadmodel->DrawDebug = R_Mod_DrawDebug;
1372 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1373 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1374 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1375 loadmodel->DrawLight = R_Mod_DrawLight;
1376 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1377 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1378 loadmodel->PointSuperContents = NULL;
1379 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1381 if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1382 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1383 if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1384 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1385 if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1386 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1387 if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1388 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1390 end = LittleLong(pinmodel->ofs_end);
1391 if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1392 Host_Error ("%s is not a valid model", loadmodel->name);
1393 if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1394 Host_Error ("%s is not a valid model", loadmodel->name);
1395 if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1396 Host_Error ("%s is not a valid model", loadmodel->name);
1397 if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1398 Host_Error ("%s is not a valid model", loadmodel->name);
1399 if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1400 Host_Error ("%s is not a valid model", loadmodel->name);
1402 loadmodel->numskins = LittleLong(pinmodel->num_skins);
1403 numxyz = LittleLong(pinmodel->num_xyz);
1404 numst = LittleLong(pinmodel->num_st);
1405 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1406 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1407 loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1408 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1409 skinwidth = LittleLong(pinmodel->skinwidth);
1410 skinheight = LittleLong(pinmodel->skinheight);
1411 iskinwidth = 1.0f / skinwidth;
1412 iskinheight = 1.0f / skinheight;
1414 loadmodel->num_surfaces = 1;
1415 loadmodel->submodelsurfaces_start = 0;
1416 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1417 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]));
1418 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1419 loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1420 loadmodel->modelsurfaces_sorted[0] = 0;
1421 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1422 loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1423 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1425 loadmodel->synctype = ST_RAND;
1428 inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1429 skinfiles = Mod_LoadSkinFiles();
1432 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1433 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1434 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1435 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1436 Mod_FreeSkinFiles(skinfiles);
1438 else if (loadmodel->numskins)
1440 // skins found (most likely not a player model)
1441 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1442 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1443 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1444 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1445 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);
1449 // no skins (most likely a player model)
1450 loadmodel->numskins = 1;
1451 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1452 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1453 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1454 Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures, loadmodel->name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing());
1457 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1458 for (i = 0;i < loadmodel->numskins;i++)
1460 loadmodel->skinscenes[i].firstframe = i;
1461 loadmodel->skinscenes[i].framecount = 1;
1462 loadmodel->skinscenes[i].loop = true;
1463 loadmodel->skinscenes[i].framerate = 10;
1466 // load the triangles and stvert data
1467 inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1468 intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1469 md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1470 md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1471 // swap the triangle list
1472 loadmodel->surfmesh.num_vertices = 0;
1473 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1475 for (j = 0;j < 3;j++)
1477 xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1478 st = (unsigned short) LittleShort (intri[i].index_st[j]);
1481 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1486 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1489 hashindex = (xyz * 256 + st) & 65535;
1490 for (hash = md2verthash[hashindex];hash;hash = hash->next)
1491 if (hash->xyz == xyz && hash->st == st)
1495 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1498 hash->next = md2verthash[hashindex];
1499 md2verthash[hashindex] = hash;
1501 loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1505 vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1506 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));
1507 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1508 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1509 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1512 hash = md2verthashdata + i;
1513 vertremap[i] = hash->xyz;
1514 sts = LittleShort(inst[hash->st*2+0]);
1515 stt = LittleShort(inst[hash->st*2+1]);
1516 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1518 Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1522 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1523 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1526 Mem_Free(md2verthash);
1527 Mem_Free(md2verthashdata);
1529 // generate ushort elements array if possible
1530 if (loadmodel->surfmesh.num_vertices <= 65536)
1531 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1532 if (loadmodel->surfmesh.data_element3s)
1533 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1534 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1537 datapointer = (base + LittleLong(pinmodel->ofs_frames));
1538 for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1543 pinframe = (md2frame_t *)datapointer;
1544 datapointer += sizeof(md2frame_t);
1545 // store the frame scale/translate into the appropriate array
1546 for (j = 0;j < 3;j++)
1548 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1549 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1551 // convert the vertices
1552 v = (trivertx_t *)datapointer;
1553 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1554 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1555 out[k] = v[vertremap[k]];
1556 datapointer += numxyz * sizeof(trivertx_t);
1558 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1559 loadmodel->animscenes[i].firstframe = i;
1560 loadmodel->animscenes[i].framecount = 1;
1561 loadmodel->animscenes[i].framerate = 10;
1562 loadmodel->animscenes[i].loop = true;
1565 Mem_Free(vertremap);
1567 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1568 Mod_Alias_MorphMesh_CompileFrames();
1569 if(mod_alias_force_animated.string[0])
1570 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1572 surface = loadmodel->data_surfaces;
1573 surface->texture = loadmodel->data_textures;
1574 surface->num_firsttriangle = 0;
1575 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1576 surface->num_firstvertex = 0;
1577 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1579 // Always make a BIH for the first frame, we can use it where possible.
1580 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1581 if (!loadmodel->surfmesh.isanimated)
1583 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1584 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1585 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1586 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1587 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1590 // because shaders can do somewhat unexpected things, check for unusual features now
1591 for (i = 0;i < loadmodel->num_textures;i++)
1593 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1594 mod->DrawSky = R_Mod_DrawSky;
1595 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1596 mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
1600 void Mod_IDP3_Load(model_t *mod, void *buffer, void *bufferend)
1602 int i, j, k, version, meshvertices, meshtriangles;
1603 unsigned char *data;
1604 msurface_t *surface;
1605 md3modelheader_t *pinmodel;
1606 md3frameinfo_t *pinframe;
1609 skinfile_t *skinfiles;
1611 pinmodel = (md3modelheader_t *)buffer;
1613 if (memcmp(pinmodel->identifier, "IDP3", 4))
1614 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1615 version = LittleLong (pinmodel->version);
1616 if (version != MD3VERSION)
1617 Host_Error ("%s has wrong version number (%i should be %i)",
1618 loadmodel->name, version, MD3VERSION);
1620 skinfiles = Mod_LoadSkinFiles();
1621 if (loadmodel->numskins < 1)
1622 loadmodel->numskins = 1;
1624 loadmodel->modeldatatypestring = "MD3";
1626 loadmodel->type = mod_alias;
1627 loadmodel->DrawSky = NULL;
1628 loadmodel->DrawAddWaterPlanes = NULL;
1629 loadmodel->Draw = R_Mod_Draw;
1630 loadmodel->DrawDepth = R_Mod_DrawDepth;
1631 loadmodel->DrawDebug = R_Mod_DrawDebug;
1632 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1633 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1634 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1635 loadmodel->DrawLight = R_Mod_DrawLight;
1636 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1637 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1638 loadmodel->PointSuperContents = NULL;
1639 loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1640 loadmodel->synctype = ST_RAND;
1641 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1642 i = LittleLong (pinmodel->flags);
1643 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1645 // set up some global info about the model
1646 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1647 loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1649 // make skinscenes for the skins (no groups)
1650 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1651 for (i = 0;i < loadmodel->numskins;i++)
1653 loadmodel->skinscenes[i].firstframe = i;
1654 loadmodel->skinscenes[i].framecount = 1;
1655 loadmodel->skinscenes[i].loop = true;
1656 loadmodel->skinscenes[i].framerate = 10;
1660 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1661 for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1663 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1664 loadmodel->animscenes[i].firstframe = i;
1665 loadmodel->animscenes[i].framecount = 1;
1666 loadmodel->animscenes[i].framerate = 10;
1667 loadmodel->animscenes[i].loop = true;
1671 loadmodel->num_tagframes = loadmodel->numframes;
1672 loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1673 loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1674 for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1676 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1677 for (j = 0;j < 9;j++)
1678 loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1679 for (j = 0;j < 3;j++)
1680 loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1681 //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);
1687 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)))
1689 if (memcmp(pinmesh->identifier, "IDP3", 4))
1690 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1691 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1692 Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1693 meshvertices += LittleLong(pinmesh->num_vertices);
1694 meshtriangles += LittleLong(pinmesh->num_triangles);
1697 loadmodel->submodelsurfaces_start = 0;
1698 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1699 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1700 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1701 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * sizeof(float[2]) + meshvertices * loadmodel->numframes * sizeof(md3vertex_t));
1702 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1703 loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1704 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1705 loadmodel->surfmesh.num_vertices = meshvertices;
1706 loadmodel->surfmesh.num_triangles = meshtriangles;
1707 loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1708 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1709 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1710 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1711 loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1712 if (meshvertices <= 65536)
1714 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1719 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)))
1721 if (memcmp(pinmesh->identifier, "IDP3", 4))
1722 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1723 loadmodel->modelsurfaces_sorted[i] = i;
1724 surface = loadmodel->data_surfaces + i;
1725 surface->texture = loadmodel->data_textures + i;
1726 surface->num_firsttriangle = meshtriangles;
1727 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1728 surface->num_firstvertex = meshvertices;
1729 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1730 meshvertices += surface->num_vertices;
1731 meshtriangles += surface->num_triangles;
1733 for (j = 0;j < surface->num_triangles * 3;j++)
1735 int e = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1736 loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = e;
1737 if (loadmodel->surfmesh.data_element3s)
1738 loadmodel->surfmesh.data_element3s[j + surface->num_firsttriangle * 3] = e;
1740 for (j = 0;j < surface->num_vertices;j++)
1742 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1743 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1745 for (j = 0;j < loadmodel->numframes;j++)
1747 const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1748 md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1749 for (k = 0;k < surface->num_vertices;k++, in++, out++)
1751 out->origin[0] = LittleShort(in->origin[0]);
1752 out->origin[1] = LittleShort(in->origin[1]);
1753 out->origin[2] = LittleShort(in->origin[2]);
1754 out->pitch = in->pitch;
1759 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1761 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__);
1763 Mod_Alias_MorphMesh_CompileFrames();
1764 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1765 Mod_FreeSkinFiles(skinfiles);
1766 Mod_MakeSortedSurfaces(loadmodel);
1767 if(mod_alias_force_animated.string[0])
1768 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1770 // Always make a BIH for the first frame, we can use it where possible.
1771 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1772 if (!loadmodel->surfmesh.isanimated)
1774 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1775 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1776 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1777 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1778 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1781 // because shaders can do somewhat unexpected things, check for unusual features now
1782 for (i = 0;i < loadmodel->num_textures;i++)
1784 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1785 mod->DrawSky = R_Mod_DrawSky;
1786 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1787 mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
1791 void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend)
1793 zymtype1header_t *pinmodel, *pheader;
1794 unsigned char *pbase;
1795 int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1796 float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1797 zymvertex_t *verts, *vertdata;
1801 skinfile_t *skinfiles;
1802 unsigned char *data;
1803 msurface_t *surface;
1805 pinmodel = (zymtype1header_t *)buffer;
1806 pbase = (unsigned char *)buffer;
1807 if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1808 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1809 if (BigLong(pinmodel->type) != 1)
1810 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1812 loadmodel->modeldatatypestring = "ZYM";
1814 loadmodel->type = mod_alias;
1815 loadmodel->synctype = ST_RAND;
1819 pheader->type = BigLong(pinmodel->type);
1820 pheader->filesize = BigLong(pinmodel->filesize);
1821 pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1822 pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1823 pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1824 pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1825 pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1826 pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1827 pheader->radius = BigFloat(pinmodel->radius);
1828 pheader->numverts = BigLong(pinmodel->numverts);
1829 pheader->numtris = BigLong(pinmodel->numtris);
1830 pheader->numshaders = BigLong(pinmodel->numshaders);
1831 pheader->numbones = BigLong(pinmodel->numbones);
1832 pheader->numscenes = BigLong(pinmodel->numscenes);
1833 pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1834 pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1835 pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1836 pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1837 pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1838 pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1839 pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1840 pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1841 pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1842 pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1843 pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1844 pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1845 pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1846 pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1847 pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1848 pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1849 pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1850 pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1852 if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1854 Con_Printf("%s has no geometry\n", loadmodel->name);
1857 if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1859 Con_Printf("%s has no animations\n", loadmodel->name);
1863 loadmodel->DrawSky = NULL;
1864 loadmodel->DrawAddWaterPlanes = NULL;
1865 loadmodel->Draw = R_Mod_Draw;
1866 loadmodel->DrawDepth = R_Mod_DrawDepth;
1867 loadmodel->DrawDebug = R_Mod_DrawDebug;
1868 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1869 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1870 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1871 loadmodel->DrawLight = R_Mod_DrawLight;
1872 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1873 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1874 loadmodel->PointSuperContents = NULL;
1875 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1877 loadmodel->numframes = pheader->numscenes;
1878 loadmodel->num_surfaces = pheader->numshaders;
1880 skinfiles = Mod_LoadSkinFiles();
1881 if (loadmodel->numskins < 1)
1882 loadmodel->numskins = 1;
1884 // make skinscenes for the skins (no groups)
1885 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1886 for (i = 0;i < loadmodel->numskins;i++)
1888 loadmodel->skinscenes[i].firstframe = i;
1889 loadmodel->skinscenes[i].framecount = 1;
1890 loadmodel->skinscenes[i].loop = true;
1891 loadmodel->skinscenes[i].framerate = 10;
1895 // LadyHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
1896 modelradius = pheader->radius;
1897 for (i = 0;i < 3;i++)
1899 loadmodel->normalmins[i] = pheader->mins[i];
1900 loadmodel->normalmaxs[i] = pheader->maxs[i];
1901 loadmodel->rotatedmins[i] = -modelradius;
1902 loadmodel->rotatedmaxs[i] = modelradius;
1904 corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1905 corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1906 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1907 if (loadmodel->yawmaxs[0] > modelradius)
1908 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1909 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1910 loadmodel->yawmins[2] = loadmodel->normalmins[2];
1911 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1912 loadmodel->radius = modelradius;
1913 loadmodel->radius2 = modelradius * modelradius;
1915 // go through the lumps, swapping things
1917 //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1918 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1919 scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1920 numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1921 for (i = 0;i < pheader->numscenes;i++)
1923 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1924 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1925 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1926 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1927 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1928 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1929 Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1930 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1931 Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1932 if (loadmodel->animscenes[i].framerate < 0)
1933 Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1937 //zymlump_t lump_bones; // zymbone_t bone[numbones];
1938 loadmodel->num_bones = pheader->numbones;
1939 loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1940 bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1941 for (i = 0;i < pheader->numbones;i++)
1943 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1944 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1945 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1946 if (loadmodel->data_bones[i].parent >= i)
1947 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1950 //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1951 vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1952 bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1953 for (i = 0;i < pheader->numverts;i++)
1955 vertbonecounts[i] = BigLong(bonecount[i]);
1956 if (vertbonecounts[i] != 1)
1957 Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1960 loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1962 meshvertices = pheader->numverts;
1963 meshtriangles = pheader->numtris;
1965 loadmodel->submodelsurfaces_start = 0;
1966 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1967 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1968 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1969 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * (sizeof(float[14]) + sizeof(unsigned short) + sizeof(unsigned char[2][4])) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]));
1970 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1971 loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1972 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1973 loadmodel->surfmesh.num_vertices = meshvertices;
1974 loadmodel->surfmesh.num_triangles = meshtriangles;
1975 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1976 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1977 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1978 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1979 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1980 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1981 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
1982 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
1983 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1984 loadmodel->surfmesh.num_blends = 0;
1985 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
1986 if (loadmodel->surfmesh.num_vertices <= 65536)
1988 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
1990 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
1991 loadmodel->surfmesh.data_blendweights = NULL;
1993 //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1994 poses = (float *) (pheader->lump_poses.start + pbase);
1995 // figure out scale of model from root bone, for compatibility with old zmodel versions
1996 tempvec[0] = BigFloat(poses[0]);
1997 tempvec[1] = BigFloat(poses[1]);
1998 tempvec[2] = BigFloat(poses[2]);
1999 modelscale = VectorLength(tempvec);
2001 for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
2003 f = fabs(BigFloat(poses[i]));
2004 biggestorigin = max(biggestorigin, f);
2006 loadmodel->num_posescale = biggestorigin / 32767.0f;
2007 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2008 for (i = 0;i < numposes;i++)
2010 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
2011 for (j = 0;j < loadmodel->num_bones;j++)
2014 matrix4x4_t posematrix;
2015 for (k = 0;k < 12;k++)
2016 pose[k] = BigFloat(frameposes[j*12+k]);
2017 //if (j < loadmodel->num_bones)
2018 // 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));
2019 // scale child bones to match the root scale
2020 if (loadmodel->data_bones[j].parent >= 0)
2022 pose[3] *= modelscale;
2023 pose[7] *= modelscale;
2024 pose[11] *= modelscale;
2026 // normalize rotation matrix
2027 VectorNormalize(pose + 0);
2028 VectorNormalize(pose + 4);
2029 VectorNormalize(pose + 8);
2030 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2031 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2035 //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2036 verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2037 vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2038 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2039 // (converting from weight-blending skeletal animation to
2040 // deformation-based skeletal animation)
2041 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2042 for (i = 0;i < loadmodel->num_bones;i++)
2045 for (k = 0;k < 12;k++)
2046 m[k] = BigFloat(poses[i*12+k]);
2047 if (loadmodel->data_bones[i].parent >= 0)
2048 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2050 for (k = 0;k < 12;k++)
2051 bonepose[12*i+k] = m[k];
2053 for (j = 0;j < pheader->numverts;j++)
2055 // this format really should have had a per vertexweight weight value...
2056 // but since it does not, the weighting is completely ignored and
2057 // only one weight is allowed per vertex
2058 int boneindex = BigLong(vertdata[j].bonenum);
2059 const float *m = bonepose + 12 * boneindex;
2060 float relativeorigin[3];
2061 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2062 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2063 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2064 // transform the vertex bone weight into the base mesh
2065 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2066 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2067 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2068 // store the weight as the primary weight on this vertex
2069 loadmodel->surfmesh.blends[j] = boneindex;
2070 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = boneindex;
2071 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2072 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2073 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2074 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = 255;
2075 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2076 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2077 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2080 // normals and tangents are calculated after elements are loaded
2082 //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2083 outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2084 intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2085 for (i = 0;i < pheader->numverts;i++)
2087 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2088 // flip T coordinate for OpenGL
2089 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2092 //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2093 //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2094 //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2096 //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2097 //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)
2098 // byteswap, validate, and swap winding order of tris
2099 count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2100 if (pheader->lump_render.length != count)
2101 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2102 renderlist = (int *) (pheader->lump_render.start + pbase);
2103 renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2105 for (i = 0;i < loadmodel->num_surfaces;i++)
2107 int firstvertex, lastvertex;
2108 if (renderlist >= renderlistend)
2109 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2110 count = BigLong(*renderlist);renderlist++;
2111 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2112 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2114 loadmodel->modelsurfaces_sorted[i] = i;
2115 surface = loadmodel->data_surfaces + i;
2116 surface->texture = loadmodel->data_textures + i;
2117 surface->num_firsttriangle = meshtriangles;
2118 surface->num_triangles = count;
2119 meshtriangles += surface->num_triangles;
2121 // load the elements
2122 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2123 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2125 outelements[j*3+2] = BigLong(renderlist[0]);
2126 outelements[j*3+1] = BigLong(renderlist[1]);
2127 outelements[j*3+0] = BigLong(renderlist[2]);
2129 // validate the elements and find the used vertex range
2130 firstvertex = meshvertices;
2132 for (j = 0;j < surface->num_triangles * 3;j++)
2134 if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2135 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2136 firstvertex = min(firstvertex, outelements[j]);
2137 lastvertex = max(lastvertex, outelements[j]);
2139 surface->num_firstvertex = firstvertex;
2140 surface->num_vertices = lastvertex + 1 - firstvertex;
2142 // since zym models do not have named sections, reuse their shader
2143 // name as the section name
2144 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2145 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2147 Mod_FreeSkinFiles(skinfiles);
2148 Mem_Free(vertbonecounts);
2150 Mod_MakeSortedSurfaces(loadmodel);
2152 // compute all the mesh information that was not loaded from the file
2153 if (loadmodel->surfmesh.data_element3s)
2154 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2155 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2156 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2157 Mod_BuildBaseBonePoses();
2158 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);
2159 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);
2160 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2161 if(mod_alias_force_animated.string[0])
2162 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2164 // Always make a BIH for the first frame, we can use it where possible.
2165 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2166 if (!loadmodel->surfmesh.isanimated)
2168 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2169 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2170 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2171 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2172 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2175 // because shaders can do somewhat unexpected things, check for unusual features now
2176 for (i = 0;i < loadmodel->num_textures;i++)
2178 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2179 mod->DrawSky = R_Mod_DrawSky;
2180 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2181 mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
2185 void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend)
2187 dpmheader_t *pheader;
2191 unsigned char *pbase;
2192 int i, j, k, meshvertices, meshtriangles;
2193 skinfile_t *skinfiles;
2194 unsigned char *data;
2196 float biggestorigin, tempvec[3], modelscale;
2200 pheader = (dpmheader_t *)buffer;
2201 pbase = (unsigned char *)buffer;
2202 if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2203 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2204 if (BigLong(pheader->type) != 2)
2205 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2207 loadmodel->modeldatatypestring = "DPM";
2209 loadmodel->type = mod_alias;
2210 loadmodel->synctype = ST_RAND;
2213 pheader->type = BigLong(pheader->type);
2214 pheader->filesize = BigLong(pheader->filesize);
2215 pheader->mins[0] = BigFloat(pheader->mins[0]);
2216 pheader->mins[1] = BigFloat(pheader->mins[1]);
2217 pheader->mins[2] = BigFloat(pheader->mins[2]);
2218 pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2219 pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2220 pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2221 pheader->yawradius = BigFloat(pheader->yawradius);
2222 pheader->allradius = BigFloat(pheader->allradius);
2223 pheader->num_bones = BigLong(pheader->num_bones);
2224 pheader->num_meshs = BigLong(pheader->num_meshs);
2225 pheader->num_frames = BigLong(pheader->num_frames);
2226 pheader->ofs_bones = BigLong(pheader->ofs_bones);
2227 pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2228 pheader->ofs_frames = BigLong(pheader->ofs_frames);
2230 if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2232 Con_Printf("%s has no geometry\n", loadmodel->name);
2235 if (pheader->num_frames < 1)
2237 Con_Printf("%s has no frames\n", loadmodel->name);
2241 loadmodel->DrawSky = NULL;
2242 loadmodel->DrawAddWaterPlanes = NULL;
2243 loadmodel->Draw = R_Mod_Draw;
2244 loadmodel->DrawDepth = R_Mod_DrawDepth;
2245 loadmodel->DrawDebug = R_Mod_DrawDebug;
2246 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
2247 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
2248 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
2249 loadmodel->DrawLight = R_Mod_DrawLight;
2250 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2251 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2252 loadmodel->PointSuperContents = NULL;
2253 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2256 // LadyHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2257 for (i = 0;i < 3;i++)
2259 loadmodel->normalmins[i] = pheader->mins[i];
2260 loadmodel->normalmaxs[i] = pheader->maxs[i];
2261 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2262 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2263 loadmodel->rotatedmins[i] = -pheader->allradius;
2264 loadmodel->rotatedmaxs[i] = pheader->allradius;
2266 loadmodel->radius = pheader->allradius;
2267 loadmodel->radius2 = pheader->allradius * pheader->allradius;
2269 // load external .skin files if present
2270 skinfiles = Mod_LoadSkinFiles();
2271 if (loadmodel->numskins < 1)
2272 loadmodel->numskins = 1;
2277 // gather combined statistics from the meshes
2278 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2279 for (i = 0;i < (int)pheader->num_meshs;i++)
2281 int numverts = BigLong(dpmmesh->num_verts);
2282 meshvertices += numverts;
2283 meshtriangles += BigLong(dpmmesh->num_tris);
2287 loadmodel->numframes = pheader->num_frames;
2288 loadmodel->num_bones = pheader->num_bones;
2289 loadmodel->num_poses = loadmodel->numframes;
2290 loadmodel->submodelsurfaces_start = 0;
2291 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = pheader->num_meshs;
2292 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2293 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2294 // do most allocations as one merged chunk
2295 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * (sizeof(float[14]) + sizeof(unsigned short) + sizeof(unsigned char[2][4])) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t));
2296 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2297 loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2298 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2299 loadmodel->surfmesh.num_vertices = meshvertices;
2300 loadmodel->surfmesh.num_triangles = meshtriangles;
2301 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2302 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2303 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2304 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2305 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2306 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2307 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2308 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2309 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2310 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2311 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2312 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2313 loadmodel->surfmesh.num_blends = 0;
2314 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2315 if (meshvertices <= 65536)
2317 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2319 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2320 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2322 for (i = 0;i < loadmodel->numskins;i++)
2324 loadmodel->skinscenes[i].firstframe = i;
2325 loadmodel->skinscenes[i].framecount = 1;
2326 loadmodel->skinscenes[i].loop = true;
2327 loadmodel->skinscenes[i].framerate = 10;
2330 // load the bone info
2331 bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2332 for (i = 0;i < loadmodel->num_bones;i++)
2334 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2335 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2336 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2337 if (loadmodel->data_bones[i].parent >= i)
2338 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2342 frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2343 // figure out scale of model from root bone, for compatibility with old dpmodel versions
2344 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2345 tempvec[0] = BigFloat(poses[0]);
2346 tempvec[1] = BigFloat(poses[1]);
2347 tempvec[2] = BigFloat(poses[2]);
2348 modelscale = VectorLength(tempvec);
2350 for (i = 0;i < loadmodel->numframes;i++)
2352 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2353 loadmodel->animscenes[i].firstframe = i;
2354 loadmodel->animscenes[i].framecount = 1;
2355 loadmodel->animscenes[i].loop = true;
2356 loadmodel->animscenes[i].framerate = 10;
2357 // load the bone poses for this frame
2358 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2359 for (j = 0;j < loadmodel->num_bones*12;j++)
2361 f = fabs(BigFloat(poses[j]));
2362 biggestorigin = max(biggestorigin, f);
2364 // stuff not processed here: mins, maxs, yawradius, allradius
2366 loadmodel->num_posescale = biggestorigin / 32767.0f;
2367 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2368 for (i = 0;i < loadmodel->numframes;i++)
2370 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2371 for (j = 0;j < loadmodel->num_bones;j++)
2374 matrix4x4_t posematrix;
2375 for (k = 0;k < 12;k++)
2376 pose[k] = BigFloat(frameposes[j*12+k]);
2377 // scale child bones to match the root scale
2378 if (loadmodel->data_bones[j].parent >= 0)
2380 pose[3] *= modelscale;
2381 pose[7] *= modelscale;
2382 pose[11] *= modelscale;
2384 // normalize rotation matrix
2385 VectorNormalize(pose + 0);
2386 VectorNormalize(pose + 4);
2387 VectorNormalize(pose + 8);
2388 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2389 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2393 // load the meshes now
2394 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2397 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2398 // (converting from weight-blending skeletal animation to
2399 // deformation-based skeletal animation)
2400 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2401 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2402 for (i = 0;i < loadmodel->num_bones;i++)
2405 for (k = 0;k < 12;k++)
2406 m[k] = BigFloat(poses[i*12+k]);
2407 if (loadmodel->data_bones[i].parent >= 0)
2408 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2410 for (k = 0;k < 12;k++)
2411 bonepose[12*i+k] = m[k];
2413 for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2415 const int *inelements;
2417 unsigned short *outelement3s;
2418 const float *intexcoord;
2419 msurface_t *surface;
2421 loadmodel->modelsurfaces_sorted[i] = i;
2422 surface = loadmodel->data_surfaces + i;
2423 surface->texture = loadmodel->data_textures + i;
2424 surface->num_firsttriangle = meshtriangles;
2425 surface->num_triangles = BigLong(dpmmesh->num_tris);
2426 surface->num_firstvertex = meshvertices;
2427 surface->num_vertices = BigLong(dpmmesh->num_verts);
2428 meshvertices += surface->num_vertices;
2429 meshtriangles += surface->num_triangles;
2431 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2432 outelement3i = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2433 outelement3s = loadmodel->surfmesh.data_element3s ? loadmodel->surfmesh.data_element3s + surface->num_firsttriangle * 3 : NULL;
2434 for (j = 0;j < surface->num_triangles;j++)
2436 // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2437 outelement3i[j * 3 + 0] = surface->num_firstvertex + BigLong(inelements[j * 3 + 2]);
2438 outelement3i[j * 3 + 1] = surface->num_firstvertex + BigLong(inelements[j * 3 + 1]);
2439 outelement3i[j * 3 + 2] = surface->num_firstvertex + BigLong(inelements[j * 3 + 0]);
2442 outelement3s[j * 3 + 0] = outelement3i[j * 3 + 0];
2443 outelement3s[j * 3 + 1] = outelement3i[j * 3 + 1];
2444 outelement3s[j * 3 + 2] = outelement3i[j * 3 + 2];
2448 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2449 for (j = 0;j < surface->num_vertices*2;j++)
2450 loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2452 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2453 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2455 int weightindex[4] = { 0, 0, 0, 0 };
2456 float weightinfluence[4] = { 0, 0, 0, 0 };
2458 int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2459 data += sizeof(dpmvertex_t);
2460 for (k = 0;k < numweights;k++)
2462 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2463 int boneindex = BigLong(vert->bonenum);
2464 const float *m = bonepose + 12 * boneindex;
2465 float influence = BigFloat(vert->influence);
2466 float relativeorigin[3], relativenormal[3];
2467 relativeorigin[0] = BigFloat(vert->origin[0]);
2468 relativeorigin[1] = BigFloat(vert->origin[1]);
2469 relativeorigin[2] = BigFloat(vert->origin[2]);
2470 relativenormal[0] = BigFloat(vert->normal[0]);
2471 relativenormal[1] = BigFloat(vert->normal[1]);
2472 relativenormal[2] = BigFloat(vert->normal[2]);
2473 // blend the vertex bone weights into the base mesh
2474 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2475 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2476 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2477 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2478 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2479 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2482 // store the first (and often only) weight
2483 weightinfluence[0] = influence;
2484 weightindex[0] = boneindex;
2488 // sort the new weight into this vertex's weight table
2489 // (which only accepts up to 4 bones per vertex)
2490 for (l = 0;l < 4;l++)
2492 if (weightinfluence[l] < influence)
2494 // move weaker influence weights out of the way first
2496 for (l2 = 3;l2 > l;l2--)
2498 weightinfluence[l2] = weightinfluence[l2-1];
2499 weightindex[l2] = weightindex[l2-1];
2501 // store the new weight
2502 weightinfluence[l] = influence;
2503 weightindex[l] = boneindex;
2508 data += sizeof(dpmbonevert_t);
2510 loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2511 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = weightindex[0];
2512 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2513 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2514 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2515 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
2516 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2517 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2518 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2521 // since dpm models do not have named sections, reuse their shader name as the section name
2522 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2524 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__);
2526 if (loadmodel->surfmesh.num_blends < meshvertices)
2527 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2529 Mod_FreeSkinFiles(skinfiles);
2530 Mod_MakeSortedSurfaces(loadmodel);
2532 // compute all the mesh information that was not loaded from the file
2533 Mod_BuildBaseBonePoses();
2534 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);
2535 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2536 if(mod_alias_force_animated.string[0])
2537 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2539 // Always make a BIH for the first frame, we can use it where possible.
2540 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2541 if (!loadmodel->surfmesh.isanimated)
2543 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2544 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2545 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2546 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2547 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2550 // because shaders can do somewhat unexpected things, check for unusual features now
2551 for (i = 0;i < loadmodel->num_textures;i++)
2553 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2554 mod->DrawSky = R_Mod_DrawSky;
2555 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2556 mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
2560 // no idea why PSK/PSA files contain weird quaternions but they do...
2561 #define PSKQUATNEGATIONS
2562 void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
2564 int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2565 int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2566 fs_offset_t filesize;
2571 pskboneinfo_t *bones;
2572 pskrawweights_t *rawweights;
2573 //pskboneinfo_t *animbones;
2574 pskaniminfo_t *anims;
2575 pskanimkeys_t *animkeys;
2576 void *animfilebuffer, *animbuffer, *animbufferend;
2577 unsigned char *data;
2579 skinfile_t *skinfiles;
2580 char animname[MAX_QPATH];
2582 float biggestorigin;
2584 pchunk = (pskchunk_t *)buffer;
2585 if (strcmp(pchunk->id, "ACTRHEAD"))
2586 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2588 loadmodel->modeldatatypestring = "PSK";
2590 loadmodel->type = mod_alias;
2591 loadmodel->DrawSky = NULL;
2592 loadmodel->DrawAddWaterPlanes = NULL;
2593 loadmodel->Draw = R_Mod_Draw;
2594 loadmodel->DrawDepth = R_Mod_DrawDepth;
2595 loadmodel->DrawDebug = R_Mod_DrawDebug;
2596 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
2597 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
2598 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
2599 loadmodel->DrawLight = R_Mod_DrawLight;
2600 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2601 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2602 loadmodel->PointSuperContents = NULL;
2603 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2604 loadmodel->synctype = ST_RAND;
2606 FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2607 strlcat(animname, ".psa", sizeof(animname));
2608 animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2609 animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2611 animbufferend = animbuffer;
2630 while (buffer < bufferend)
2632 pchunk = (pskchunk_t *)buffer;
2633 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2634 version = LittleLong(pchunk->version);
2635 recordsize = LittleLong(pchunk->recordsize);
2636 numrecords = LittleLong(pchunk->numrecords);
2637 if (developer_extra.integer)
2638 Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2639 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2640 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);
2641 if (!strcmp(pchunk->id, "ACTRHEAD"))
2645 else if (!strcmp(pchunk->id, "PNTS0000"))
2648 if (recordsize != sizeof(*p))
2649 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2650 // byteswap in place and keep the pointer
2651 numpnts = numrecords;
2652 pnts = (pskpnts_t *)buffer;
2653 for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2655 p->origin[0] = LittleFloat(p->origin[0]);
2656 p->origin[1] = LittleFloat(p->origin[1]);
2657 p->origin[2] = LittleFloat(p->origin[2]);
2661 else if (!strcmp(pchunk->id, "VTXW0000"))
2664 if (recordsize != sizeof(*p))
2665 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2666 // byteswap in place and keep the pointer
2667 numvtxw = numrecords;
2668 vtxw = (pskvtxw_t *)buffer;
2669 for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2671 p->pntsindex = LittleShort(p->pntsindex);
2672 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2673 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2674 if (p->pntsindex >= numpnts)
2676 Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2682 else if (!strcmp(pchunk->id, "FACE0000"))
2685 if (recordsize != sizeof(*p))
2686 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2687 // byteswap in place and keep the pointer
2688 numfaces = numrecords;
2689 faces = (pskface_t *)buffer;
2690 for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2692 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2693 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2694 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2695 p->group = LittleLong(p->group);
2696 if (p->vtxwindex[0] >= numvtxw)
2698 Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2699 p->vtxwindex[0] = 0;
2701 if (p->vtxwindex[1] >= numvtxw)
2703 Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2704 p->vtxwindex[1] = 0;
2706 if (p->vtxwindex[2] >= numvtxw)
2708 Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2709 p->vtxwindex[2] = 0;
2714 else if (!strcmp(pchunk->id, "MATT0000"))
2717 if (recordsize != sizeof(*p))
2718 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2719 // byteswap in place and keep the pointer
2720 nummatts = numrecords;
2721 matts = (pskmatt_t *)buffer;
2722 for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2728 else if (!strcmp(pchunk->id, "REFSKELT"))
2731 if (recordsize != sizeof(*p))
2732 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2733 // byteswap in place and keep the pointer
2734 numbones = numrecords;
2735 bones = (pskboneinfo_t *)buffer;
2736 for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2738 p->numchildren = LittleLong(p->numchildren);
2739 p->parent = LittleLong(p->parent);
2740 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2741 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2742 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2743 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2744 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2745 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2746 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2747 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2748 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2749 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2750 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2751 #ifdef PSKQUATNEGATIONS
2754 p->basepose.quat[0] *= -1;
2755 p->basepose.quat[1] *= -1;
2756 p->basepose.quat[2] *= -1;
2760 p->basepose.quat[0] *= 1;
2761 p->basepose.quat[1] *= -1;
2762 p->basepose.quat[2] *= 1;
2765 if (p->parent < 0 || p->parent >= numbones)
2767 Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2773 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2776 if (recordsize != sizeof(*p))
2777 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2778 // byteswap in place and keep the pointer
2779 numrawweights = numrecords;
2780 rawweights = (pskrawweights_t *)buffer;
2781 for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2783 p->weight = LittleFloat(p->weight);
2784 p->pntsindex = LittleLong(p->pntsindex);
2785 p->boneindex = LittleLong(p->boneindex);
2786 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2788 Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2791 if (p->boneindex < 0 || p->boneindex >= numbones)
2793 Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2801 while (animbuffer < animbufferend)
2803 pchunk = (pskchunk_t *)animbuffer;
2804 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2805 version = LittleLong(pchunk->version);
2806 recordsize = LittleLong(pchunk->recordsize);
2807 numrecords = LittleLong(pchunk->numrecords);
2808 if (developer_extra.integer)
2809 Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2810 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2811 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);
2812 if (!strcmp(pchunk->id, "ANIMHEAD"))
2816 else if (!strcmp(pchunk->id, "BONENAMES"))
2819 if (recordsize != sizeof(*p))
2820 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2821 // byteswap in place and keep the pointer
2822 numanimbones = numrecords;
2823 //animbones = (pskboneinfo_t *)animbuffer;
2824 // NOTE: supposedly psa does not need to match the psk model, the
2825 // bones missing from the psa would simply use their base
2826 // positions from the psk, but this is hard for me to implement
2827 // and people can easily make animations that match.
2828 if (numanimbones != numbones)
2829 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2830 for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2832 p->numchildren = LittleLong(p->numchildren);
2833 p->parent = LittleLong(p->parent);
2834 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2835 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2836 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2837 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2838 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2839 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2840 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2841 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2842 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2843 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2844 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2845 #ifdef PSKQUATNEGATIONS
2848 p->basepose.quat[0] *= -1;
2849 p->basepose.quat[1] *= -1;
2850 p->basepose.quat[2] *= -1;
2854 p->basepose.quat[0] *= 1;
2855 p->basepose.quat[1] *= -1;
2856 p->basepose.quat[2] *= 1;
2859 if (p->parent < 0 || p->parent >= numanimbones)
2861 Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2864 // check that bones are the same as in the base
2865 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2866 Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2870 else if (!strcmp(pchunk->id, "ANIMINFO"))
2873 if (recordsize != sizeof(*p))
2874 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2875 // byteswap in place and keep the pointer
2876 numanims = numrecords;
2877 anims = (pskaniminfo_t *)animbuffer;
2878 for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2880 p->numbones = LittleLong(p->numbones);
2881 p->playtime = LittleFloat(p->playtime);
2882 p->fps = LittleFloat(p->fps);
2883 p->firstframe = LittleLong(p->firstframe);
2884 p->numframes = LittleLong(p->numframes);
2885 if (p->numbones != numbones)
2886 Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2890 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2893 if (recordsize != sizeof(*p))
2894 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2895 numanimkeys = numrecords;
2896 animkeys = (pskanimkeys_t *)animbuffer;
2897 for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2899 p->origin[0] = LittleFloat(p->origin[0]);
2900 p->origin[1] = LittleFloat(p->origin[1]);
2901 p->origin[2] = LittleFloat(p->origin[2]);
2902 p->quat[0] = LittleFloat(p->quat[0]);
2903 p->quat[1] = LittleFloat(p->quat[1]);
2904 p->quat[2] = LittleFloat(p->quat[2]);
2905 p->quat[3] = LittleFloat(p->quat[3]);
2906 p->frametime = LittleFloat(p->frametime);
2907 #ifdef PSKQUATNEGATIONS
2908 if (index % numbones)
2923 // TODO: allocate bonepose stuff
2926 Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2929 if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2930 Host_Error("%s: missing required chunks", loadmodel->name);
2934 loadmodel->numframes = 0;
2935 for (index = 0;index < numanims;index++)
2936 loadmodel->numframes += anims[index].numframes;
2937 if (numanimkeys != numbones * loadmodel->numframes)
2938 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2941 loadmodel->numframes = loadmodel->num_poses = 1;
2943 meshvertices = numvtxw;
2944 meshtriangles = numfaces;
2946 // load external .skin files if present
2947 skinfiles = Mod_LoadSkinFiles();
2948 if (loadmodel->numskins < 1)
2949 loadmodel->numskins = 1;
2950 loadmodel->num_bones = numbones;
2951 loadmodel->num_poses = loadmodel->numframes;
2952 loadmodel->submodelsurfaces_start = 0;
2953 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = nummatts;
2954 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2955 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2956 loadmodel->surfmesh.num_vertices = meshvertices;
2957 loadmodel->surfmesh.num_triangles = meshtriangles;
2958 // do most allocations as one merged chunk
2959 size = loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned short) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t) + ((loadmodel->surfmesh.num_vertices <= 65536) ? (loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0);
2960 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2961 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2962 loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2963 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2964 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2965 loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2966 loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2967 loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2968 loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2969 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2970 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2971 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2972 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2973 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2974 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2975 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2976 loadmodel->surfmesh.num_blends = 0;
2977 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2978 if (loadmodel->surfmesh.num_vertices <= 65536)
2980 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2982 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2983 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
2985 for (i = 0;i < loadmodel->numskins;i++)
2987 loadmodel->skinscenes[i].firstframe = i;
2988 loadmodel->skinscenes[i].framecount = 1;
2989 loadmodel->skinscenes[i].loop = true;
2990 loadmodel->skinscenes[i].framerate = 10;
2994 for (index = 0, i = 0;index < nummatts;index++)
2996 // since psk models do not have named sections, reuse their shader name as the section name
2997 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2998 loadmodel->modelsurfaces_sorted[index] = index;
2999 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
3000 loadmodel->data_surfaces[index].num_firstvertex = 0;
3001 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
3004 // copy over the vertex locations and texcoords
3005 for (index = 0;index < numvtxw;index++)
3007 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
3008 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
3009 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
3010 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
3011 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
3014 // loading the faces is complicated because we need to sort them into surfaces by mattindex
3015 for (index = 0;index < numfaces;index++)
3016 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
3017 for (index = 0, i = 0;index < nummatts;index++)
3019 loadmodel->data_surfaces[index].num_firsttriangle = i;
3020 i += loadmodel->data_surfaces[index].num_triangles;
3021 loadmodel->data_surfaces[index].num_triangles = 0;
3023 for (index = 0;index < numfaces;index++)
3025 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
3026 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
3027 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
3028 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
3031 // copy over the bones
3032 for (index = 0;index < numbones;index++)
3034 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
3035 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
3036 if (loadmodel->data_bones[index].parent >= index)
3037 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
3040 // convert the basepose data
3041 if (loadmodel->num_bones)
3044 matrix4x4_t *basebonepose;
3045 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
3046 matrix4x4_t bonematrix;
3047 matrix4x4_t tempbonematrix;
3048 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
3049 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
3051 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]);
3052 if (loadmodel->data_bones[boneindex].parent >= 0)
3054 tempbonematrix = bonematrix;
3055 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3057 basebonepose[boneindex] = bonematrix;
3058 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3059 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3061 Mem_Free(basebonepose);
3064 // sort the psk point weights into the vertex weight tables
3065 // (which only accept up to 4 bones per vertex)
3066 for (index = 0;index < numvtxw;index++)
3068 int weightindex[4] = { 0, 0, 0, 0 };
3069 float weightinfluence[4] = { 0, 0, 0, 0 };
3071 for (j = 0;j < numrawweights;j++)
3073 if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3075 int boneindex = rawweights[j].boneindex;
3076 float influence = rawweights[j].weight;
3077 for (l = 0;l < 4;l++)
3079 if (weightinfluence[l] < influence)
3081 // move lower influence weights out of the way first
3083 for (l2 = 3;l2 > l;l2--)
3085 weightinfluence[l2] = weightinfluence[l2-1];
3086 weightindex[l2] = weightindex[l2-1];
3088 // store the new weight
3089 weightinfluence[l] = influence;
3090 weightindex[l] = boneindex;
3096 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3097 loadmodel->surfmesh.data_skeletalindex4ub[index*4 ] = weightindex[0];
3098 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3099 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3100 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3101 loadmodel->surfmesh.data_skeletalweight4ub[index*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
3102 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3103 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3104 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3106 if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3107 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3109 // set up the animscenes based on the anims
3112 for (index = 0, i = 0;index < numanims;index++)
3114 for (j = 0;j < anims[index].numframes;j++, i++)
3116 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3117 loadmodel->animscenes[i].firstframe = i;
3118 loadmodel->animscenes[i].framecount = 1;
3119 loadmodel->animscenes[i].loop = true;
3120 loadmodel->animscenes[i].framerate = anims[index].fps;
3123 // calculate the scaling value for bone origins so they can be compressed to short
3125 for (index = 0;index < numanimkeys;index++)
3127 pskanimkeys_t *k = animkeys + index;
3128 biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3129 biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3130 biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3132 loadmodel->num_posescale = biggestorigin / 32767.0f;
3133 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3135 // load the poses from the animkeys
3136 for (index = 0;index < numanimkeys;index++)
3138 pskanimkeys_t *k = animkeys + index;
3140 Vector4Copy(k->quat, quat);
3142 Vector4Negate(quat, quat);
3143 Vector4Normalize2(quat, quat);
3144 // compress poses to the short[7] format for longterm storage
3145 loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3146 loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3147 loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3148 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3149 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3150 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3151 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3156 strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3157 loadmodel->animscenes[0].firstframe = 0;
3158 loadmodel->animscenes[0].framecount = 1;
3159 loadmodel->animscenes[0].loop = true;
3160 loadmodel->animscenes[0].framerate = 10;
3162 // calculate the scaling value for bone origins so they can be compressed to short
3164 for (index = 0;index < numbones;index++)
3166 pskboneinfo_t *p = bones + index;
3167 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3168 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3169 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3171 loadmodel->num_posescale = biggestorigin / 32767.0f;
3172 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3174 // load the basepose as a frame
3175 for (index = 0;index < numbones;index++)
3177 pskboneinfo_t *p = bones + index;
3179 Vector4Copy(p->basepose.quat, quat);
3181 Vector4Negate(quat, quat);
3182 Vector4Normalize2(quat, quat);
3183 // compress poses to the short[7] format for longterm storage
3184 loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3185 loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3186 loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3187 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3188 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3189 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3190 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3194 Mod_FreeSkinFiles(skinfiles);
3196 Mem_Free(animfilebuffer);
3197 Mod_MakeSortedSurfaces(loadmodel);
3199 // compute all the mesh information that was not loaded from the file
3200 // TODO: honor smoothing groups somehow?
3201 if (loadmodel->surfmesh.data_element3s)
3202 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3203 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3204 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3205 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);
3206 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);
3207 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3208 if(mod_alias_force_animated.string[0])
3209 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3211 // Always make a BIH for the first frame, we can use it where possible.
3212 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3213 if (!loadmodel->surfmesh.isanimated)
3215 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3216 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3217 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3218 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3219 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3222 // because shaders can do somewhat unexpected things, check for unusual features now
3223 for (i = 0;i < loadmodel->num_textures;i++)
3225 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3226 mod->DrawSky = R_Mod_DrawSky;
3227 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3228 mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
3232 void Mod_INTERQUAKEMODEL_Load(model_t *mod, void *buffer, void *bufferend)
3234 unsigned char *data;
3236 const unsigned char *pbase, *pend;
3238 skinfile_t *skinfiles;
3239 int i, j, k, meshvertices, meshtriangles;
3240 float biggestorigin;
3241 const unsigned int *inelements;
3243 float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3244 // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3245 const float *vnormal = NULL;
3246 const float *vposition = NULL;
3247 const float *vtangent = NULL;
3248 const float *vtexcoord = NULL;
3249 const float *vcolor4f = NULL;
3250 const unsigned char *vblendindexes = NULL;
3251 const unsigned char *vblendweights = NULL;
3252 const unsigned char *vcolor4ub = NULL;
3253 const unsigned short *framedata = NULL;
3254 // temporary memory allocations (because the data in the file may be misaligned)
3255 iqmanim_t *anims = NULL;
3256 iqmbounds_t *bounds = NULL;
3257 iqmjoint1_t *joint1 = NULL;
3258 iqmjoint_t *joint = NULL;
3259 iqmmesh_t *meshes = NULL;
3260 iqmpose1_t *pose1 = NULL;
3261 iqmpose_t *pose = NULL;
3262 iqmvertexarray_t *vas = NULL;
3264 pbase = (unsigned char *)buffer;
3265 pend = (unsigned char *)bufferend;
3267 if (pbase + sizeof(iqmheader_t) > pend)
3268 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3270 // copy struct (otherwise it may be misaligned)
3271 // LadyHavoc: okay it's definitely not misaligned here, but for consistency...
3272 memcpy(&header, pbase, sizeof(iqmheader_t));
3274 if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3275 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3276 if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3277 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3279 loadmodel->modeldatatypestring = "IQM";
3281 loadmodel->type = mod_alias;
3282 loadmodel->synctype = ST_RAND;
3285 header.version = LittleLong(header.version);
3286 header.filesize = LittleLong(header.filesize);
3287 header.flags = LittleLong(header.flags);
3288 header.num_text = LittleLong(header.num_text);
3289 header.ofs_text = LittleLong(header.ofs_text);
3290 header.num_meshes = LittleLong(header.num_meshes);
3291 header.ofs_meshes = LittleLong(header.ofs_meshes);
3292 header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3293 header.num_vertexes = LittleLong(header.num_vertexes);
3294 header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3295 header.num_triangles = LittleLong(header.num_triangles);
3296 header.ofs_triangles = LittleLong(header.ofs_triangles);
3297 header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3298 header.num_joints = LittleLong(header.num_joints);
3299 header.ofs_joints = LittleLong(header.ofs_joints);
3300 header.num_poses = LittleLong(header.num_poses);
3301 header.ofs_poses = LittleLong(header.ofs_poses);
3302 header.num_anims = LittleLong(header.num_anims);
3303 header.ofs_anims = LittleLong(header.ofs_anims);
3304 header.num_frames = LittleLong(header.num_frames);
3305 header.num_framechannels = LittleLong(header.num_framechannels);
3306 header.ofs_frames = LittleLong(header.ofs_frames);
3307 header.ofs_bounds = LittleLong(header.ofs_bounds);
3308 header.num_comment = LittleLong(header.num_comment);
3309 header.ofs_comment = LittleLong(header.ofs_comment);
3310 header.num_extensions = LittleLong(header.num_extensions);
3311 header.ofs_extensions = LittleLong(header.ofs_extensions);
3313 if (header.version == 1)
3315 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3316 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3318 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3324 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3325 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3327 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3331 if (pbase + header.ofs_text + header.num_text > pend ||
3332 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3333 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3334 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3335 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3336 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3337 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3338 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3339 pbase + header.ofs_comment + header.num_comment > pend)
3341 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3345 // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3346 if (header.num_vertexarrays)
3347 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3348 if (header.num_anims)
3349 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3350 if (header.ofs_bounds)
3351 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3352 if (header.num_meshes)
3353 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3355 for (i = 0;i < (int)header.num_vertexarrays;i++)
3357 iqmvertexarray_t va;
3359 va.type = LittleLong(vas[i].type);
3360 va.flags = LittleLong(vas[i].flags);
3361 va.format = LittleLong(vas[i].format);
3362 va.size = LittleLong(vas[i].size);
3363 va.offset = LittleLong(vas[i].offset);
3364 vsize = header.num_vertexes*va.size;
3367 case IQM_FLOAT: vsize *= sizeof(float); break;
3368 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3371 if (pbase + va.offset + vsize > pend)
3373 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3377 if (va.format == IQM_FLOAT && va.size == 3)
3378 vposition = (const float *)(pbase + va.offset);
3381 if (va.format == IQM_FLOAT && va.size == 2)
3382 vtexcoord = (const float *)(pbase + va.offset);
3385 if (va.format == IQM_FLOAT && va.size == 3)
3386 vnormal = (const float *)(pbase + va.offset);
3389 if (va.format == IQM_FLOAT && va.size == 4)
3390 vtangent = (const float *)(pbase + va.offset);
3392 case IQM_BLENDINDEXES:
3393 if (va.format == IQM_UBYTE && va.size == 4)
3394 vblendindexes = (const unsigned char *)(pbase + va.offset);
3396 case IQM_BLENDWEIGHTS:
3397 if (va.format == IQM_UBYTE && va.size == 4)
3398 vblendweights = (const unsigned char *)(pbase + va.offset);
3401 if (va.format == IQM_FLOAT && va.size == 4)
3402 vcolor4f = (const float *)(pbase + va.offset);
3403 if (va.format == IQM_UBYTE && va.size == 4)
3404 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3408 if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3410 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3414 text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3416 loadmodel->DrawSky = NULL;
3417 loadmodel->DrawAddWaterPlanes = NULL;
3418 loadmodel->Draw = R_Mod_Draw;
3419 loadmodel->DrawDepth = R_Mod_DrawDepth;
3420 loadmodel->DrawDebug = R_Mod_DrawDebug;
3421 loadmodel->DrawPrepass = R_Mod_DrawPrepass;
3422 loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
3423 loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
3424 loadmodel->DrawLight = R_Mod_DrawLight;
3425 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3426 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3427 loadmodel->PointSuperContents = NULL;
3428 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3430 // load external .skin files if present
3431 skinfiles = Mod_LoadSkinFiles();
3432 if (loadmodel->numskins < 1)
3433 loadmodel->numskins = 1;
3435 loadmodel->numframes = max(header.num_anims, 1);
3436 loadmodel->num_bones = header.num_joints;
3437 loadmodel->num_poses = max(header.num_frames, 1);
3438 loadmodel->submodelsurfaces_start = 0;
3439 loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = header.num_meshes;
3440 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3441 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3443 meshvertices = header.num_vertexes;
3444 meshtriangles = header.num_triangles;
3446 // do most allocations as one merged chunk
3447 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * (sizeof(float[14]) + (vcolor4f || vcolor4ub ? sizeof(float[4]) : 0)) + (vblendindexes && vblendweights ? meshvertices * (sizeof(unsigned short) + sizeof(unsigned char[2][4])) : 0) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t));
3448 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3449 loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3450 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3451 loadmodel->surfmesh.num_vertices = meshvertices;
3452 loadmodel->surfmesh.num_triangles = meshtriangles;
3453 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3454 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3455 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3456 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3457 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3458 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3459 if (vcolor4f || vcolor4ub)
3461 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]);
3463 if (vblendindexes && vblendweights)
3465 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3466 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3468 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3469 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3470 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3471 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3472 if (vblendindexes && vblendweights)
3474 loadmodel->surfmesh.num_blends = 0;
3475 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3477 if (meshvertices <= 65536)
3479 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3481 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3482 if (vblendindexes && vblendweights)
3483 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3485 for (i = 0;i < loadmodel->numskins;i++)
3487 loadmodel->skinscenes[i].firstframe = i;
3488 loadmodel->skinscenes[i].framecount = 1;
3489 loadmodel->skinscenes[i].loop = true;
3490 loadmodel->skinscenes[i].framerate = 10;
3493 // load the bone info
3494 if (header.version == 1)
3496 iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3497 if (loadmodel->num_bones)
3498 joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3499 for (i = 0;i < loadmodel->num_bones;i++)
3501 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3502 joint1[i].name = LittleLong(injoint1[i].name);
3503 joint1[i].parent = LittleLong(injoint1[i].parent);
3504 for (j = 0;j < 3;j++)
3506 joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
3507 joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
3508 joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
3510 strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3511 loadmodel->data_bones[i].parent = joint1[i].parent;
3512 if (loadmodel->data_bones[i].parent >= i)
3513 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3514 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]);
3515 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3516 if (loadmodel->data_bones[i].parent >= 0)
3518 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3519 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3520 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3522 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3527 iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
3528 if (header.num_joints)
3529 joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3530 for (i = 0;i < loadmodel->num_bones;i++)
3532 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3533 joint[i].name = LittleLong(injoint[i].name);
3534 joint[i].parent = LittleLong(injoint[i].parent);
3535 for (j = 0;j < 3;j++)
3537 joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
3538 joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
3539 joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
3541 joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
3542 strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3543 loadmodel->data_bones[i].parent = joint[i].parent;
3544 if (loadmodel->data_bones[i].parent >= i)
3545 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3546 if (joint[i].rotation[3] > 0)
3547 Vector4Negate(joint[i].rotation, joint[i].rotation);
3548 Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3549 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]);
3550 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3551 if (loadmodel->data_bones[i].parent >= 0)
3553 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3554 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3555 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3557 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3561 // set up the animscenes based on the anims
3562 for (i = 0;i < (int)header.num_anims;i++)
3565 anim.name = LittleLong(anims[i].name);
3566 anim.first_frame = LittleLong(anims[i].first_frame);
3567 anim.num_frames = LittleLong(anims[i].num_frames);
3568 anim.framerate = LittleFloat(anims[i].framerate);
3569 anim.flags = LittleLong(anims[i].flags);
3570 strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3571 loadmodel->animscenes[i].firstframe = anim.first_frame;
3572 loadmodel->animscenes[i].framecount = anim.num_frames;
3573 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3574 loadmodel->animscenes[i].framerate = anim.framerate;
3576 if (header.num_anims <= 0)
3578 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3579 loadmodel->animscenes[0].firstframe = 0;
3580 loadmodel->animscenes[0].framecount = 1;
3581 loadmodel->animscenes[0].loop = true;
3582 loadmodel->animscenes[0].framerate = 10;
3585 loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3586 if(mod_alias_force_animated.string[0])
3587 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3590 if (header.version == 1)
3592 iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3593 if (header.num_poses)
3594 pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3595 for (i = 0;i < (int)header.num_poses;i++)
3598 pose1[i].parent = LittleLong(inpose1[i].parent);
3599 pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
3600 for (j = 0;j < 9;j++)
3602 pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
3603 pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
3605 f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3606 f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3607 f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3608 f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3609 f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3610 f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3612 if (header.num_frames <= 0)
3614 for (i = 0;i < loadmodel->num_bones;i++)
3617 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3618 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3619 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3625 iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
3626 if (header.num_poses)
3627 pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3628 for (i = 0;i < (int)header.num_poses;i++)
3631 pose[i].parent = LittleLong(inpose[i].parent);
3632 pose[i].channelmask = LittleLong(inpose[i].channelmask);
3633 for (j = 0;j < 10;j++)
3635 pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
3636 pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
3638 f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3639 f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3640 f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3641 f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3642 f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3643 f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3645 if (header.num_frames <= 0)
3647 for (i = 0;i < loadmodel->num_bones;i++)
3650 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3651 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3652 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3656 loadmodel->num_posescale = biggestorigin / 32767.0f;
3657 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3659 // load the pose data
3660 // this unaligned memory access is safe (LittleShort reads as bytes)
3661 framedata = (const unsigned short *)(pbase + header.ofs_frames);
3662 if (header.version == 1)
3664 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3666 for (j = 0;j < (int)header.num_poses;j++, k++)
3668 float qx, qy, qz, qw;
3669 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));
3670 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));
3671 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));
3672 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3673 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3674 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3675 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3676 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3677 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3678 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3679 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3680 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3681 // skip scale data for now
3682 if(pose1[j].channelmask&64) framedata++;
3683 if(pose1[j].channelmask&128) framedata++;
3684 if(pose1[j].channelmask&256) framedata++;
3687 if (header.num_frames <= 0)
3689 for (i = 0;i < loadmodel->num_bones;i++)
3691 float qx, qy, qz, qw;
3692 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3693 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3694 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3695 qx = joint1[i].rotation[0];
3696 qy = joint1[i].rotation[1];
3697 qz = joint1[i].rotation[2];
3698 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3699 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3700 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3701 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3702 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3703 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3709 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3711 for (j = 0;j < (int)header.num_poses;j++, k++)
3714 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));
3715 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));
3716 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));
3717 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3718 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3719 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3720 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3722 Vector4Negate(rot, rot);
3723 Vector4Normalize2(rot, rot);
3724 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3725 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3726 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3727 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3728 // skip scale data for now
3729 if(pose[j].channelmask&128) framedata++;
3730 if(pose[j].channelmask&256) framedata++;
3731 if(pose[j].channelmask&512) framedata++;
3734 if (header.num_frames <= 0)
3736 for (i = 0;i < loadmodel->num_bones;i++)
3738 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3739 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3740 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3741 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3742 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3743 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3744 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3749 // load bounding box data
3750 if (header.ofs_bounds)
3752 float xyradius = 0, radius = 0;
3753 VectorClear(loadmodel->normalmins);
3754 VectorClear(loadmodel->normalmaxs);
3755 for (i = 0; i < (int)header.num_frames;i++)
3758 bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3759 bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3760 bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3761 bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);
3762 bound.maxs[1] = LittleFloat(bounds[i].maxs[1]);
3763 bound.maxs[2] = LittleFloat(bounds[i].maxs[2]);
3764 bound.xyradius = LittleFloat(bounds[i].xyradius);
3765 bound.radius = LittleFloat(bounds[i].radius);
3768 VectorCopy(bound.mins, loadmodel->normalmins);
3769 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3773 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3774 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3775 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3776 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3777 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3778 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3780 if (bound.xyradius > xyradius)
3781 xyradius = bound.xyradius;
3782 if (bound.radius > radius)
3783 radius = bound.radius;
3785 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3786 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3787 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3788 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3789 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3790 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3791 loadmodel->radius = radius;
3792 loadmodel->radius2 = radius * radius;
3795 // load triangle data
3796 // this unaligned memory access is safe (LittleLong reads as bytes)
3797 inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3798 outelements = loadmodel->surfmesh.data_element3i;
3799 for (i = 0;i < (int)header.num_triangles;i++)
3801 outelements[0] = LittleLong(inelements[0]);
3802 outelements[1] = LittleLong(inelements[1]);
3803 outelements[2] = LittleLong(inelements[2]);
3807 if (loadmodel->surfmesh.data_element3s)
3808 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3809 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3810 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3813 // this unaligned memory access is safe (LittleFloat reads as bytes)
3814 outvertex = loadmodel->surfmesh.data_vertex3f;
3815 for (i = 0;i < (int)header.num_vertexes;i++)
3817 outvertex[0] = LittleFloat(vposition[0]);
3818 outvertex[1] = LittleFloat(vposition[1]);
3819 outvertex[2] = LittleFloat(vposition[2]);
3824 outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3825 // this unaligned memory access is safe (LittleFloat reads as bytes)
3826 for (i = 0;i < (int)header.num_vertexes;i++)
3828 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3829 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3834 // this unaligned memory access is safe (LittleFloat reads as bytes)
3837 outnormal = loadmodel->surfmesh.data_normal3f;
3838 for (i = 0;i < (int)header.num_vertexes;i++)
3840 outnormal[0] = LittleFloat(vnormal[0]);
3841 outnormal[1] = LittleFloat(vnormal[1]);
3842 outnormal[2] = LittleFloat(vnormal[2]);
3848 // this unaligned memory access is safe (LittleFloat reads as bytes)
3849 if(vnormal && vtangent)
3851 outnormal = loadmodel->surfmesh.data_normal3f;
3852 outsvector = loadmodel->surfmesh.data_svector3f;
3853 outtvector = loadmodel->surfmesh.data_tvector3f;
3854 for (i = 0;i < (int)header.num_vertexes;i++)
3856 outsvector[0] = LittleFloat(vtangent[0]);
3857 outsvector[1] = LittleFloat(vtangent[1]);
3858 outsvector[2] = LittleFloat(vtangent[2]);
3859 if(LittleFloat(vtangent[3]) < 0)
3860 CrossProduct(outsvector, outnormal, outtvector);
3862 CrossProduct(outnormal, outsvector, outtvector);
3870 // this unaligned memory access is safe (all bytes)
3871 if (vblendindexes && vblendweights)
3873 for (i = 0; i < (int)header.num_vertexes;i++)
3875 blendweights_t weights;
3876 memcpy(weights.index, vblendindexes + i*4, 4);
3877 memcpy(weights.influence, vblendweights + i*4, 4);
3878 loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3879 loadmodel->surfmesh.data_skeletalindex4ub[i*4 ] = weights.index[0];
3880 loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3881 loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3882 loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3883 loadmodel->surfmesh.data_skeletalweight4ub[i*4 ] = weights.influence[0];
3884 loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3885 loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3886 loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3892 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3893 // this unaligned memory access is safe (LittleFloat reads as bytes)
3894 for (i = 0;i < (int)header.num_vertexes;i++)
3896 outcolor[0] = LittleFloat(vcolor4f[0]);
3897 outcolor[1] = LittleFloat(vcolor4f[1]);
3898 outcolor[2] = LittleFloat(vcolor4f[2]);
3899 outcolor[3] = LittleFloat(vcolor4f[3]);
3906 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3907 // this unaligned memory access is safe (all bytes)
3908 for (i = 0;i < (int)header.num_vertexes;i++)
3910 outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3911 outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3912 outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3913 outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3920 for (i = 0;i < (int)header.num_meshes;i++)
3923 msurface_t *surface;
3925 mesh.name = LittleLong(meshes[i].name);
3926 mesh.material = LittleLong(meshes[i].material);
3927 mesh.first_vertex = LittleLong(meshes[i].first_vertex);
3928 mesh.num_vertexes = LittleLong(meshes[i].num_vertexes);
3929 mesh.first_triangle = LittleLong(meshes[i].first_triangle);
3930 mesh.num_triangles = LittleLong(meshes[i].num_triangles);
3932 loadmodel->modelsurfaces_sorted[i] = i;
3933 surface = loadmodel->data_surfaces + i;
3934 surface->texture = loadmodel->data_textures + i;
3935 surface->num_firsttriangle = mesh.first_triangle;
3936 surface->num_triangles = mesh.num_triangles;
3937 surface->num_firstvertex = mesh.first_vertex;
3938 surface->num_vertices = mesh.num_vertexes;
3940 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
3943 Mod_FreeSkinFiles(skinfiles);
3944 Mod_MakeSortedSurfaces(loadmodel);
3946 // compute all the mesh information that was not loaded from the file
3948 Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, r_smoothnormals_areaweighting.integer != 0);
3949 if (!vnormal || !vtangent)
3950 Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
3951 if (!header.ofs_bounds)
3952 Mod_Alias_CalculateBoundingBox();
3954 // Always make a BIH for the first frame, we can use it where possible.
3955 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3956 if (!loadmodel->surfmesh.isanimated)
3958 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3959 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3960 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3961 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3962 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3965 if (joint ) Mem_Free(joint );joint = NULL;
3966 if (joint1 ) Mem_Free(joint1 );joint1 = NULL;
3967 if (pose ) Mem_Free(pose );pose = NULL;
3968 if (pose1 ) Mem_Free(pose1 );pose1 = NULL;
3970 // because shaders can do somewhat unexpected things, check for unusual features now
3971 for (i = 0;i < loadmodel->num_textures;i++)
3973 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3974 mod->DrawSky = R_Mod_DrawSky;
3975 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3976 mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;