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 qboolean r_skeletal_use_sse_defined = false;
31 cvar_t r_skeletal_use_sse = {0, "r_skeletal_use_sse", "1", "use SSE for skeletal model animation"};
33 cvar_t r_skeletal_debugbone = {0, "r_skeletal_debugbone", "-1", "development cvar for testing skeletal model code"};
34 cvar_t r_skeletal_debugbonecomponent = {0, "r_skeletal_debugbonecomponent", "3", "development cvar for testing skeletal model code"};
35 cvar_t r_skeletal_debugbonevalue = {0, "r_skeletal_debugbonevalue", "100", "development cvar for testing skeletal model code"};
36 cvar_t r_skeletal_debugtranslatex = {0, "r_skeletal_debugtranslatex", "1", "development cvar for testing skeletal model code"};
37 cvar_t r_skeletal_debugtranslatey = {0, "r_skeletal_debugtranslatey", "1", "development cvar for testing skeletal model code"};
38 cvar_t r_skeletal_debugtranslatez = {0, "r_skeletal_debugtranslatez", "1", "development cvar for testing skeletal model code"};
39 cvar_t mod_alias_supporttagscale = {0, "mod_alias_supporttagscale", "1", "support scaling factors in bone/tag attachment matrices as supported by MD3"};
40 cvar_t mod_alias_force_animated = {0, "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 dp_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 dp_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(dp_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(dp_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 dp_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 dp_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 dp_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 dp_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 dp_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 qboolean Mod_Alias_CalculateBoundingBox(void)
629 qboolean firstvertex = true;
630 float dist, yawradius, radius;
632 qboolean 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(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask)
758 float segmentmins[3], segmentmaxs[3];
760 float vertex3fbuf[1024*3];
761 float *vertex3f = vertex3fbuf;
762 memset(trace, 0, sizeof(*trace));
764 trace->hitsupercontentsmask = hitsupercontentsmask;
765 if (model->surfmesh.num_vertices > 1024)
766 vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
767 segmentmins[0] = min(start[0], end[0]) - 1;
768 segmentmins[1] = min(start[1], end[1]) - 1;
769 segmentmins[2] = min(start[2], end[2]) - 1;
770 segmentmaxs[0] = max(start[0], end[0]) + 1;
771 segmentmaxs[1] = max(start[1], end[1]) + 1;
772 segmentmaxs[2] = max(start[2], end[2]) + 1;
773 model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
774 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
775 Collision_TraceLineTriangleMeshFloat(trace, start, end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
776 if (vertex3f != vertex3fbuf)
780 static void Mod_MDLMD2MD3_TraceBox(dp_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)
783 vec3_t shiftstart, shiftend;
784 float segmentmins[3], segmentmaxs[3];
786 float vertex3fbuf[1024*3];
787 float *vertex3f = vertex3fbuf;
788 colboxbrushf_t thisbrush_start, thisbrush_end;
789 vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
791 if (VectorCompare(boxmins, boxmaxs))
793 VectorAdd(start, boxmins, shiftstart);
794 VectorAdd(end, boxmins, shiftend);
795 Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask);
796 VectorSubtract(trace->endpos, boxmins, trace->endpos);
800 // box trace, performed as brush trace
801 memset(trace, 0, sizeof(*trace));
803 trace->hitsupercontentsmask = hitsupercontentsmask;
804 if (model->surfmesh.num_vertices > 1024)
805 vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
806 segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1;
807 segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1;
808 segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1;
809 segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1;
810 segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1;
811 segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1;
812 VectorAdd(start, boxmins, boxstartmins);
813 VectorAdd(start, boxmaxs, boxstartmaxs);
814 VectorAdd(end, boxmins, boxendmins);
815 VectorAdd(end, boxmaxs, boxendmaxs);
816 Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL);
817 Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL);
818 model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
819 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
820 Collision_TraceBrushTriangleMeshFloat(trace, &thisbrush_start.brush, &thisbrush_end.brush, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
821 if (vertex3f != vertex3fbuf)
825 static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap)
828 for (i = 0;i < inverts;i++)
830 if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
832 j = vertremap[i]; // not onseam
835 j = vertremap[i+inverts]; // onseam
841 static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *vertremap)
843 int i, f, pose, groupframes;
845 daliasframetype_t *pframetype;
846 daliasframe_t *pinframe;
847 daliasgroup_t *group;
848 daliasinterval_t *intervals;
851 scene = loadmodel->animscenes;
852 for (f = 0;f < loadmodel->numframes;f++)
854 pframetype = (daliasframetype_t *)datapointer;
855 datapointer += sizeof(daliasframetype_t);
856 if (LittleLong (pframetype->type) == ALIAS_SINGLE)
858 // a single frame is still treated as a group
865 group = (daliasgroup_t *)datapointer;
866 datapointer += sizeof(daliasgroup_t);
867 groupframes = LittleLong (group->numframes);
869 // intervals (time per frame)
870 intervals = (daliasinterval_t *)datapointer;
871 datapointer += sizeof(daliasinterval_t) * groupframes;
873 interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
874 if (interval < 0.01f)
876 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
881 // get scene name from first frame
882 pinframe = (daliasframe_t *)datapointer;
884 strlcpy(scene->name, pinframe->name, sizeof(scene->name));
885 scene->firstframe = pose;
886 scene->framecount = groupframes;
887 scene->framerate = 1.0f / interval;
892 for (i = 0;i < groupframes;i++)
894 datapointer += sizeof(daliasframe_t);
895 Mod_ConvertAliasVerts(inverts, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphmdlvertex + pose * loadmodel->surfmesh.num_vertices, vertremap);
896 datapointer += sizeof(trivertx_t) * inverts;
902 static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *skinframe)
904 if (cls.state == ca_dedicated)
908 skinframe = R_SkinFrame_LoadMissing();
909 memset(texture, 0, sizeof(*texture));
910 texture->currentframe = texture;
911 //texture->animated = false;
912 texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(skinframe);
913 texture->currentskinframe = skinframe;
914 //texture->backgroundnumskinframes = 0;
915 //texture->customblendfunc[0] = 0;
916 //texture->customblendfunc[1] = 0;
917 //texture->surfaceflags = 0;
918 //texture->supercontents = 0;
919 //texture->surfaceparms = 0;
920 //texture->textureflags = 0;
922 texture->basematerialflags = MATERIALFLAG_WALL;
923 texture->basealpha = 1.0f;
924 if (texture->currentskinframe->hasalpha)
925 texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
926 texture->currentmaterialflags = texture->basematerialflags;
927 texture->offsetmapping = OFFSETMAPPING_DEFAULT;
928 texture->offsetscale = 1;
929 texture->offsetbias = 0;
930 texture->specularscalemod = 1;
931 texture->specularpowermod = 1;
932 texture->surfaceflags = 0;
933 texture->supercontents = SUPERCONTENTS_SOLID;
934 if (!(texture->basematerialflags & MATERIALFLAG_BLENDED))
935 texture->supercontents |= SUPERCONTENTS_OPAQUE;
936 texture->transparentsort = TRANSPARENTSORT_DISTANCE;
937 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
938 // JUST GREP FOR "specularscalemod = 1".
941 void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
944 char stripbuf[MAX_QPATH];
945 skinfileitem_t *skinfileitem;
946 if(developer_extra.integer)
947 Con_DPrintf("Looking up texture for %s (default: %s)\n", meshname, shadername);
950 // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
951 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
953 memset(skin, 0, sizeof(*skin));
955 for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
957 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
958 if (!strcmp(skinfileitem->name, meshname))
960 Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf));
961 if(developer_extra.integer)
962 Con_DPrintf("--> got %s from skin file\n", stripbuf);
963 Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
969 // don't render unmentioned meshes
970 Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
971 if(developer_extra.integer)
972 Con_DPrintf("--> skipping\n");
973 skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW;
979 if(developer_extra.integer)
980 Con_DPrintf("--> using default\n");
981 Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf));
982 Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
986 #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);
987 #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);
988 void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
990 int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
991 float scales, scalet, interval;
995 stvert_t *pinstverts;
996 dtriangle_t *pintriangles;
997 daliasskintype_t *pinskintype;
998 daliasskingroup_t *pinskingroup;
999 daliasskininterval_t *pinskinintervals;
1000 daliasframetype_t *pinframetype;
1001 daliasgroup_t *pinframegroup;
1002 unsigned char *datapointer, *startframes, *startskins;
1003 char name[MAX_QPATH];
1004 skinframe_t *tempskinframe;
1005 animscene_t *tempskinscenes;
1006 texture_t *tempaliasskins;
1008 int *vertonseam, *vertremap;
1009 skinfile_t *skinfiles;
1012 datapointer = (unsigned char *)buffer;
1013 pinmodel = (mdl_t *)datapointer;
1014 datapointer += sizeof(mdl_t);
1016 version = LittleLong (pinmodel->version);
1017 if (version != ALIAS_VERSION)
1018 Host_Error ("%s has wrong version number (%i should be %i)",
1019 loadmodel->name, version, ALIAS_VERSION);
1021 loadmodel->modeldatatypestring = "MDL";
1023 loadmodel->type = mod_alias;
1024 loadmodel->DrawSky = NULL;
1025 loadmodel->DrawAddWaterPlanes = NULL;
1026 loadmodel->Draw = R_Q1BSP_Draw;
1027 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1028 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1029 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1030 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1031 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1032 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1033 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1034 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1035 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1036 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1037 // FIXME add TraceBrush!
1038 loadmodel->PointSuperContents = NULL;
1039 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1041 loadmodel->num_surfaces = 1;
1042 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1043 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
1044 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1045 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1046 loadmodel->sortedmodelsurfaces[0] = 0;
1048 loadmodel->numskins = LittleLong(pinmodel->numskins);
1049 BOUNDI(loadmodel->numskins,0,65536);
1050 skinwidth = LittleLong (pinmodel->skinwidth);
1051 BOUNDI(skinwidth,0,65536);
1052 skinheight = LittleLong (pinmodel->skinheight);
1053 BOUNDI(skinheight,0,65536);
1054 numverts = LittleLong(pinmodel->numverts);
1055 BOUNDI(numverts,0,65536);
1056 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
1057 BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
1058 loadmodel->numframes = LittleLong(pinmodel->numframes);
1059 BOUNDI(loadmodel->numframes,0,65536);
1060 loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
1061 BOUNDI((int)loadmodel->synctype,0,2);
1062 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1063 i = LittleLong (pinmodel->flags);
1064 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1066 for (i = 0;i < 3;i++)
1068 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
1069 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
1072 startskins = datapointer;
1074 for (i = 0;i < loadmodel->numskins;i++)
1076 pinskintype = (daliasskintype_t *)datapointer;
1077 datapointer += sizeof(daliasskintype_t);
1078 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
1082 pinskingroup = (daliasskingroup_t *)datapointer;
1083 datapointer += sizeof(daliasskingroup_t);
1084 groupskins = LittleLong(pinskingroup->numskins);
1085 datapointer += sizeof(daliasskininterval_t) * groupskins;
1088 for (j = 0;j < groupskins;j++)
1090 datapointer += skinwidth * skinheight;
1095 pinstverts = (stvert_t *)datapointer;
1096 datapointer += sizeof(stvert_t) * numverts;
1098 pintriangles = (dtriangle_t *)datapointer;
1099 datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
1101 startframes = datapointer;
1102 loadmodel->surfmesh.num_morphframes = 0;
1103 for (i = 0;i < loadmodel->numframes;i++)
1105 pinframetype = (daliasframetype_t *)datapointer;
1106 datapointer += sizeof(daliasframetype_t);
1107 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1111 pinframegroup = (daliasgroup_t *)datapointer;
1112 datapointer += sizeof(daliasgroup_t);
1113 groupframes = LittleLong(pinframegroup->numframes);
1114 datapointer += sizeof(daliasinterval_t) * groupframes;
1117 for (j = 0;j < groupframes;j++)
1119 datapointer += sizeof(daliasframe_t);
1120 datapointer += sizeof(trivertx_t) * numverts;
1121 loadmodel->surfmesh.num_morphframes++;
1124 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1126 // store texture coordinates into temporary array, they will be stored
1127 // after usage is determined (triangle data)
1128 vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1129 vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1130 vertonseam = vertremap + numverts * 2;
1132 scales = 1.0 / skinwidth;
1133 scalet = 1.0 / skinheight;
1134 for (i = 0;i < numverts;i++)
1136 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1137 vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales;
1138 vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet;
1139 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1140 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1143 // load triangle data
1144 loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1146 // read the triangle elements
1147 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1148 for (j = 0;j < 3;j++)
1149 loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1150 // validate (note numverts is used because this is the original data)
1151 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1152 // now butcher the elements according to vertonseam and tri->facesfront
1153 // and then compact the vertex set to remove duplicates
1154 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1155 if (!LittleLong(pintriangles[i].facesfront)) // backface
1156 for (j = 0;j < 3;j++)
1157 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1158 loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1160 // (this uses vertremap to count usage to save some memory)
1161 for (i = 0;i < numverts*2;i++)
1163 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1164 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1165 // build remapping table and compact array
1166 loadmodel->surfmesh.num_vertices = 0;
1167 for (i = 0;i < numverts*2;i++)
1171 vertremap[i] = loadmodel->surfmesh.num_vertices;
1172 vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1173 vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1174 loadmodel->surfmesh.num_vertices++;
1177 vertremap[i] = -1; // not used at all
1179 // remap the elements to the new vertex set
1180 for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1181 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1182 // store the texture coordinates
1183 loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1184 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1186 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1187 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1190 // generate ushort elements array if possible
1191 if (loadmodel->surfmesh.num_vertices <= 65536)
1192 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1193 if (loadmodel->surfmesh.data_element3s)
1194 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1195 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1198 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1199 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1200 if (r_enableshadowvolumes.integer)
1202 loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
1204 Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1205 if (loadmodel->surfmesh.data_neighbor3i)
1206 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1207 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1208 Mod_Alias_MorphMesh_CompileFrames();
1211 Mem_Free(vertremap);
1214 skinfiles = Mod_LoadSkinFiles();
1217 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1218 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1219 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1220 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1221 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1222 Mod_FreeSkinFiles(skinfiles);
1223 for (i = 0;i < loadmodel->numskins;i++)
1225 loadmodel->skinscenes[i].firstframe = i;
1226 loadmodel->skinscenes[i].framecount = 1;
1227 loadmodel->skinscenes[i].loop = true;
1228 loadmodel->skinscenes[i].framerate = 10;
1233 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1234 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1235 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1236 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1238 datapointer = startskins;
1239 for (i = 0;i < loadmodel->numskins;i++)
1241 pinskintype = (daliasskintype_t *)datapointer;
1242 datapointer += sizeof(daliasskintype_t);
1244 if (pinskintype->type == ALIAS_SKIN_SINGLE)
1251 pinskingroup = (daliasskingroup_t *)datapointer;
1252 datapointer += sizeof(daliasskingroup_t);
1254 groupskins = LittleLong (pinskingroup->numskins);
1256 pinskinintervals = (daliasskininterval_t *)datapointer;
1257 datapointer += sizeof(daliasskininterval_t) * groupskins;
1259 interval = LittleFloat(pinskinintervals[0].interval);
1260 if (interval < 0.01f)
1262 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1267 dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1268 loadmodel->skinscenes[i].firstframe = totalskins;
1269 loadmodel->skinscenes[i].framecount = groupskins;
1270 loadmodel->skinscenes[i].framerate = 1.0f / interval;
1271 loadmodel->skinscenes[i].loop = true;
1273 for (j = 0;j < groupskins;j++)
1276 dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1278 dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1279 if (!Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS))
1280 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, R_SkinFrame_LoadInternalQuake(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight));
1281 datapointer += skinwidth * skinheight;
1285 // check for skins that don't exist in the model, but do exist as external images
1286 // (this was added because yummyluv kept pestering me about support for it)
1287 // TODO: support shaders here?
1288 while ((tempskinframe = R_SkinFrame_LoadExternal(va(vabuf, sizeof(vabuf), "%s_%i", loadmodel->name, loadmodel->numskins), (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false)))
1290 // expand the arrays to make room
1291 tempskinscenes = loadmodel->skinscenes;
1292 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1293 memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1294 Mem_Free(tempskinscenes);
1296 tempaliasskins = loadmodel->data_textures;
1297 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1298 memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1299 Mem_Free(tempaliasskins);
1301 // store the info about the new skin
1302 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, tempskinframe);
1303 strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1304 loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1305 loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1306 loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1307 loadmodel->skinscenes[loadmodel->numskins].loop = true;
1309 //increase skin counts
1310 loadmodel->numskins++;
1313 // fix up the pointers since they are pointing at the old textures array
1314 // FIXME: this is a hack!
1315 for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1316 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1320 surface = loadmodel->data_surfaces;
1321 surface->texture = loadmodel->data_textures;
1322 surface->num_firsttriangle = 0;
1323 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1324 surface->num_firstvertex = 0;
1325 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1327 if(mod_alias_force_animated.string[0])
1328 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1330 if (!loadmodel->surfmesh.isanimated)
1332 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1333 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1334 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1335 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1336 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1337 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1340 // because shaders can do somewhat unexpected things, check for unusual features now
1341 for (i = 0;i < loadmodel->num_textures;i++)
1343 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1344 mod->DrawSky = R_Q1BSP_DrawSky;
1345 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1346 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1350 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
1352 int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1353 float iskinwidth, iskinheight;
1354 unsigned char *data;
1355 msurface_t *surface;
1357 unsigned char *base, *datapointer;
1358 md2frame_t *pinframe;
1360 md2triangle_t *intri;
1361 unsigned short *inst;
1362 struct md2verthash_s
1364 struct md2verthash_s *next;
1368 *hash, **md2verthash, *md2verthashdata;
1369 skinfile_t *skinfiles;
1371 pinmodel = (md2_t *)buffer;
1372 base = (unsigned char *)buffer;
1374 version = LittleLong (pinmodel->version);
1375 if (version != MD2ALIAS_VERSION)
1376 Host_Error ("%s has wrong version number (%i should be %i)",
1377 loadmodel->name, version, MD2ALIAS_VERSION);
1379 loadmodel->modeldatatypestring = "MD2";
1381 loadmodel->type = mod_alias;
1382 loadmodel->DrawSky = NULL;
1383 loadmodel->DrawAddWaterPlanes = NULL;
1384 loadmodel->Draw = R_Q1BSP_Draw;
1385 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1386 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1387 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1388 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1389 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1390 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1391 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1392 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1393 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1394 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1395 loadmodel->PointSuperContents = NULL;
1396 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1398 if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1399 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1400 if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1401 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1402 if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1403 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1404 if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1405 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1407 end = LittleLong(pinmodel->ofs_end);
1408 if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1409 Host_Error ("%s is not a valid model", loadmodel->name);
1410 if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1411 Host_Error ("%s is not a valid model", loadmodel->name);
1412 if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1413 Host_Error ("%s is not a valid model", loadmodel->name);
1414 if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1415 Host_Error ("%s is not a valid model", loadmodel->name);
1416 if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1417 Host_Error ("%s is not a valid model", loadmodel->name);
1419 loadmodel->numskins = LittleLong(pinmodel->num_skins);
1420 numxyz = LittleLong(pinmodel->num_xyz);
1421 numst = LittleLong(pinmodel->num_st);
1422 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1423 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1424 loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1425 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1426 skinwidth = LittleLong(pinmodel->skinwidth);
1427 skinheight = LittleLong(pinmodel->skinheight);
1428 iskinwidth = 1.0f / skinwidth;
1429 iskinheight = 1.0f / skinheight;
1431 loadmodel->num_surfaces = 1;
1432 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1433 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]) + (r_enableshadowvolumes.integer ? loadmodel->surfmesh.num_triangles * sizeof(int[3]) : 0));
1434 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1435 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1436 loadmodel->sortedmodelsurfaces[0] = 0;
1437 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1438 loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1439 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1440 if (r_enableshadowvolumes.integer)
1442 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1445 loadmodel->synctype = ST_RAND;
1448 inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1449 skinfiles = Mod_LoadSkinFiles();
1452 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1453 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1454 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1455 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1456 Mod_FreeSkinFiles(skinfiles);
1458 else if (loadmodel->numskins)
1460 // skins found (most likely not a player model)
1461 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1462 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1463 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1464 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1465 Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
1469 // no skins (most likely a player model)
1470 loadmodel->numskins = 1;
1471 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1472 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1473 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1474 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL);
1477 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1478 for (i = 0;i < loadmodel->numskins;i++)
1480 loadmodel->skinscenes[i].firstframe = i;
1481 loadmodel->skinscenes[i].framecount = 1;
1482 loadmodel->skinscenes[i].loop = true;
1483 loadmodel->skinscenes[i].framerate = 10;
1486 // load the triangles and stvert data
1487 inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1488 intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1489 md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1490 md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1491 // swap the triangle list
1492 loadmodel->surfmesh.num_vertices = 0;
1493 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1495 for (j = 0;j < 3;j++)
1497 xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1498 st = (unsigned short) LittleShort (intri[i].index_st[j]);
1501 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1506 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1509 hashindex = (xyz * 256 + st) & 65535;
1510 for (hash = md2verthash[hashindex];hash;hash = hash->next)
1511 if (hash->xyz == xyz && hash->st == st)
1515 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1518 hash->next = md2verthash[hashindex];
1519 md2verthash[hashindex] = hash;
1521 loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1525 vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1526 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));
1527 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1528 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1529 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1532 hash = md2verthashdata + i;
1533 vertremap[i] = hash->xyz;
1534 sts = LittleShort(inst[hash->st*2+0]);
1535 stt = LittleShort(inst[hash->st*2+1]);
1536 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1538 Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1542 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1543 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1546 Mem_Free(md2verthash);
1547 Mem_Free(md2verthashdata);
1549 // generate ushort elements array if possible
1550 if (loadmodel->surfmesh.num_vertices <= 65536)
1551 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1552 if (loadmodel->surfmesh.data_element3s)
1553 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1554 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1557 datapointer = (base + LittleLong(pinmodel->ofs_frames));
1558 for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1563 pinframe = (md2frame_t *)datapointer;
1564 datapointer += sizeof(md2frame_t);
1565 // store the frame scale/translate into the appropriate array
1566 for (j = 0;j < 3;j++)
1568 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1569 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1571 // convert the vertices
1572 v = (trivertx_t *)datapointer;
1573 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1574 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1575 out[k] = v[vertremap[k]];
1576 datapointer += numxyz * sizeof(trivertx_t);
1578 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1579 loadmodel->animscenes[i].firstframe = i;
1580 loadmodel->animscenes[i].framecount = 1;
1581 loadmodel->animscenes[i].framerate = 10;
1582 loadmodel->animscenes[i].loop = true;
1585 Mem_Free(vertremap);
1587 if (loadmodel->surfmesh.data_neighbor3i)
1588 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1589 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1590 Mod_Alias_MorphMesh_CompileFrames();
1591 if(mod_alias_force_animated.string[0])
1592 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1594 surface = loadmodel->data_surfaces;
1595 surface->texture = loadmodel->data_textures;
1596 surface->num_firsttriangle = 0;
1597 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1598 surface->num_firstvertex = 0;
1599 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1601 if (!loadmodel->surfmesh.isanimated)
1603 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1604 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1605 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1606 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1607 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1608 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1611 // because shaders can do somewhat unexpected things, check for unusual features now
1612 for (i = 0;i < loadmodel->num_textures;i++)
1614 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1615 mod->DrawSky = R_Q1BSP_DrawSky;
1616 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1617 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1621 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
1623 int i, j, k, version, meshvertices, meshtriangles;
1624 unsigned char *data;
1625 msurface_t *surface;
1626 md3modelheader_t *pinmodel;
1627 md3frameinfo_t *pinframe;
1630 skinfile_t *skinfiles;
1632 pinmodel = (md3modelheader_t *)buffer;
1634 if (memcmp(pinmodel->identifier, "IDP3", 4))
1635 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1636 version = LittleLong (pinmodel->version);
1637 if (version != MD3VERSION)
1638 Host_Error ("%s has wrong version number (%i should be %i)",
1639 loadmodel->name, version, MD3VERSION);
1641 skinfiles = Mod_LoadSkinFiles();
1642 if (loadmodel->numskins < 1)
1643 loadmodel->numskins = 1;
1645 loadmodel->modeldatatypestring = "MD3";
1647 loadmodel->type = mod_alias;
1648 loadmodel->DrawSky = NULL;
1649 loadmodel->DrawAddWaterPlanes = NULL;
1650 loadmodel->Draw = R_Q1BSP_Draw;
1651 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1652 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1653 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1654 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1655 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1656 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1657 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1658 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1659 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1660 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1661 loadmodel->PointSuperContents = NULL;
1662 loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1663 loadmodel->synctype = ST_RAND;
1664 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1665 i = LittleLong (pinmodel->flags);
1666 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1668 // set up some global info about the model
1669 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1670 loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1672 // make skinscenes for the skins (no groups)
1673 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1674 for (i = 0;i < loadmodel->numskins;i++)
1676 loadmodel->skinscenes[i].firstframe = i;
1677 loadmodel->skinscenes[i].framecount = 1;
1678 loadmodel->skinscenes[i].loop = true;
1679 loadmodel->skinscenes[i].framerate = 10;
1683 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1684 for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1686 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1687 loadmodel->animscenes[i].firstframe = i;
1688 loadmodel->animscenes[i].framecount = 1;
1689 loadmodel->animscenes[i].framerate = 10;
1690 loadmodel->animscenes[i].loop = true;
1694 loadmodel->num_tagframes = loadmodel->numframes;
1695 loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1696 loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1697 for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1699 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1700 for (j = 0;j < 9;j++)
1701 loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1702 for (j = 0;j < 3;j++)
1703 loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1704 //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);
1710 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)))
1712 if (memcmp(pinmesh->identifier, "IDP3", 4))
1713 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1714 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1715 Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1716 meshvertices += LittleLong(pinmesh->num_vertices);
1717 meshtriangles += LittleLong(pinmesh->num_triangles);
1720 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1721 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1722 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1723 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]) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * sizeof(float[2]) + meshvertices * loadmodel->numframes * sizeof(md3vertex_t));
1724 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1725 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1726 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1727 loadmodel->surfmesh.num_vertices = meshvertices;
1728 loadmodel->surfmesh.num_triangles = meshtriangles;
1729 loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1730 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1731 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1732 if (r_enableshadowvolumes.integer)
1734 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1736 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1737 loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1738 if (meshvertices <= 65536)
1740 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1745 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)))
1747 if (memcmp(pinmesh->identifier, "IDP3", 4))
1748 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1749 loadmodel->sortedmodelsurfaces[i] = i;
1750 surface = loadmodel->data_surfaces + i;
1751 surface->texture = loadmodel->data_textures + i;
1752 surface->num_firsttriangle = meshtriangles;
1753 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1754 surface->num_firstvertex = meshvertices;
1755 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1756 meshvertices += surface->num_vertices;
1757 meshtriangles += surface->num_triangles;
1759 for (j = 0;j < surface->num_triangles * 3;j++)
1760 loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1761 for (j = 0;j < surface->num_vertices;j++)
1763 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1764 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1766 for (j = 0;j < loadmodel->numframes;j++)
1768 const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1769 md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1770 for (k = 0;k < surface->num_vertices;k++, in++, out++)
1772 out->origin[0] = LittleShort(in->origin[0]);
1773 out->origin[1] = LittleShort(in->origin[1]);
1774 out->origin[2] = LittleShort(in->origin[2]);
1775 out->pitch = in->pitch;
1780 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1782 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1784 if (loadmodel->surfmesh.data_element3s)
1785 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1786 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1787 if (loadmodel->surfmesh.data_neighbor3i)
1788 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1789 Mod_Alias_MorphMesh_CompileFrames();
1790 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1791 Mod_FreeSkinFiles(skinfiles);
1792 Mod_MakeSortedSurfaces(loadmodel);
1793 if(mod_alias_force_animated.string[0])
1794 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1796 if (!loadmodel->surfmesh.isanimated)
1798 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1799 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1800 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1801 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1802 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1803 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1806 // because shaders can do somewhat unexpected things, check for unusual features now
1807 for (i = 0;i < loadmodel->num_textures;i++)
1809 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1810 mod->DrawSky = R_Q1BSP_DrawSky;
1811 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1812 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1816 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1818 zymtype1header_t *pinmodel, *pheader;
1819 unsigned char *pbase;
1820 int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1821 float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1822 zymvertex_t *verts, *vertdata;
1826 skinfile_t *skinfiles;
1827 unsigned char *data;
1828 msurface_t *surface;
1830 pinmodel = (zymtype1header_t *)buffer;
1831 pbase = (unsigned char *)buffer;
1832 if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1833 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1834 if (BigLong(pinmodel->type) != 1)
1835 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1837 loadmodel->modeldatatypestring = "ZYM";
1839 loadmodel->type = mod_alias;
1840 loadmodel->synctype = ST_RAND;
1844 pheader->type = BigLong(pinmodel->type);
1845 pheader->filesize = BigLong(pinmodel->filesize);
1846 pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1847 pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1848 pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1849 pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1850 pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1851 pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1852 pheader->radius = BigFloat(pinmodel->radius);
1853 pheader->numverts = BigLong(pinmodel->numverts);
1854 pheader->numtris = BigLong(pinmodel->numtris);
1855 pheader->numshaders = BigLong(pinmodel->numshaders);
1856 pheader->numbones = BigLong(pinmodel->numbones);
1857 pheader->numscenes = BigLong(pinmodel->numscenes);
1858 pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1859 pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1860 pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1861 pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1862 pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1863 pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1864 pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1865 pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1866 pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1867 pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1868 pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1869 pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1870 pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1871 pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1872 pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1873 pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1874 pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1875 pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1877 if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1879 Con_Printf("%s has no geometry\n", loadmodel->name);
1882 if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1884 Con_Printf("%s has no animations\n", loadmodel->name);
1888 loadmodel->DrawSky = NULL;
1889 loadmodel->DrawAddWaterPlanes = NULL;
1890 loadmodel->Draw = R_Q1BSP_Draw;
1891 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1892 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1893 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1894 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1895 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1896 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1897 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1898 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1899 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1900 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1901 loadmodel->PointSuperContents = NULL;
1902 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1904 loadmodel->numframes = pheader->numscenes;
1905 loadmodel->num_surfaces = pheader->numshaders;
1907 skinfiles = Mod_LoadSkinFiles();
1908 if (loadmodel->numskins < 1)
1909 loadmodel->numskins = 1;
1911 // make skinscenes for the skins (no groups)
1912 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1913 for (i = 0;i < loadmodel->numskins;i++)
1915 loadmodel->skinscenes[i].firstframe = i;
1916 loadmodel->skinscenes[i].framecount = 1;
1917 loadmodel->skinscenes[i].loop = true;
1918 loadmodel->skinscenes[i].framerate = 10;
1922 // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
1923 modelradius = pheader->radius;
1924 for (i = 0;i < 3;i++)
1926 loadmodel->normalmins[i] = pheader->mins[i];
1927 loadmodel->normalmaxs[i] = pheader->maxs[i];
1928 loadmodel->rotatedmins[i] = -modelradius;
1929 loadmodel->rotatedmaxs[i] = modelradius;
1931 corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1932 corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1933 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1934 if (loadmodel->yawmaxs[0] > modelradius)
1935 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1936 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1937 loadmodel->yawmins[2] = loadmodel->normalmins[2];
1938 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1939 loadmodel->radius = modelradius;
1940 loadmodel->radius2 = modelradius * modelradius;
1942 // go through the lumps, swapping things
1944 //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1945 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1946 scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1947 numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1948 for (i = 0;i < pheader->numscenes;i++)
1950 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1951 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1952 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1953 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1954 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1955 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1956 Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1957 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1958 Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1959 if (loadmodel->animscenes[i].framerate < 0)
1960 Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1964 //zymlump_t lump_bones; // zymbone_t bone[numbones];
1965 loadmodel->num_bones = pheader->numbones;
1966 loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1967 bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1968 for (i = 0;i < pheader->numbones;i++)
1970 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1971 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1972 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1973 if (loadmodel->data_bones[i].parent >= i)
1974 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1977 //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1978 vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1979 bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1980 for (i = 0;i < pheader->numverts;i++)
1982 vertbonecounts[i] = BigLong(bonecount[i]);
1983 if (vertbonecounts[i] != 1)
1984 Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1987 loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1989 meshvertices = pheader->numverts;
1990 meshtriangles = pheader->numtris;
1992 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1993 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1994 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1995 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]) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + (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]));
1996 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1997 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1998 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1999 loadmodel->surfmesh.num_vertices = meshvertices;
2000 loadmodel->surfmesh.num_triangles = meshtriangles;
2001 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2002 if (r_enableshadowvolumes.integer)
2004 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2006 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2007 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2008 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2009 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2010 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2011 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2012 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2013 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2014 loadmodel->surfmesh.num_blends = 0;
2015 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2016 if (loadmodel->surfmesh.num_vertices <= 65536)
2018 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2020 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2021 loadmodel->surfmesh.data_blendweights = NULL;
2023 //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
2024 poses = (float *) (pheader->lump_poses.start + pbase);
2025 // figure out scale of model from root bone, for compatibility with old zmodel versions
2026 tempvec[0] = BigFloat(poses[0]);
2027 tempvec[1] = BigFloat(poses[1]);
2028 tempvec[2] = BigFloat(poses[2]);
2029 modelscale = VectorLength(tempvec);
2031 for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
2033 f = fabs(BigFloat(poses[i]));
2034 biggestorigin = max(biggestorigin, f);
2036 loadmodel->num_posescale = biggestorigin / 32767.0f;
2037 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2038 for (i = 0;i < numposes;i++)
2040 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
2041 for (j = 0;j < loadmodel->num_bones;j++)
2044 matrix4x4_t posematrix;
2045 for (k = 0;k < 12;k++)
2046 pose[k] = BigFloat(frameposes[j*12+k]);
2047 //if (j < loadmodel->num_bones)
2048 // 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));
2049 // scale child bones to match the root scale
2050 if (loadmodel->data_bones[j].parent >= 0)
2052 pose[3] *= modelscale;
2053 pose[7] *= modelscale;
2054 pose[11] *= modelscale;
2056 // normalize rotation matrix
2057 VectorNormalize(pose + 0);
2058 VectorNormalize(pose + 4);
2059 VectorNormalize(pose + 8);
2060 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2061 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2065 //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2066 verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2067 vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2068 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2069 // (converting from weight-blending skeletal animation to
2070 // deformation-based skeletal animation)
2071 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2072 for (i = 0;i < loadmodel->num_bones;i++)
2075 for (k = 0;k < 12;k++)
2076 m[k] = BigFloat(poses[i*12+k]);
2077 if (loadmodel->data_bones[i].parent >= 0)
2078 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2080 for (k = 0;k < 12;k++)
2081 bonepose[12*i+k] = m[k];
2083 for (j = 0;j < pheader->numverts;j++)
2085 // this format really should have had a per vertexweight weight value...
2086 // but since it does not, the weighting is completely ignored and
2087 // only one weight is allowed per vertex
2088 int boneindex = BigLong(vertdata[j].bonenum);
2089 const float *m = bonepose + 12 * boneindex;
2090 float relativeorigin[3];
2091 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2092 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2093 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2094 // transform the vertex bone weight into the base mesh
2095 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2096 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2097 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2098 // store the weight as the primary weight on this vertex
2099 loadmodel->surfmesh.blends[j] = boneindex;
2100 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = boneindex;
2101 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2102 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2103 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2104 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = 255;
2105 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2106 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2107 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2110 // normals and tangents are calculated after elements are loaded
2112 //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2113 outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2114 intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2115 for (i = 0;i < pheader->numverts;i++)
2117 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2118 // flip T coordinate for OpenGL
2119 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2122 //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2123 //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2124 //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2126 //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2127 //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)
2128 // byteswap, validate, and swap winding order of tris
2129 count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2130 if (pheader->lump_render.length != count)
2131 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2132 renderlist = (int *) (pheader->lump_render.start + pbase);
2133 renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2135 for (i = 0;i < loadmodel->num_surfaces;i++)
2137 int firstvertex, lastvertex;
2138 if (renderlist >= renderlistend)
2139 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2140 count = BigLong(*renderlist);renderlist++;
2141 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2142 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2144 loadmodel->sortedmodelsurfaces[i] = i;
2145 surface = loadmodel->data_surfaces + i;
2146 surface->texture = loadmodel->data_textures + i;
2147 surface->num_firsttriangle = meshtriangles;
2148 surface->num_triangles = count;
2149 meshtriangles += surface->num_triangles;
2151 // load the elements
2152 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2153 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2155 outelements[j*3+2] = BigLong(renderlist[0]);
2156 outelements[j*3+1] = BigLong(renderlist[1]);
2157 outelements[j*3+0] = BigLong(renderlist[2]);
2159 // validate the elements and find the used vertex range
2160 firstvertex = meshvertices;
2162 for (j = 0;j < surface->num_triangles * 3;j++)
2164 if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2165 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2166 firstvertex = min(firstvertex, outelements[j]);
2167 lastvertex = max(lastvertex, outelements[j]);
2169 surface->num_firstvertex = firstvertex;
2170 surface->num_vertices = lastvertex + 1 - firstvertex;
2172 // since zym models do not have named sections, reuse their shader
2173 // name as the section name
2174 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2175 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2177 Mod_FreeSkinFiles(skinfiles);
2178 Mem_Free(vertbonecounts);
2180 Mod_MakeSortedSurfaces(loadmodel);
2182 // compute all the mesh information that was not loaded from the file
2183 if (loadmodel->surfmesh.data_element3s)
2184 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2185 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2186 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2187 Mod_BuildBaseBonePoses();
2188 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);
2189 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);
2190 if (loadmodel->surfmesh.data_neighbor3i)
2191 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2192 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2193 if(mod_alias_force_animated.string[0])
2194 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2196 if (!loadmodel->surfmesh.isanimated)
2198 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2199 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2200 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2201 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2202 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2203 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2206 // because shaders can do somewhat unexpected things, check for unusual features now
2207 for (i = 0;i < loadmodel->num_textures;i++)
2209 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2210 mod->DrawSky = R_Q1BSP_DrawSky;
2211 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2212 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2216 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2218 dpmheader_t *pheader;
2222 unsigned char *pbase;
2223 int i, j, k, meshvertices, meshtriangles;
2224 skinfile_t *skinfiles;
2225 unsigned char *data;
2227 float biggestorigin, tempvec[3], modelscale;
2231 pheader = (dpmheader_t *)buffer;
2232 pbase = (unsigned char *)buffer;
2233 if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2234 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2235 if (BigLong(pheader->type) != 2)
2236 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2238 loadmodel->modeldatatypestring = "DPM";
2240 loadmodel->type = mod_alias;
2241 loadmodel->synctype = ST_RAND;
2244 pheader->type = BigLong(pheader->type);
2245 pheader->filesize = BigLong(pheader->filesize);
2246 pheader->mins[0] = BigFloat(pheader->mins[0]);
2247 pheader->mins[1] = BigFloat(pheader->mins[1]);
2248 pheader->mins[2] = BigFloat(pheader->mins[2]);
2249 pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2250 pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2251 pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2252 pheader->yawradius = BigFloat(pheader->yawradius);
2253 pheader->allradius = BigFloat(pheader->allradius);
2254 pheader->num_bones = BigLong(pheader->num_bones);
2255 pheader->num_meshs = BigLong(pheader->num_meshs);
2256 pheader->num_frames = BigLong(pheader->num_frames);
2257 pheader->ofs_bones = BigLong(pheader->ofs_bones);
2258 pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2259 pheader->ofs_frames = BigLong(pheader->ofs_frames);
2261 if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2263 Con_Printf("%s has no geometry\n", loadmodel->name);
2266 if (pheader->num_frames < 1)
2268 Con_Printf("%s has no frames\n", loadmodel->name);
2272 loadmodel->DrawSky = NULL;
2273 loadmodel->DrawAddWaterPlanes = NULL;
2274 loadmodel->Draw = R_Q1BSP_Draw;
2275 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2276 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2277 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2278 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2279 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2280 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2281 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2282 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2283 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2284 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2285 loadmodel->PointSuperContents = NULL;
2286 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2289 // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2290 for (i = 0;i < 3;i++)
2292 loadmodel->normalmins[i] = pheader->mins[i];
2293 loadmodel->normalmaxs[i] = pheader->maxs[i];
2294 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2295 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2296 loadmodel->rotatedmins[i] = -pheader->allradius;
2297 loadmodel->rotatedmaxs[i] = pheader->allradius;
2299 loadmodel->radius = pheader->allradius;
2300 loadmodel->radius2 = pheader->allradius * pheader->allradius;
2302 // load external .skin files if present
2303 skinfiles = Mod_LoadSkinFiles();
2304 if (loadmodel->numskins < 1)
2305 loadmodel->numskins = 1;
2310 // gather combined statistics from the meshes
2311 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2312 for (i = 0;i < (int)pheader->num_meshs;i++)
2314 int numverts = BigLong(dpmmesh->num_verts);
2315 meshvertices += numverts;
2316 meshtriangles += BigLong(dpmmesh->num_tris);
2320 loadmodel->numframes = pheader->num_frames;
2321 loadmodel->num_bones = pheader->num_bones;
2322 loadmodel->num_poses = loadmodel->numframes;
2323 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
2324 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2325 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2326 // do most allocations as one merged chunk
2327 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) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[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));
2328 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2329 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2330 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2331 loadmodel->surfmesh.num_vertices = meshvertices;
2332 loadmodel->surfmesh.num_triangles = meshtriangles;
2333 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2334 if (r_enableshadowvolumes.integer)
2336 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2338 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2339 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2340 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2341 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2342 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2343 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2344 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2345 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2346 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2347 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2348 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2349 loadmodel->surfmesh.num_blends = 0;
2350 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2351 if (meshvertices <= 65536)
2353 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2355 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2356 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2358 for (i = 0;i < loadmodel->numskins;i++)
2360 loadmodel->skinscenes[i].firstframe = i;
2361 loadmodel->skinscenes[i].framecount = 1;
2362 loadmodel->skinscenes[i].loop = true;
2363 loadmodel->skinscenes[i].framerate = 10;
2366 // load the bone info
2367 bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2368 for (i = 0;i < loadmodel->num_bones;i++)
2370 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2371 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2372 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2373 if (loadmodel->data_bones[i].parent >= i)
2374 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2378 frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2379 // figure out scale of model from root bone, for compatibility with old dpmodel versions
2380 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2381 tempvec[0] = BigFloat(poses[0]);
2382 tempvec[1] = BigFloat(poses[1]);
2383 tempvec[2] = BigFloat(poses[2]);
2384 modelscale = VectorLength(tempvec);
2386 for (i = 0;i < loadmodel->numframes;i++)
2388 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2389 loadmodel->animscenes[i].firstframe = i;
2390 loadmodel->animscenes[i].framecount = 1;
2391 loadmodel->animscenes[i].loop = true;
2392 loadmodel->animscenes[i].framerate = 10;
2393 // load the bone poses for this frame
2394 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2395 for (j = 0;j < loadmodel->num_bones*12;j++)
2397 f = fabs(BigFloat(poses[j]));
2398 biggestorigin = max(biggestorigin, f);
2400 // stuff not processed here: mins, maxs, yawradius, allradius
2402 loadmodel->num_posescale = biggestorigin / 32767.0f;
2403 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2404 for (i = 0;i < loadmodel->numframes;i++)
2406 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2407 for (j = 0;j < loadmodel->num_bones;j++)
2410 matrix4x4_t posematrix;
2411 for (k = 0;k < 12;k++)
2412 pose[k] = BigFloat(frameposes[j*12+k]);
2413 // scale child bones to match the root scale
2414 if (loadmodel->data_bones[j].parent >= 0)
2416 pose[3] *= modelscale;
2417 pose[7] *= modelscale;
2418 pose[11] *= modelscale;
2420 // normalize rotation matrix
2421 VectorNormalize(pose + 0);
2422 VectorNormalize(pose + 4);
2423 VectorNormalize(pose + 8);
2424 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2425 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2429 // load the meshes now
2430 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2433 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2434 // (converting from weight-blending skeletal animation to
2435 // deformation-based skeletal animation)
2436 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2437 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2438 for (i = 0;i < loadmodel->num_bones;i++)
2441 for (k = 0;k < 12;k++)
2442 m[k] = BigFloat(poses[i*12+k]);
2443 if (loadmodel->data_bones[i].parent >= 0)
2444 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2446 for (k = 0;k < 12;k++)
2447 bonepose[12*i+k] = m[k];
2449 for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2451 const int *inelements;
2453 const float *intexcoord;
2454 msurface_t *surface;
2456 loadmodel->sortedmodelsurfaces[i] = i;
2457 surface = loadmodel->data_surfaces + i;
2458 surface->texture = loadmodel->data_textures + i;
2459 surface->num_firsttriangle = meshtriangles;
2460 surface->num_triangles = BigLong(dpmmesh->num_tris);
2461 surface->num_firstvertex = meshvertices;
2462 surface->num_vertices = BigLong(dpmmesh->num_verts);
2463 meshvertices += surface->num_vertices;
2464 meshtriangles += surface->num_triangles;
2466 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2467 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2468 for (j = 0;j < surface->num_triangles;j++)
2470 // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2471 outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
2472 outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
2473 outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
2478 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2479 for (j = 0;j < surface->num_vertices*2;j++)
2480 loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2482 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2483 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2485 int weightindex[4] = { 0, 0, 0, 0 };
2486 float weightinfluence[4] = { 0, 0, 0, 0 };
2488 int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2489 data += sizeof(dpmvertex_t);
2490 for (k = 0;k < numweights;k++)
2492 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2493 int boneindex = BigLong(vert->bonenum);
2494 const float *m = bonepose + 12 * boneindex;
2495 float influence = BigFloat(vert->influence);
2496 float relativeorigin[3], relativenormal[3];
2497 relativeorigin[0] = BigFloat(vert->origin[0]);
2498 relativeorigin[1] = BigFloat(vert->origin[1]);
2499 relativeorigin[2] = BigFloat(vert->origin[2]);
2500 relativenormal[0] = BigFloat(vert->normal[0]);
2501 relativenormal[1] = BigFloat(vert->normal[1]);
2502 relativenormal[2] = BigFloat(vert->normal[2]);
2503 // blend the vertex bone weights into the base mesh
2504 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2505 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2506 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2507 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2508 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2509 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2512 // store the first (and often only) weight
2513 weightinfluence[0] = influence;
2514 weightindex[0] = boneindex;
2518 // sort the new weight into this vertex's weight table
2519 // (which only accepts up to 4 bones per vertex)
2520 for (l = 0;l < 4;l++)
2522 if (weightinfluence[l] < influence)
2524 // move weaker influence weights out of the way first
2526 for (l2 = 3;l2 > l;l2--)
2528 weightinfluence[l2] = weightinfluence[l2-1];
2529 weightindex[l2] = weightindex[l2-1];
2531 // store the new weight
2532 weightinfluence[l] = influence;
2533 weightindex[l] = boneindex;
2538 data += sizeof(dpmbonevert_t);
2540 loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2541 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = weightindex[0];
2542 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2543 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2544 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2545 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
2546 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2547 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2548 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2551 // since dpm models do not have named sections, reuse their shader name as the section name
2552 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2554 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2556 if (loadmodel->surfmesh.num_blends < meshvertices)
2557 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2559 Mod_FreeSkinFiles(skinfiles);
2560 Mod_MakeSortedSurfaces(loadmodel);
2562 // compute all the mesh information that was not loaded from the file
2563 if (loadmodel->surfmesh.data_element3s)
2564 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2565 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2566 Mod_BuildBaseBonePoses();
2567 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);
2568 if (loadmodel->surfmesh.data_neighbor3i)
2569 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2570 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2571 if(mod_alias_force_animated.string[0])
2572 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2574 if (!loadmodel->surfmesh.isanimated)
2576 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2577 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2578 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2579 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2580 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2581 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2584 // because shaders can do somewhat unexpected things, check for unusual features now
2585 for (i = 0;i < loadmodel->num_textures;i++)
2587 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2588 mod->DrawSky = R_Q1BSP_DrawSky;
2589 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2590 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2594 // no idea why PSK/PSA files contain weird quaternions but they do...
2595 #define PSKQUATNEGATIONS
2596 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2598 int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2599 int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2600 fs_offset_t filesize;
2605 pskboneinfo_t *bones;
2606 pskrawweights_t *rawweights;
2607 //pskboneinfo_t *animbones;
2608 pskaniminfo_t *anims;
2609 pskanimkeys_t *animkeys;
2610 void *animfilebuffer, *animbuffer, *animbufferend;
2611 unsigned char *data;
2613 skinfile_t *skinfiles;
2614 char animname[MAX_QPATH];
2616 float biggestorigin;
2618 pchunk = (pskchunk_t *)buffer;
2619 if (strcmp(pchunk->id, "ACTRHEAD"))
2620 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2622 loadmodel->modeldatatypestring = "PSK";
2624 loadmodel->type = mod_alias;
2625 loadmodel->DrawSky = NULL;
2626 loadmodel->DrawAddWaterPlanes = NULL;
2627 loadmodel->Draw = R_Q1BSP_Draw;
2628 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2629 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2630 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2631 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2632 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2633 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2634 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2635 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2636 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2637 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2638 loadmodel->PointSuperContents = NULL;
2639 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2640 loadmodel->synctype = ST_RAND;
2642 FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2643 strlcat(animname, ".psa", sizeof(animname));
2644 animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2645 animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2647 animbufferend = animbuffer;
2666 while (buffer < bufferend)
2668 pchunk = (pskchunk_t *)buffer;
2669 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2670 version = LittleLong(pchunk->version);
2671 recordsize = LittleLong(pchunk->recordsize);
2672 numrecords = LittleLong(pchunk->numrecords);
2673 if (developer_extra.integer)
2674 Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2675 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2676 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);
2677 if (!strcmp(pchunk->id, "ACTRHEAD"))
2681 else if (!strcmp(pchunk->id, "PNTS0000"))
2684 if (recordsize != sizeof(*p))
2685 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2686 // byteswap in place and keep the pointer
2687 numpnts = numrecords;
2688 pnts = (pskpnts_t *)buffer;
2689 for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2691 p->origin[0] = LittleFloat(p->origin[0]);
2692 p->origin[1] = LittleFloat(p->origin[1]);
2693 p->origin[2] = LittleFloat(p->origin[2]);
2697 else if (!strcmp(pchunk->id, "VTXW0000"))
2700 if (recordsize != sizeof(*p))
2701 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2702 // byteswap in place and keep the pointer
2703 numvtxw = numrecords;
2704 vtxw = (pskvtxw_t *)buffer;
2705 for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2707 p->pntsindex = LittleShort(p->pntsindex);
2708 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2709 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2710 if (p->pntsindex >= numpnts)
2712 Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2718 else if (!strcmp(pchunk->id, "FACE0000"))
2721 if (recordsize != sizeof(*p))
2722 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2723 // byteswap in place and keep the pointer
2724 numfaces = numrecords;
2725 faces = (pskface_t *)buffer;
2726 for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2728 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2729 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2730 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2731 p->group = LittleLong(p->group);
2732 if (p->vtxwindex[0] >= numvtxw)
2734 Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2735 p->vtxwindex[0] = 0;
2737 if (p->vtxwindex[1] >= numvtxw)
2739 Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2740 p->vtxwindex[1] = 0;
2742 if (p->vtxwindex[2] >= numvtxw)
2744 Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2745 p->vtxwindex[2] = 0;
2750 else if (!strcmp(pchunk->id, "MATT0000"))
2753 if (recordsize != sizeof(*p))
2754 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2755 // byteswap in place and keep the pointer
2756 nummatts = numrecords;
2757 matts = (pskmatt_t *)buffer;
2758 for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2764 else if (!strcmp(pchunk->id, "REFSKELT"))
2767 if (recordsize != sizeof(*p))
2768 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2769 // byteswap in place and keep the pointer
2770 numbones = numrecords;
2771 bones = (pskboneinfo_t *)buffer;
2772 for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2774 p->numchildren = LittleLong(p->numchildren);
2775 p->parent = LittleLong(p->parent);
2776 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2777 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2778 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2779 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2780 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2781 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2782 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2783 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2784 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2785 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2786 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2787 #ifdef PSKQUATNEGATIONS
2790 p->basepose.quat[0] *= -1;
2791 p->basepose.quat[1] *= -1;
2792 p->basepose.quat[2] *= -1;
2796 p->basepose.quat[0] *= 1;
2797 p->basepose.quat[1] *= -1;
2798 p->basepose.quat[2] *= 1;
2801 if (p->parent < 0 || p->parent >= numbones)
2803 Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2809 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2812 if (recordsize != sizeof(*p))
2813 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2814 // byteswap in place and keep the pointer
2815 numrawweights = numrecords;
2816 rawweights = (pskrawweights_t *)buffer;
2817 for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2819 p->weight = LittleFloat(p->weight);
2820 p->pntsindex = LittleLong(p->pntsindex);
2821 p->boneindex = LittleLong(p->boneindex);
2822 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2824 Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2827 if (p->boneindex < 0 || p->boneindex >= numbones)
2829 Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2837 while (animbuffer < animbufferend)
2839 pchunk = (pskchunk_t *)animbuffer;
2840 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2841 version = LittleLong(pchunk->version);
2842 recordsize = LittleLong(pchunk->recordsize);
2843 numrecords = LittleLong(pchunk->numrecords);
2844 if (developer_extra.integer)
2845 Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2846 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2847 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);
2848 if (!strcmp(pchunk->id, "ANIMHEAD"))
2852 else if (!strcmp(pchunk->id, "BONENAMES"))
2855 if (recordsize != sizeof(*p))
2856 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2857 // byteswap in place and keep the pointer
2858 numanimbones = numrecords;
2859 //animbones = (pskboneinfo_t *)animbuffer;
2860 // NOTE: supposedly psa does not need to match the psk model, the
2861 // bones missing from the psa would simply use their base
2862 // positions from the psk, but this is hard for me to implement
2863 // and people can easily make animations that match.
2864 if (numanimbones != numbones)
2865 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2866 for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2868 p->numchildren = LittleLong(p->numchildren);
2869 p->parent = LittleLong(p->parent);
2870 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2871 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2872 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2873 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2874 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2875 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2876 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2877 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2878 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2879 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2880 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2881 #ifdef PSKQUATNEGATIONS
2884 p->basepose.quat[0] *= -1;
2885 p->basepose.quat[1] *= -1;
2886 p->basepose.quat[2] *= -1;
2890 p->basepose.quat[0] *= 1;
2891 p->basepose.quat[1] *= -1;
2892 p->basepose.quat[2] *= 1;
2895 if (p->parent < 0 || p->parent >= numanimbones)
2897 Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2900 // check that bones are the same as in the base
2901 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2902 Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2906 else if (!strcmp(pchunk->id, "ANIMINFO"))
2909 if (recordsize != sizeof(*p))
2910 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2911 // byteswap in place and keep the pointer
2912 numanims = numrecords;
2913 anims = (pskaniminfo_t *)animbuffer;
2914 for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2916 p->numbones = LittleLong(p->numbones);
2917 p->playtime = LittleFloat(p->playtime);
2918 p->fps = LittleFloat(p->fps);
2919 p->firstframe = LittleLong(p->firstframe);
2920 p->numframes = LittleLong(p->numframes);
2921 if (p->numbones != numbones)
2922 Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2926 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2929 if (recordsize != sizeof(*p))
2930 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2931 numanimkeys = numrecords;
2932 animkeys = (pskanimkeys_t *)animbuffer;
2933 for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2935 p->origin[0] = LittleFloat(p->origin[0]);
2936 p->origin[1] = LittleFloat(p->origin[1]);
2937 p->origin[2] = LittleFloat(p->origin[2]);
2938 p->quat[0] = LittleFloat(p->quat[0]);
2939 p->quat[1] = LittleFloat(p->quat[1]);
2940 p->quat[2] = LittleFloat(p->quat[2]);
2941 p->quat[3] = LittleFloat(p->quat[3]);
2942 p->frametime = LittleFloat(p->frametime);
2943 #ifdef PSKQUATNEGATIONS
2944 if (index % numbones)
2959 // TODO: allocate bonepose stuff
2962 Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2965 if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2966 Host_Error("%s: missing required chunks", loadmodel->name);
2970 loadmodel->numframes = 0;
2971 for (index = 0;index < numanims;index++)
2972 loadmodel->numframes += anims[index].numframes;
2973 if (numanimkeys != numbones * loadmodel->numframes)
2974 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2977 loadmodel->numframes = loadmodel->num_poses = 1;
2979 meshvertices = numvtxw;
2980 meshtriangles = numfaces;
2982 // load external .skin files if present
2983 skinfiles = Mod_LoadSkinFiles();
2984 if (loadmodel->numskins < 1)
2985 loadmodel->numskins = 1;
2986 loadmodel->num_bones = numbones;
2987 loadmodel->num_poses = loadmodel->numframes;
2988 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2989 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2990 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2991 loadmodel->surfmesh.num_vertices = meshvertices;
2992 loadmodel->surfmesh.num_triangles = meshtriangles;
2993 // do most allocations as one merged chunk
2994 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]) + (r_enableshadowvolumes.integer ? loadmodel->surfmesh.num_triangles * sizeof(int[3]) : 0) + 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);
2995 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2996 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2997 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2998 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2999 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
3000 if (r_enableshadowvolumes.integer)
3002 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
3004 loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3005 loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3006 loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3007 loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3008 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3009 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3010 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3011 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3012 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3013 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3014 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3015 loadmodel->surfmesh.num_blends = 0;
3016 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3017 if (loadmodel->surfmesh.num_vertices <= 65536)
3019 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
3021 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3022 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
3024 for (i = 0;i < loadmodel->numskins;i++)
3026 loadmodel->skinscenes[i].firstframe = i;
3027 loadmodel->skinscenes[i].framecount = 1;
3028 loadmodel->skinscenes[i].loop = true;
3029 loadmodel->skinscenes[i].framerate = 10;
3033 for (index = 0, i = 0;index < nummatts;index++)
3035 // since psk models do not have named sections, reuse their shader name as the section name
3036 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
3037 loadmodel->sortedmodelsurfaces[index] = index;
3038 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
3039 loadmodel->data_surfaces[index].num_firstvertex = 0;
3040 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
3043 // copy over the vertex locations and texcoords
3044 for (index = 0;index < numvtxw;index++)
3046 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
3047 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
3048 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
3049 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
3050 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
3053 // loading the faces is complicated because we need to sort them into surfaces by mattindex
3054 for (index = 0;index < numfaces;index++)
3055 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
3056 for (index = 0, i = 0;index < nummatts;index++)
3058 loadmodel->data_surfaces[index].num_firsttriangle = i;
3059 i += loadmodel->data_surfaces[index].num_triangles;
3060 loadmodel->data_surfaces[index].num_triangles = 0;
3062 for (index = 0;index < numfaces;index++)
3064 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
3065 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
3066 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
3067 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
3070 // copy over the bones
3071 for (index = 0;index < numbones;index++)
3073 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
3074 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
3075 if (loadmodel->data_bones[index].parent >= index)
3076 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
3079 // convert the basepose data
3080 if (loadmodel->num_bones)
3083 matrix4x4_t *basebonepose;
3084 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
3085 matrix4x4_t bonematrix;
3086 matrix4x4_t tempbonematrix;
3087 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
3088 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
3090 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]);
3091 if (loadmodel->data_bones[boneindex].parent >= 0)
3093 tempbonematrix = bonematrix;
3094 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3096 basebonepose[boneindex] = bonematrix;
3097 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3098 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3100 Mem_Free(basebonepose);
3103 // sort the psk point weights into the vertex weight tables
3104 // (which only accept up to 4 bones per vertex)
3105 for (index = 0;index < numvtxw;index++)
3107 int weightindex[4] = { 0, 0, 0, 0 };
3108 float weightinfluence[4] = { 0, 0, 0, 0 };
3110 for (j = 0;j < numrawweights;j++)
3112 if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3114 int boneindex = rawweights[j].boneindex;
3115 float influence = rawweights[j].weight;
3116 for (l = 0;l < 4;l++)
3118 if (weightinfluence[l] < influence)
3120 // move lower influence weights out of the way first
3122 for (l2 = 3;l2 > l;l2--)
3124 weightinfluence[l2] = weightinfluence[l2-1];
3125 weightindex[l2] = weightindex[l2-1];
3127 // store the new weight
3128 weightinfluence[l] = influence;
3129 weightindex[l] = boneindex;
3135 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3136 loadmodel->surfmesh.data_skeletalindex4ub[index*4 ] = weightindex[0];
3137 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3138 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3139 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3140 loadmodel->surfmesh.data_skeletalweight4ub[index*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
3141 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3142 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3143 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3145 if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3146 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3148 // set up the animscenes based on the anims
3151 for (index = 0, i = 0;index < numanims;index++)
3153 for (j = 0;j < anims[index].numframes;j++, i++)
3155 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3156 loadmodel->animscenes[i].firstframe = i;
3157 loadmodel->animscenes[i].framecount = 1;
3158 loadmodel->animscenes[i].loop = true;
3159 loadmodel->animscenes[i].framerate = anims[index].fps;
3162 // calculate the scaling value for bone origins so they can be compressed to short
3164 for (index = 0;index < numanimkeys;index++)
3166 pskanimkeys_t *k = animkeys + index;
3167 biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3168 biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3169 biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3171 loadmodel->num_posescale = biggestorigin / 32767.0f;
3172 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3174 // load the poses from the animkeys
3175 for (index = 0;index < numanimkeys;index++)
3177 pskanimkeys_t *k = animkeys + index;
3179 Vector4Copy(k->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] = k->origin[0] * loadmodel->num_poseinvscale;
3185 loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3186 loadmodel->data_poses7s[index*7+2] = k->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;
3195 strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3196 loadmodel->animscenes[0].firstframe = 0;
3197 loadmodel->animscenes[0].framecount = 1;
3198 loadmodel->animscenes[0].loop = true;
3199 loadmodel->animscenes[0].framerate = 10;
3201 // calculate the scaling value for bone origins so they can be compressed to short
3203 for (index = 0;index < numbones;index++)
3205 pskboneinfo_t *p = bones + index;
3206 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3207 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3208 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3210 loadmodel->num_posescale = biggestorigin / 32767.0f;
3211 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3213 // load the basepose as a frame
3214 for (index = 0;index < numbones;index++)
3216 pskboneinfo_t *p = bones + index;
3218 Vector4Copy(p->basepose.quat, quat);
3220 Vector4Negate(quat, quat);
3221 Vector4Normalize2(quat, quat);
3222 // compress poses to the short[7] format for longterm storage
3223 loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3224 loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3225 loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3226 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3227 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3228 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3229 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3233 Mod_FreeSkinFiles(skinfiles);
3235 Mem_Free(animfilebuffer);
3236 Mod_MakeSortedSurfaces(loadmodel);
3238 // compute all the mesh information that was not loaded from the file
3239 // TODO: honor smoothing groups somehow?
3240 if (loadmodel->surfmesh.data_element3s)
3241 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3242 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3243 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3244 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);
3245 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);
3246 if (loadmodel->surfmesh.data_neighbor3i)
3247 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
3248 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3249 if(mod_alias_force_animated.string[0])
3250 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3252 if (!loadmodel->surfmesh.isanimated)
3254 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3255 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3256 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3257 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3258 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3259 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3262 // because shaders can do somewhat unexpected things, check for unusual features now
3263 for (i = 0;i < loadmodel->num_textures;i++)
3265 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3266 mod->DrawSky = R_Q1BSP_DrawSky;
3267 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3268 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
3272 void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
3274 unsigned char *data;
3276 const unsigned char *pbase, *pend;
3278 skinfile_t *skinfiles;
3279 int i, j, k, meshvertices, meshtriangles;
3280 float biggestorigin;
3281 const unsigned int *inelements;
3283 const int *inneighbors;
3285 float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3286 // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3287 const float *vnormal = NULL;
3288 const float *vposition = NULL;
3289 const float *vtangent = NULL;
3290 const float *vtexcoord = NULL;
3291 const float *vcolor4f = NULL;
3292 const unsigned char *vblendindexes = NULL;
3293 const unsigned char *vblendweights = NULL;
3294 const unsigned char *vcolor4ub = NULL;
3295 const unsigned short *framedata = NULL;
3296 // temporary memory allocations (because the data in the file may be misaligned)
3297 iqmanim_t *anims = NULL;
3298 iqmbounds_t *bounds = NULL;
3299 iqmjoint1_t *joint1 = NULL;
3300 iqmjoint_t *joint = NULL;
3301 iqmmesh_t *meshes = NULL;
3302 iqmpose1_t *pose1 = NULL;
3303 iqmpose_t *pose = NULL;
3304 iqmvertexarray_t *vas = NULL;
3306 pbase = (unsigned char *)buffer;
3307 pend = (unsigned char *)bufferend;
3309 if (pbase + sizeof(iqmheader_t) > pend)
3310 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3312 // copy struct (otherwise it may be misaligned)
3313 // LordHavoc: okay it's definitely not misaligned here, but for consistency...
3314 memcpy(&header, pbase, sizeof(iqmheader_t));
3316 if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3317 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3318 if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3319 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3321 loadmodel->modeldatatypestring = "IQM";
3323 loadmodel->type = mod_alias;
3324 loadmodel->synctype = ST_RAND;
3327 header.version = LittleLong(header.version);
3328 header.filesize = LittleLong(header.filesize);
3329 header.flags = LittleLong(header.flags);
3330 header.num_text = LittleLong(header.num_text);
3331 header.ofs_text = LittleLong(header.ofs_text);
3332 header.num_meshes = LittleLong(header.num_meshes);
3333 header.ofs_meshes = LittleLong(header.ofs_meshes);
3334 header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3335 header.num_vertexes = LittleLong(header.num_vertexes);
3336 header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3337 header.num_triangles = LittleLong(header.num_triangles);
3338 header.ofs_triangles = LittleLong(header.ofs_triangles);
3339 header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3340 header.num_joints = LittleLong(header.num_joints);
3341 header.ofs_joints = LittleLong(header.ofs_joints);
3342 header.num_poses = LittleLong(header.num_poses);
3343 header.ofs_poses = LittleLong(header.ofs_poses);
3344 header.num_anims = LittleLong(header.num_anims);
3345 header.ofs_anims = LittleLong(header.ofs_anims);
3346 header.num_frames = LittleLong(header.num_frames);
3347 header.num_framechannels = LittleLong(header.num_framechannels);
3348 header.ofs_frames = LittleLong(header.ofs_frames);
3349 header.ofs_bounds = LittleLong(header.ofs_bounds);
3350 header.num_comment = LittleLong(header.num_comment);
3351 header.ofs_comment = LittleLong(header.ofs_comment);
3352 header.num_extensions = LittleLong(header.num_extensions);
3353 header.ofs_extensions = LittleLong(header.ofs_extensions);
3355 if (header.version == 1)
3357 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3358 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3360 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3366 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3367 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3369 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3373 if (pbase + header.ofs_text + header.num_text > pend ||
3374 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3375 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3376 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3377 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3378 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3379 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3380 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3381 pbase + header.ofs_comment + header.num_comment > pend)
3383 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3387 // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3388 if (header.num_vertexarrays)
3389 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3390 if (header.num_anims)
3391 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3392 if (header.ofs_bounds)
3393 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3394 if (header.num_meshes)
3395 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3397 for (i = 0;i < (int)header.num_vertexarrays;i++)
3399 iqmvertexarray_t va;
3401 va.type = LittleLong(vas[i].type);
3402 va.flags = LittleLong(vas[i].flags);
3403 va.format = LittleLong(vas[i].format);
3404 va.size = LittleLong(vas[i].size);
3405 va.offset = LittleLong(vas[i].offset);
3406 vsize = header.num_vertexes*va.size;
3409 case IQM_FLOAT: vsize *= sizeof(float); break;
3410 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3413 if (pbase + va.offset + vsize > pend)
3415 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3419 if (va.format == IQM_FLOAT && va.size == 3)
3420 vposition = (const float *)(pbase + va.offset);
3423 if (va.format == IQM_FLOAT && va.size == 2)
3424 vtexcoord = (const float *)(pbase + va.offset);
3427 if (va.format == IQM_FLOAT && va.size == 3)
3428 vnormal = (const float *)(pbase + va.offset);
3431 if (va.format == IQM_FLOAT && va.size == 4)
3432 vtangent = (const float *)(pbase + va.offset);
3434 case IQM_BLENDINDEXES:
3435 if (va.format == IQM_UBYTE && va.size == 4)
3436 vblendindexes = (const unsigned char *)(pbase + va.offset);
3438 case IQM_BLENDWEIGHTS:
3439 if (va.format == IQM_UBYTE && va.size == 4)
3440 vblendweights = (const unsigned char *)(pbase + va.offset);
3443 if (va.format == IQM_FLOAT && va.size == 4)
3444 vcolor4f = (const float *)(pbase + va.offset);
3445 if (va.format == IQM_UBYTE && va.size == 4)
3446 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3450 if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3452 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3456 text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3458 loadmodel->DrawSky = NULL;
3459 loadmodel->DrawAddWaterPlanes = NULL;
3460 loadmodel->Draw = R_Q1BSP_Draw;
3461 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
3462 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
3463 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
3464 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
3465 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
3466 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
3467 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
3468 loadmodel->DrawLight = R_Q1BSP_DrawLight;
3469 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3470 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3471 loadmodel->PointSuperContents = NULL;
3472 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3474 // load external .skin files if present
3475 skinfiles = Mod_LoadSkinFiles();
3476 if (loadmodel->numskins < 1)
3477 loadmodel->numskins = 1;
3479 loadmodel->numframes = max(header.num_anims, 1);
3480 loadmodel->num_bones = header.num_joints;
3481 loadmodel->num_poses = max(header.num_frames, 1);
3482 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header.num_meshes;
3483 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3484 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3486 meshvertices = header.num_vertexes;
3487 meshtriangles = header.num_triangles;
3489 // do most allocations as one merged chunk
3490 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) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[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));
3491 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3492 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3493 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3494 loadmodel->surfmesh.num_vertices = meshvertices;
3495 loadmodel->surfmesh.num_triangles = meshtriangles;
3496 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3497 if (r_enableshadowvolumes.integer)
3499 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3501 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3502 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3503 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3504 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3505 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3506 if (vcolor4f || vcolor4ub)
3508 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]);
3510 if (vblendindexes && vblendweights)
3512 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3513 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3515 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3516 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3517 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3518 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3519 if (vblendindexes && vblendweights)
3521 loadmodel->surfmesh.num_blends = 0;
3522 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3524 if (meshvertices <= 65536)
3526 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3528 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3529 if (vblendindexes && vblendweights)
3530 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3532 for (i = 0;i < loadmodel->numskins;i++)
3534 loadmodel->skinscenes[i].firstframe = i;
3535 loadmodel->skinscenes[i].framecount = 1;
3536 loadmodel->skinscenes[i].loop = true;
3537 loadmodel->skinscenes[i].framerate = 10;
3540 // load the bone info
3541 if (header.version == 1)
3543 iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3544 if (loadmodel->num_bones)
3545 joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3546 for (i = 0;i < loadmodel->num_bones;i++)
3548 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3549 joint1[i].name = LittleLong(injoint1[i].name);
3550 joint1[i].parent = LittleLong(injoint1[i].parent);
3551 for (j = 0;j < 3;j++)
3553 joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
3554 joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
3555 joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
3557 strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3558 loadmodel->data_bones[i].parent = joint1[i].parent;
3559 if (loadmodel->data_bones[i].parent >= i)
3560 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3561 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]);
3562 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3563 if (loadmodel->data_bones[i].parent >= 0)
3565 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3566 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3567 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3569 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3574 iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
3575 if (header.num_joints)
3576 joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3577 for (i = 0;i < loadmodel->num_bones;i++)
3579 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3580 joint[i].name = LittleLong(injoint[i].name);
3581 joint[i].parent = LittleLong(injoint[i].parent);
3582 for (j = 0;j < 3;j++)
3584 joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
3585 joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
3586 joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
3588 joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
3589 strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3590 loadmodel->data_bones[i].parent = joint[i].parent;
3591 if (loadmodel->data_bones[i].parent >= i)
3592 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3593 if (joint[i].rotation[3] > 0)
3594 Vector4Negate(joint[i].rotation, joint[i].rotation);
3595 Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3596 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]);
3597 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3598 if (loadmodel->data_bones[i].parent >= 0)
3600 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3601 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3602 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3604 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3608 // set up the animscenes based on the anims
3609 for (i = 0;i < (int)header.num_anims;i++)
3612 anim.name = LittleLong(anims[i].name);
3613 anim.first_frame = LittleLong(anims[i].first_frame);
3614 anim.num_frames = LittleLong(anims[i].num_frames);
3615 anim.framerate = LittleFloat(anims[i].framerate);
3616 anim.flags = LittleLong(anims[i].flags);
3617 strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3618 loadmodel->animscenes[i].firstframe = anim.first_frame;
3619 loadmodel->animscenes[i].framecount = anim.num_frames;
3620 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3621 loadmodel->animscenes[i].framerate = anim.framerate;
3623 if (header.num_anims <= 0)
3625 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3626 loadmodel->animscenes[0].firstframe = 0;
3627 loadmodel->animscenes[0].framecount = 1;
3628 loadmodel->animscenes[0].loop = true;
3629 loadmodel->animscenes[0].framerate = 10;
3632 loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3633 if(mod_alias_force_animated.string[0])
3634 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3637 if (header.version == 1)
3639 iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3640 if (header.num_poses)
3641 pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3642 for (i = 0;i < (int)header.num_poses;i++)
3645 pose1[i].parent = LittleLong(inpose1[i].parent);
3646 pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
3647 for (j = 0;j < 9;j++)
3649 pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
3650 pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
3652 f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3653 f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3654 f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3655 f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3656 f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3657 f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3659 if (header.num_frames <= 0)
3661 for (i = 0;i < loadmodel->num_bones;i++)
3664 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3665 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3666 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3672 iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
3673 if (header.num_poses)
3674 pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3675 for (i = 0;i < (int)header.num_poses;i++)
3678 pose[i].parent = LittleLong(inpose[i].parent);
3679 pose[i].channelmask = LittleLong(inpose[i].channelmask);
3680 for (j = 0;j < 10;j++)
3682 pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
3683 pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
3685 f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3686 f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3687 f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3688 f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3689 f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3690 f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3692 if (header.num_frames <= 0)
3694 for (i = 0;i < loadmodel->num_bones;i++)
3697 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3698 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3699 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3703 loadmodel->num_posescale = biggestorigin / 32767.0f;
3704 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3706 // load the pose data
3707 // this unaligned memory access is safe (LittleShort reads as bytes)
3708 framedata = (const unsigned short *)(pbase + header.ofs_frames);
3709 if (header.version == 1)
3711 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3713 for (j = 0;j < (int)header.num_poses;j++, k++)
3715 float qx, qy, qz, qw;
3716 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));
3717 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));
3718 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));
3719 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3720 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3721 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3722 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3723 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3724 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3725 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3726 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3727 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3728 // skip scale data for now
3729 if(pose1[j].channelmask&64) framedata++;
3730 if(pose1[j].channelmask&128) framedata++;
3731 if(pose1[j].channelmask&256) framedata++;
3734 if (header.num_frames <= 0)
3736 for (i = 0;i < loadmodel->num_bones;i++)
3738 float qx, qy, qz, qw;
3739 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3740 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3741 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3742 qx = joint1[i].rotation[0];
3743 qy = joint1[i].rotation[1];
3744 qz = joint1[i].rotation[2];
3745 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3746 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3747 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3748 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3749 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3750 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3756 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3758 for (j = 0;j < (int)header.num_poses;j++, k++)
3761 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));
3762 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));
3763 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));
3764 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3765 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3766 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3767 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3769 Vector4Negate(rot, rot);
3770 Vector4Normalize2(rot, rot);
3771 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3772 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3773 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3774 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3775 // skip scale data for now
3776 if(pose[j].channelmask&128) framedata++;
3777 if(pose[j].channelmask&256) framedata++;
3778 if(pose[j].channelmask&512) framedata++;
3781 if (header.num_frames <= 0)
3783 for (i = 0;i < loadmodel->num_bones;i++)
3785 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3786 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3787 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3788 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3789 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3790 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3791 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3796 // load bounding box data
3797 if (header.ofs_bounds)
3799 float xyradius = 0, radius = 0;
3800 VectorClear(loadmodel->normalmins);
3801 VectorClear(loadmodel->normalmaxs);
3802 for (i = 0; i < (int)header.num_frames;i++)
3805 bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3806 bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3807 bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3808 bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);
3809 bound.maxs[1] = LittleFloat(bounds[i].maxs[1]);
3810 bound.maxs[2] = LittleFloat(bounds[i].maxs[2]);
3811 bound.xyradius = LittleFloat(bounds[i].xyradius);
3812 bound.radius = LittleFloat(bounds[i].radius);
3815 VectorCopy(bound.mins, loadmodel->normalmins);
3816 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3820 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3821 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3822 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3823 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3824 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3825 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3827 if (bound.xyradius > xyradius)
3828 xyradius = bound.xyradius;
3829 if (bound.radius > radius)
3830 radius = bound.radius;
3832 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3833 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3834 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3835 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3836 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3837 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3838 loadmodel->radius = radius;
3839 loadmodel->radius2 = radius * radius;
3842 // load triangle data
3843 // this unaligned memory access is safe (LittleLong reads as bytes)
3844 inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3845 outelements = loadmodel->surfmesh.data_element3i;
3846 for (i = 0;i < (int)header.num_triangles;i++)
3848 outelements[0] = LittleLong(inelements[0]);
3849 outelements[1] = LittleLong(inelements[1]);
3850 outelements[2] = LittleLong(inelements[2]);
3854 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3856 if (header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
3858 // this unaligned memory access is safe (LittleLong reads as bytes)
3859 inneighbors = (const int *)(pbase + header.ofs_neighbors);
3860 outneighbors = loadmodel->surfmesh.data_neighbor3i;
3861 for (i = 0;i < (int)header.num_triangles;i++)
3863 outneighbors[0] = LittleLong(inneighbors[0]);
3864 outneighbors[1] = LittleLong(inneighbors[1]);
3865 outneighbors[2] = LittleLong(inneighbors[2]);
3872 // this unaligned memory access is safe (LittleFloat reads as bytes)
3873 outvertex = loadmodel->surfmesh.data_vertex3f;
3874 for (i = 0;i < (int)header.num_vertexes;i++)
3876 outvertex[0] = LittleFloat(vposition[0]);
3877 outvertex[1] = LittleFloat(vposition[1]);
3878 outvertex[2] = LittleFloat(vposition[2]);
3883 outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3884 // this unaligned memory access is safe (LittleFloat reads as bytes)
3885 for (i = 0;i < (int)header.num_vertexes;i++)
3887 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3888 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3893 // this unaligned memory access is safe (LittleFloat reads as bytes)
3896 outnormal = loadmodel->surfmesh.data_normal3f;
3897 for (i = 0;i < (int)header.num_vertexes;i++)
3899 outnormal[0] = LittleFloat(vnormal[0]);
3900 outnormal[1] = LittleFloat(vnormal[1]);
3901 outnormal[2] = LittleFloat(vnormal[2]);
3907 // this unaligned memory access is safe (LittleFloat reads as bytes)
3908 if(vnormal && vtangent)
3910 outnormal = loadmodel->surfmesh.data_normal3f;
3911 outsvector = loadmodel->surfmesh.data_svector3f;
3912 outtvector = loadmodel->surfmesh.data_tvector3f;
3913 for (i = 0;i < (int)header.num_vertexes;i++)
3915 outsvector[0] = LittleFloat(vtangent[0]);
3916 outsvector[1] = LittleFloat(vtangent[1]);
3917 outsvector[2] = LittleFloat(vtangent[2]);
3918 if(LittleFloat(vtangent[3]) < 0)
3919 CrossProduct(outsvector, outnormal, outtvector);
3921 CrossProduct(outnormal, outsvector, outtvector);
3929 // this unaligned memory access is safe (all bytes)
3930 if (vblendindexes && vblendweights)
3932 for (i = 0; i < (int)header.num_vertexes;i++)
3934 blendweights_t weights;
3935 memcpy(weights.index, vblendindexes + i*4, 4);
3936 memcpy(weights.influence, vblendweights + i*4, 4);
3937 loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3938 loadmodel->surfmesh.data_skeletalindex4ub[i*4 ] = weights.index[0];
3939 loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3940 loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3941 loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3942 loadmodel->surfmesh.data_skeletalweight4ub[i*4 ] = weights.influence[0];
3943 loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3944 loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3945 loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3951 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3952 // this unaligned memory access is safe (LittleFloat reads as bytes)
3953 for (i = 0;i < (int)header.num_vertexes;i++)
3955 outcolor[0] = LittleFloat(vcolor4f[0]);
3956 outcolor[1] = LittleFloat(vcolor4f[1]);
3957 outcolor[2] = LittleFloat(vcolor4f[2]);
3958 outcolor[3] = LittleFloat(vcolor4f[3]);
3965 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3966 // this unaligned memory access is safe (all bytes)
3967 for (i = 0;i < (int)header.num_vertexes;i++)
3969 outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3970 outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3971 outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3972 outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3979 for (i = 0;i < (int)header.num_meshes;i++)
3982 msurface_t *surface;
3984 mesh.name = LittleLong(meshes[i].name);
3985 mesh.material = LittleLong(meshes[i].material);
3986 mesh.first_vertex = LittleLong(meshes[i].first_vertex);
3987 mesh.num_vertexes = LittleLong(meshes[i].num_vertexes);
3988 mesh.first_triangle = LittleLong(meshes[i].first_triangle);
3989 mesh.num_triangles = LittleLong(meshes[i].num_triangles);
3991 loadmodel->sortedmodelsurfaces[i] = i;
3992 surface = loadmodel->data_surfaces + i;
3993 surface->texture = loadmodel->data_textures + i;
3994 surface->num_firsttriangle = mesh.first_triangle;
3995 surface->num_triangles = mesh.num_triangles;
3996 surface->num_firstvertex = mesh.first_vertex;
3997 surface->num_vertices = mesh.num_vertexes;
3999 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
4002 Mod_FreeSkinFiles(skinfiles);
4003 Mod_MakeSortedSurfaces(loadmodel);
4005 // compute all the mesh information that was not loaded from the file
4006 if (loadmodel->surfmesh.data_element3s)
4007 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
4008 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
4010 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);
4011 if (!vnormal || !vtangent)
4012 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);
4013 if (!header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
4014 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
4015 if (!header.ofs_bounds)
4016 Mod_Alias_CalculateBoundingBox();
4018 if (!loadmodel->surfmesh.isanimated && loadmodel->surfmesh.num_triangles >= 1)
4020 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
4021 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
4022 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
4023 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
4024 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
4025 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
4028 if (joint ) Mem_Free(joint );joint = NULL;
4029 if (joint1 ) Mem_Free(joint1 );joint1 = NULL;
4030 if (pose ) Mem_Free(pose );pose = NULL;
4031 if (pose1 ) Mem_Free(pose1 );pose1 = NULL;
4033 // because shaders can do somewhat unexpected things, check for unusual features now
4034 for (i = 0;i < loadmodel->num_textures;i++)
4036 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
4037 mod->DrawSky = R_Q1BSP_DrawSky;
4038 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
4039 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;