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, int skipsupercontentsmask)
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 trace->skipsupercontentsmask = skipsupercontentsmask;
766 if (model->surfmesh.num_vertices > 1024)
767 vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
768 segmentmins[0] = min(start[0], end[0]) - 1;
769 segmentmins[1] = min(start[1], end[1]) - 1;
770 segmentmins[2] = min(start[2], end[2]) - 1;
771 segmentmaxs[0] = max(start[0], end[0]) + 1;
772 segmentmaxs[1] = max(start[1], end[1]) + 1;
773 segmentmaxs[2] = max(start[2], end[2]) + 1;
774 model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
775 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
776 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);
777 if (vertex3f != vertex3fbuf)
781 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, int skipsupercontentsmask)
784 vec3_t shiftstart, shiftend;
785 float segmentmins[3], segmentmaxs[3];
787 float vertex3fbuf[1024*3];
788 float *vertex3f = vertex3fbuf;
789 colboxbrushf_t thisbrush_start, thisbrush_end;
790 vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
792 if (VectorCompare(boxmins, boxmaxs))
794 VectorAdd(start, boxmins, shiftstart);
795 VectorAdd(end, boxmins, shiftend);
796 Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask, skipsupercontentsmask);
797 VectorSubtract(trace->endpos, boxmins, trace->endpos);
801 // box trace, performed as brush trace
802 memset(trace, 0, sizeof(*trace));
804 trace->hitsupercontentsmask = hitsupercontentsmask;
805 trace->skipsupercontentsmask = skipsupercontentsmask;
806 if (model->surfmesh.num_vertices > 1024)
807 vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
808 segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1;
809 segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1;
810 segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1;
811 segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1;
812 segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1;
813 segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1;
814 VectorAdd(start, boxmins, boxstartmins);
815 VectorAdd(start, boxmaxs, boxstartmaxs);
816 VectorAdd(end, boxmins, boxendmins);
817 VectorAdd(end, boxmaxs, boxendmaxs);
818 Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL);
819 Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL);
820 model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
821 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
822 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);
823 if (vertex3f != vertex3fbuf)
827 static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap)
830 for (i = 0;i < inverts;i++)
832 if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
834 j = vertremap[i]; // not onseam
837 j = vertremap[i+inverts]; // onseam
843 static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *vertremap)
845 int i, f, pose, groupframes;
847 daliasframetype_t *pframetype;
848 daliasframe_t *pinframe;
849 daliasgroup_t *group;
850 daliasinterval_t *intervals;
853 scene = loadmodel->animscenes;
854 for (f = 0;f < loadmodel->numframes;f++)
856 pframetype = (daliasframetype_t *)datapointer;
857 datapointer += sizeof(daliasframetype_t);
858 if (LittleLong (pframetype->type) == ALIAS_SINGLE)
860 // a single frame is still treated as a group
867 group = (daliasgroup_t *)datapointer;
868 datapointer += sizeof(daliasgroup_t);
869 groupframes = LittleLong (group->numframes);
871 // intervals (time per frame)
872 intervals = (daliasinterval_t *)datapointer;
873 datapointer += sizeof(daliasinterval_t) * groupframes;
875 interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
876 if (interval < 0.01f)
878 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
883 // get scene name from first frame
884 pinframe = (daliasframe_t *)datapointer;
886 strlcpy(scene->name, pinframe->name, sizeof(scene->name));
887 scene->firstframe = pose;
888 scene->framecount = groupframes;
889 scene->framerate = 1.0f / interval;
894 for (i = 0;i < groupframes;i++)
896 datapointer += sizeof(daliasframe_t);
897 Mod_ConvertAliasVerts(inverts, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphmdlvertex + pose * loadmodel->surfmesh.num_vertices, vertremap);
898 datapointer += sizeof(trivertx_t) * inverts;
904 static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *skinframe)
906 if (cls.state == ca_dedicated)
910 skinframe = R_SkinFrame_LoadMissing();
911 memset(texture, 0, sizeof(*texture));
912 texture->currentframe = texture;
913 //texture->animated = false;
914 texture->numskinframes = 1;
915 texture->skinframerate = 1;
916 texture->skinframes[0] = skinframe;
917 texture->currentskinframe = skinframe;
918 //texture->backgroundnumskinframes = 0;
919 //texture->customblendfunc[0] = 0;
920 //texture->customblendfunc[1] = 0;
921 //texture->surfaceflags = 0;
922 //texture->supercontents = 0;
923 //texture->surfaceparms = 0;
924 //texture->textureflags = 0;
926 texture->basematerialflags = MATERIALFLAG_WALL;
927 texture->basealpha = 1.0f;
928 if (texture->currentskinframe->hasalpha)
929 texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
930 texture->currentmaterialflags = texture->basematerialflags;
931 texture->offsetmapping = OFFSETMAPPING_DEFAULT;
932 texture->offsetscale = 1;
933 texture->offsetbias = 0;
934 texture->specularscalemod = 1;
935 texture->specularpowermod = 1;
936 texture->surfaceflags = 0;
937 texture->supercontents = SUPERCONTENTS_SOLID;
938 if (!(texture->basematerialflags & MATERIALFLAG_BLENDED))
939 texture->supercontents |= SUPERCONTENTS_OPAQUE;
940 texture->transparentsort = TRANSPARENTSORT_DISTANCE;
941 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
942 // JUST GREP FOR "specularscalemod = 1".
945 void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
948 char stripbuf[MAX_QPATH];
949 skinfileitem_t *skinfileitem;
950 if(developer_extra.integer)
951 Con_DPrintf("Looking up texture for %s (default: %s)\n", meshname, shadername);
954 // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
955 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
957 memset(skin, 0, sizeof(*skin));
959 for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
961 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
962 if (!strcmp(skinfileitem->name, meshname))
964 Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf));
965 if(developer_extra.integer)
966 Con_DPrintf("--> got %s from skin file\n", stripbuf);
967 Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
973 // don't render unmentioned meshes
974 Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
975 if(developer_extra.integer)
976 Con_DPrintf("--> skipping\n");
977 skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW;
983 if(developer_extra.integer)
984 Con_DPrintf("--> using default\n");
985 Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf));
986 Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
990 #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);
991 #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);
992 void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
994 int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
995 float scales, scalet, interval;
999 stvert_t *pinstverts;
1000 dtriangle_t *pintriangles;
1001 daliasskintype_t *pinskintype;
1002 daliasskingroup_t *pinskingroup;
1003 daliasskininterval_t *pinskinintervals;
1004 daliasframetype_t *pinframetype;
1005 daliasgroup_t *pinframegroup;
1006 unsigned char *datapointer, *startframes, *startskins;
1007 char name[MAX_QPATH];
1008 skinframe_t *tempskinframe;
1009 animscene_t *tempskinscenes;
1010 texture_t *tempaliasskins;
1012 int *vertonseam, *vertremap;
1013 skinfile_t *skinfiles;
1016 datapointer = (unsigned char *)buffer;
1017 pinmodel = (mdl_t *)datapointer;
1018 datapointer += sizeof(mdl_t);
1020 version = LittleLong (pinmodel->version);
1021 if (version != ALIAS_VERSION)
1022 Host_Error ("%s has wrong version number (%i should be %i)",
1023 loadmodel->name, version, ALIAS_VERSION);
1025 loadmodel->modeldatatypestring = "MDL";
1027 loadmodel->type = mod_alias;
1028 loadmodel->DrawSky = NULL;
1029 loadmodel->DrawAddWaterPlanes = NULL;
1030 loadmodel->Draw = R_Q1BSP_Draw;
1031 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1032 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1033 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1034 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1035 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1036 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1037 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1038 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1039 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1040 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1041 // FIXME add TraceBrush!
1042 loadmodel->PointSuperContents = NULL;
1043 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1045 loadmodel->num_surfaces = 1;
1046 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1047 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
1048 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1049 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1050 loadmodel->sortedmodelsurfaces[0] = 0;
1052 loadmodel->numskins = LittleLong(pinmodel->numskins);
1053 BOUNDI(loadmodel->numskins,0,65536);
1054 skinwidth = LittleLong (pinmodel->skinwidth);
1055 BOUNDI(skinwidth,0,65536);
1056 skinheight = LittleLong (pinmodel->skinheight);
1057 BOUNDI(skinheight,0,65536);
1058 numverts = LittleLong(pinmodel->numverts);
1059 BOUNDI(numverts,0,65536);
1060 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
1061 BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
1062 loadmodel->numframes = LittleLong(pinmodel->numframes);
1063 BOUNDI(loadmodel->numframes,0,65536);
1064 loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
1065 BOUNDI((int)loadmodel->synctype,0,2);
1066 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1067 i = LittleLong (pinmodel->flags);
1068 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1070 for (i = 0;i < 3;i++)
1072 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
1073 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
1076 startskins = datapointer;
1078 for (i = 0;i < loadmodel->numskins;i++)
1080 pinskintype = (daliasskintype_t *)datapointer;
1081 datapointer += sizeof(daliasskintype_t);
1082 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
1086 pinskingroup = (daliasskingroup_t *)datapointer;
1087 datapointer += sizeof(daliasskingroup_t);
1088 groupskins = LittleLong(pinskingroup->numskins);
1089 datapointer += sizeof(daliasskininterval_t) * groupskins;
1092 for (j = 0;j < groupskins;j++)
1094 datapointer += skinwidth * skinheight;
1099 pinstverts = (stvert_t *)datapointer;
1100 datapointer += sizeof(stvert_t) * numverts;
1102 pintriangles = (dtriangle_t *)datapointer;
1103 datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
1105 startframes = datapointer;
1106 loadmodel->surfmesh.num_morphframes = 0;
1107 for (i = 0;i < loadmodel->numframes;i++)
1109 pinframetype = (daliasframetype_t *)datapointer;
1110 datapointer += sizeof(daliasframetype_t);
1111 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1115 pinframegroup = (daliasgroup_t *)datapointer;
1116 datapointer += sizeof(daliasgroup_t);
1117 groupframes = LittleLong(pinframegroup->numframes);
1118 datapointer += sizeof(daliasinterval_t) * groupframes;
1121 for (j = 0;j < groupframes;j++)
1123 datapointer += sizeof(daliasframe_t);
1124 datapointer += sizeof(trivertx_t) * numverts;
1125 loadmodel->surfmesh.num_morphframes++;
1128 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1130 // store texture coordinates into temporary array, they will be stored
1131 // after usage is determined (triangle data)
1132 vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1133 vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1134 vertonseam = vertremap + numverts * 2;
1136 scales = 1.0 / skinwidth;
1137 scalet = 1.0 / skinheight;
1138 for (i = 0;i < numverts;i++)
1140 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1141 vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales;
1142 vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet;
1143 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1144 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1147 // load triangle data
1148 loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1150 // read the triangle elements
1151 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1152 for (j = 0;j < 3;j++)
1153 loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1154 // validate (note numverts is used because this is the original data)
1155 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1156 // now butcher the elements according to vertonseam and tri->facesfront
1157 // and then compact the vertex set to remove duplicates
1158 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1159 if (!LittleLong(pintriangles[i].facesfront)) // backface
1160 for (j = 0;j < 3;j++)
1161 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1162 loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1164 // (this uses vertremap to count usage to save some memory)
1165 for (i = 0;i < numverts*2;i++)
1167 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1168 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1169 // build remapping table and compact array
1170 loadmodel->surfmesh.num_vertices = 0;
1171 for (i = 0;i < numverts*2;i++)
1175 vertremap[i] = loadmodel->surfmesh.num_vertices;
1176 vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1177 vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1178 loadmodel->surfmesh.num_vertices++;
1181 vertremap[i] = -1; // not used at all
1183 // remap the elements to the new vertex set
1184 for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1185 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1186 // store the texture coordinates
1187 loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1188 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1190 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1191 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1194 // generate ushort elements array if possible
1195 if (loadmodel->surfmesh.num_vertices <= 65536)
1196 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1197 if (loadmodel->surfmesh.data_element3s)
1198 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1199 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1202 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1203 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1204 if (r_enableshadowvolumes.integer)
1206 loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
1208 Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1209 if (loadmodel->surfmesh.data_neighbor3i)
1210 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1211 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1212 Mod_Alias_MorphMesh_CompileFrames();
1215 Mem_Free(vertremap);
1218 skinfiles = Mod_LoadSkinFiles();
1221 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1222 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1223 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1224 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1225 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1226 Mod_FreeSkinFiles(skinfiles);
1227 for (i = 0;i < loadmodel->numskins;i++)
1229 loadmodel->skinscenes[i].firstframe = i;
1230 loadmodel->skinscenes[i].framecount = 1;
1231 loadmodel->skinscenes[i].loop = true;
1232 loadmodel->skinscenes[i].framerate = 10;
1237 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1238 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1239 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1240 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1242 datapointer = startskins;
1243 for (i = 0;i < loadmodel->numskins;i++)
1245 pinskintype = (daliasskintype_t *)datapointer;
1246 datapointer += sizeof(daliasskintype_t);
1248 if (pinskintype->type == ALIAS_SKIN_SINGLE)
1255 pinskingroup = (daliasskingroup_t *)datapointer;
1256 datapointer += sizeof(daliasskingroup_t);
1258 groupskins = LittleLong (pinskingroup->numskins);
1260 pinskinintervals = (daliasskininterval_t *)datapointer;
1261 datapointer += sizeof(daliasskininterval_t) * groupskins;
1263 interval = LittleFloat(pinskinintervals[0].interval);
1264 if (interval < 0.01f)
1266 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1271 dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1272 loadmodel->skinscenes[i].firstframe = totalskins;
1273 loadmodel->skinscenes[i].framecount = groupskins;
1274 loadmodel->skinscenes[i].framerate = 1.0f / interval;
1275 loadmodel->skinscenes[i].loop = true;
1277 for (j = 0;j < groupskins;j++)
1280 dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1282 dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1283 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))
1284 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));
1285 datapointer += skinwidth * skinheight;
1289 // check for skins that don't exist in the model, but do exist as external images
1290 // (this was added because yummyluv kept pestering me about support for it)
1291 // TODO: support shaders here?
1292 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)))
1294 // expand the arrays to make room
1295 tempskinscenes = loadmodel->skinscenes;
1296 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1297 memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1298 Mem_Free(tempskinscenes);
1300 tempaliasskins = loadmodel->data_textures;
1301 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1302 memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1303 Mem_Free(tempaliasskins);
1305 // store the info about the new skin
1306 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, tempskinframe);
1307 strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1308 loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1309 loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1310 loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1311 loadmodel->skinscenes[loadmodel->numskins].loop = true;
1313 //increase skin counts
1314 loadmodel->numskins++;
1317 // fix up the pointers since they are pointing at the old textures array
1318 // FIXME: this is a hack!
1319 for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1320 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1324 surface = loadmodel->data_surfaces;
1325 surface->texture = loadmodel->data_textures;
1326 surface->num_firsttriangle = 0;
1327 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1328 surface->num_firstvertex = 0;
1329 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1331 if(mod_alias_force_animated.string[0])
1332 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1334 if (!loadmodel->surfmesh.isanimated)
1336 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1337 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1338 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1339 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1340 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1341 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1344 // because shaders can do somewhat unexpected things, check for unusual features now
1345 for (i = 0;i < loadmodel->num_textures;i++)
1347 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1348 mod->DrawSky = R_Q1BSP_DrawSky;
1349 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1350 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1354 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
1356 int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1357 float iskinwidth, iskinheight;
1358 unsigned char *data;
1359 msurface_t *surface;
1361 unsigned char *base, *datapointer;
1362 md2frame_t *pinframe;
1364 md2triangle_t *intri;
1365 unsigned short *inst;
1366 struct md2verthash_s
1368 struct md2verthash_s *next;
1372 *hash, **md2verthash, *md2verthashdata;
1373 skinfile_t *skinfiles;
1375 pinmodel = (md2_t *)buffer;
1376 base = (unsigned char *)buffer;
1378 version = LittleLong (pinmodel->version);
1379 if (version != MD2ALIAS_VERSION)
1380 Host_Error ("%s has wrong version number (%i should be %i)",
1381 loadmodel->name, version, MD2ALIAS_VERSION);
1383 loadmodel->modeldatatypestring = "MD2";
1385 loadmodel->type = mod_alias;
1386 loadmodel->DrawSky = NULL;
1387 loadmodel->DrawAddWaterPlanes = NULL;
1388 loadmodel->Draw = R_Q1BSP_Draw;
1389 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1390 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1391 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1392 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1393 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1394 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1395 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1396 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1397 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1398 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1399 loadmodel->PointSuperContents = NULL;
1400 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1402 if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1403 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1404 if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1405 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1406 if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1407 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1408 if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1409 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1411 end = LittleLong(pinmodel->ofs_end);
1412 if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1413 Host_Error ("%s is not a valid model", loadmodel->name);
1414 if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1415 Host_Error ("%s is not a valid model", loadmodel->name);
1416 if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1417 Host_Error ("%s is not a valid model", loadmodel->name);
1418 if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1419 Host_Error ("%s is not a valid model", loadmodel->name);
1420 if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1421 Host_Error ("%s is not a valid model", loadmodel->name);
1423 loadmodel->numskins = LittleLong(pinmodel->num_skins);
1424 numxyz = LittleLong(pinmodel->num_xyz);
1425 numst = LittleLong(pinmodel->num_st);
1426 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1427 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1428 loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1429 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1430 skinwidth = LittleLong(pinmodel->skinwidth);
1431 skinheight = LittleLong(pinmodel->skinheight);
1432 iskinwidth = 1.0f / skinwidth;
1433 iskinheight = 1.0f / skinheight;
1435 loadmodel->num_surfaces = 1;
1436 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1437 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));
1438 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1439 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1440 loadmodel->sortedmodelsurfaces[0] = 0;
1441 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1442 loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1443 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1444 if (r_enableshadowvolumes.integer)
1446 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1449 loadmodel->synctype = ST_RAND;
1452 inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1453 skinfiles = Mod_LoadSkinFiles();
1456 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1457 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1458 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1459 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1460 Mod_FreeSkinFiles(skinfiles);
1462 else if (loadmodel->numskins)
1464 // skins found (most likely not a player model)
1465 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1466 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1467 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1468 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1469 Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
1473 // no skins (most likely a player model)
1474 loadmodel->numskins = 1;
1475 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1476 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1477 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1478 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL);
1481 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1482 for (i = 0;i < loadmodel->numskins;i++)
1484 loadmodel->skinscenes[i].firstframe = i;
1485 loadmodel->skinscenes[i].framecount = 1;
1486 loadmodel->skinscenes[i].loop = true;
1487 loadmodel->skinscenes[i].framerate = 10;
1490 // load the triangles and stvert data
1491 inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1492 intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1493 md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1494 md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1495 // swap the triangle list
1496 loadmodel->surfmesh.num_vertices = 0;
1497 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1499 for (j = 0;j < 3;j++)
1501 xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1502 st = (unsigned short) LittleShort (intri[i].index_st[j]);
1505 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1510 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1513 hashindex = (xyz * 256 + st) & 65535;
1514 for (hash = md2verthash[hashindex];hash;hash = hash->next)
1515 if (hash->xyz == xyz && hash->st == st)
1519 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1522 hash->next = md2verthash[hashindex];
1523 md2verthash[hashindex] = hash;
1525 loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1529 vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1530 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));
1531 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1532 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1533 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1536 hash = md2verthashdata + i;
1537 vertremap[i] = hash->xyz;
1538 sts = LittleShort(inst[hash->st*2+0]);
1539 stt = LittleShort(inst[hash->st*2+1]);
1540 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1542 Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1546 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1547 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1550 Mem_Free(md2verthash);
1551 Mem_Free(md2verthashdata);
1553 // generate ushort elements array if possible
1554 if (loadmodel->surfmesh.num_vertices <= 65536)
1555 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1556 if (loadmodel->surfmesh.data_element3s)
1557 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1558 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1561 datapointer = (base + LittleLong(pinmodel->ofs_frames));
1562 for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1567 pinframe = (md2frame_t *)datapointer;
1568 datapointer += sizeof(md2frame_t);
1569 // store the frame scale/translate into the appropriate array
1570 for (j = 0;j < 3;j++)
1572 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1573 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1575 // convert the vertices
1576 v = (trivertx_t *)datapointer;
1577 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1578 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1579 out[k] = v[vertremap[k]];
1580 datapointer += numxyz * sizeof(trivertx_t);
1582 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1583 loadmodel->animscenes[i].firstframe = i;
1584 loadmodel->animscenes[i].framecount = 1;
1585 loadmodel->animscenes[i].framerate = 10;
1586 loadmodel->animscenes[i].loop = true;
1589 Mem_Free(vertremap);
1591 if (loadmodel->surfmesh.data_neighbor3i)
1592 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1593 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1594 Mod_Alias_MorphMesh_CompileFrames();
1595 if(mod_alias_force_animated.string[0])
1596 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1598 surface = loadmodel->data_surfaces;
1599 surface->texture = loadmodel->data_textures;
1600 surface->num_firsttriangle = 0;
1601 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1602 surface->num_firstvertex = 0;
1603 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1605 if (!loadmodel->surfmesh.isanimated)
1607 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1608 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1609 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1610 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1611 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1612 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1615 // because shaders can do somewhat unexpected things, check for unusual features now
1616 for (i = 0;i < loadmodel->num_textures;i++)
1618 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1619 mod->DrawSky = R_Q1BSP_DrawSky;
1620 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1621 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1625 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
1627 int i, j, k, version, meshvertices, meshtriangles;
1628 unsigned char *data;
1629 msurface_t *surface;
1630 md3modelheader_t *pinmodel;
1631 md3frameinfo_t *pinframe;
1634 skinfile_t *skinfiles;
1636 pinmodel = (md3modelheader_t *)buffer;
1638 if (memcmp(pinmodel->identifier, "IDP3", 4))
1639 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1640 version = LittleLong (pinmodel->version);
1641 if (version != MD3VERSION)
1642 Host_Error ("%s has wrong version number (%i should be %i)",
1643 loadmodel->name, version, MD3VERSION);
1645 skinfiles = Mod_LoadSkinFiles();
1646 if (loadmodel->numskins < 1)
1647 loadmodel->numskins = 1;
1649 loadmodel->modeldatatypestring = "MD3";
1651 loadmodel->type = mod_alias;
1652 loadmodel->DrawSky = NULL;
1653 loadmodel->DrawAddWaterPlanes = NULL;
1654 loadmodel->Draw = R_Q1BSP_Draw;
1655 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1656 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1657 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1658 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1659 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1660 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1661 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1662 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1663 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1664 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1665 loadmodel->PointSuperContents = NULL;
1666 loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1667 loadmodel->synctype = ST_RAND;
1668 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1669 i = LittleLong (pinmodel->flags);
1670 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1672 // set up some global info about the model
1673 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1674 loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1676 // make skinscenes for the skins (no groups)
1677 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1678 for (i = 0;i < loadmodel->numskins;i++)
1680 loadmodel->skinscenes[i].firstframe = i;
1681 loadmodel->skinscenes[i].framecount = 1;
1682 loadmodel->skinscenes[i].loop = true;
1683 loadmodel->skinscenes[i].framerate = 10;
1687 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1688 for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1690 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1691 loadmodel->animscenes[i].firstframe = i;
1692 loadmodel->animscenes[i].framecount = 1;
1693 loadmodel->animscenes[i].framerate = 10;
1694 loadmodel->animscenes[i].loop = true;
1698 loadmodel->num_tagframes = loadmodel->numframes;
1699 loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1700 loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1701 for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1703 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1704 for (j = 0;j < 9;j++)
1705 loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1706 for (j = 0;j < 3;j++)
1707 loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1708 //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);
1714 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)))
1716 if (memcmp(pinmesh->identifier, "IDP3", 4))
1717 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1718 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1719 Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1720 meshvertices += LittleLong(pinmesh->num_vertices);
1721 meshtriangles += LittleLong(pinmesh->num_triangles);
1724 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1725 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1726 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1727 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));
1728 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1729 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1730 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1731 loadmodel->surfmesh.num_vertices = meshvertices;
1732 loadmodel->surfmesh.num_triangles = meshtriangles;
1733 loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1734 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1735 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1736 if (r_enableshadowvolumes.integer)
1738 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1740 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1741 loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1742 if (meshvertices <= 65536)
1744 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1749 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)))
1751 if (memcmp(pinmesh->identifier, "IDP3", 4))
1752 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1753 loadmodel->sortedmodelsurfaces[i] = i;
1754 surface = loadmodel->data_surfaces + i;
1755 surface->texture = loadmodel->data_textures + i;
1756 surface->num_firsttriangle = meshtriangles;
1757 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1758 surface->num_firstvertex = meshvertices;
1759 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1760 meshvertices += surface->num_vertices;
1761 meshtriangles += surface->num_triangles;
1763 for (j = 0;j < surface->num_triangles * 3;j++)
1764 loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1765 for (j = 0;j < surface->num_vertices;j++)
1767 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1768 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1770 for (j = 0;j < loadmodel->numframes;j++)
1772 const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1773 md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1774 for (k = 0;k < surface->num_vertices;k++, in++, out++)
1776 out->origin[0] = LittleShort(in->origin[0]);
1777 out->origin[1] = LittleShort(in->origin[1]);
1778 out->origin[2] = LittleShort(in->origin[2]);
1779 out->pitch = in->pitch;
1784 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1786 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1788 if (loadmodel->surfmesh.data_element3s)
1789 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1790 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1791 if (loadmodel->surfmesh.data_neighbor3i)
1792 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1793 Mod_Alias_MorphMesh_CompileFrames();
1794 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1795 Mod_FreeSkinFiles(skinfiles);
1796 Mod_MakeSortedSurfaces(loadmodel);
1797 if(mod_alias_force_animated.string[0])
1798 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1800 if (!loadmodel->surfmesh.isanimated)
1802 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1803 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1804 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1805 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1806 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1807 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1810 // because shaders can do somewhat unexpected things, check for unusual features now
1811 for (i = 0;i < loadmodel->num_textures;i++)
1813 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1814 mod->DrawSky = R_Q1BSP_DrawSky;
1815 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1816 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1820 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1822 zymtype1header_t *pinmodel, *pheader;
1823 unsigned char *pbase;
1824 int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1825 float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1826 zymvertex_t *verts, *vertdata;
1830 skinfile_t *skinfiles;
1831 unsigned char *data;
1832 msurface_t *surface;
1834 pinmodel = (zymtype1header_t *)buffer;
1835 pbase = (unsigned char *)buffer;
1836 if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1837 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1838 if (BigLong(pinmodel->type) != 1)
1839 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1841 loadmodel->modeldatatypestring = "ZYM";
1843 loadmodel->type = mod_alias;
1844 loadmodel->synctype = ST_RAND;
1848 pheader->type = BigLong(pinmodel->type);
1849 pheader->filesize = BigLong(pinmodel->filesize);
1850 pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1851 pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1852 pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1853 pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1854 pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1855 pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1856 pheader->radius = BigFloat(pinmodel->radius);
1857 pheader->numverts = BigLong(pinmodel->numverts);
1858 pheader->numtris = BigLong(pinmodel->numtris);
1859 pheader->numshaders = BigLong(pinmodel->numshaders);
1860 pheader->numbones = BigLong(pinmodel->numbones);
1861 pheader->numscenes = BigLong(pinmodel->numscenes);
1862 pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1863 pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1864 pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1865 pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1866 pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1867 pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1868 pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1869 pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1870 pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1871 pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1872 pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1873 pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1874 pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1875 pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1876 pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1877 pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1878 pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1879 pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1881 if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1883 Con_Printf("%s has no geometry\n", loadmodel->name);
1886 if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1888 Con_Printf("%s has no animations\n", loadmodel->name);
1892 loadmodel->DrawSky = NULL;
1893 loadmodel->DrawAddWaterPlanes = NULL;
1894 loadmodel->Draw = R_Q1BSP_Draw;
1895 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1896 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1897 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1898 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1899 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1900 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1901 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1902 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1903 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1904 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1905 loadmodel->PointSuperContents = NULL;
1906 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1908 loadmodel->numframes = pheader->numscenes;
1909 loadmodel->num_surfaces = pheader->numshaders;
1911 skinfiles = Mod_LoadSkinFiles();
1912 if (loadmodel->numskins < 1)
1913 loadmodel->numskins = 1;
1915 // make skinscenes for the skins (no groups)
1916 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1917 for (i = 0;i < loadmodel->numskins;i++)
1919 loadmodel->skinscenes[i].firstframe = i;
1920 loadmodel->skinscenes[i].framecount = 1;
1921 loadmodel->skinscenes[i].loop = true;
1922 loadmodel->skinscenes[i].framerate = 10;
1926 // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
1927 modelradius = pheader->radius;
1928 for (i = 0;i < 3;i++)
1930 loadmodel->normalmins[i] = pheader->mins[i];
1931 loadmodel->normalmaxs[i] = pheader->maxs[i];
1932 loadmodel->rotatedmins[i] = -modelradius;
1933 loadmodel->rotatedmaxs[i] = modelradius;
1935 corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1936 corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1937 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1938 if (loadmodel->yawmaxs[0] > modelradius)
1939 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1940 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1941 loadmodel->yawmins[2] = loadmodel->normalmins[2];
1942 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1943 loadmodel->radius = modelradius;
1944 loadmodel->radius2 = modelradius * modelradius;
1946 // go through the lumps, swapping things
1948 //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1949 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1950 scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1951 numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1952 for (i = 0;i < pheader->numscenes;i++)
1954 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1955 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1956 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1957 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1958 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1959 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1960 Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1961 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1962 Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1963 if (loadmodel->animscenes[i].framerate < 0)
1964 Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1968 //zymlump_t lump_bones; // zymbone_t bone[numbones];
1969 loadmodel->num_bones = pheader->numbones;
1970 loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1971 bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1972 for (i = 0;i < pheader->numbones;i++)
1974 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1975 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1976 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1977 if (loadmodel->data_bones[i].parent >= i)
1978 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1981 //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1982 vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1983 bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1984 for (i = 0;i < pheader->numverts;i++)
1986 vertbonecounts[i] = BigLong(bonecount[i]);
1987 if (vertbonecounts[i] != 1)
1988 Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1991 loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1993 meshvertices = pheader->numverts;
1994 meshtriangles = pheader->numtris;
1996 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1997 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1998 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1999 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]));
2000 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2001 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2002 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2003 loadmodel->surfmesh.num_vertices = meshvertices;
2004 loadmodel->surfmesh.num_triangles = meshtriangles;
2005 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2006 if (r_enableshadowvolumes.integer)
2008 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2010 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2011 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2012 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2013 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2014 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2015 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2016 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2017 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2018 loadmodel->surfmesh.num_blends = 0;
2019 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2020 if (loadmodel->surfmesh.num_vertices <= 65536)
2022 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2024 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2025 loadmodel->surfmesh.data_blendweights = NULL;
2027 //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
2028 poses = (float *) (pheader->lump_poses.start + pbase);
2029 // figure out scale of model from root bone, for compatibility with old zmodel versions
2030 tempvec[0] = BigFloat(poses[0]);
2031 tempvec[1] = BigFloat(poses[1]);
2032 tempvec[2] = BigFloat(poses[2]);
2033 modelscale = VectorLength(tempvec);
2035 for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
2037 f = fabs(BigFloat(poses[i]));
2038 biggestorigin = max(biggestorigin, f);
2040 loadmodel->num_posescale = biggestorigin / 32767.0f;
2041 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2042 for (i = 0;i < numposes;i++)
2044 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
2045 for (j = 0;j < loadmodel->num_bones;j++)
2048 matrix4x4_t posematrix;
2049 for (k = 0;k < 12;k++)
2050 pose[k] = BigFloat(frameposes[j*12+k]);
2051 //if (j < loadmodel->num_bones)
2052 // 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));
2053 // scale child bones to match the root scale
2054 if (loadmodel->data_bones[j].parent >= 0)
2056 pose[3] *= modelscale;
2057 pose[7] *= modelscale;
2058 pose[11] *= modelscale;
2060 // normalize rotation matrix
2061 VectorNormalize(pose + 0);
2062 VectorNormalize(pose + 4);
2063 VectorNormalize(pose + 8);
2064 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2065 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2069 //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2070 verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2071 vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2072 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2073 // (converting from weight-blending skeletal animation to
2074 // deformation-based skeletal animation)
2075 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2076 for (i = 0;i < loadmodel->num_bones;i++)
2079 for (k = 0;k < 12;k++)
2080 m[k] = BigFloat(poses[i*12+k]);
2081 if (loadmodel->data_bones[i].parent >= 0)
2082 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2084 for (k = 0;k < 12;k++)
2085 bonepose[12*i+k] = m[k];
2087 for (j = 0;j < pheader->numverts;j++)
2089 // this format really should have had a per vertexweight weight value...
2090 // but since it does not, the weighting is completely ignored and
2091 // only one weight is allowed per vertex
2092 int boneindex = BigLong(vertdata[j].bonenum);
2093 const float *m = bonepose + 12 * boneindex;
2094 float relativeorigin[3];
2095 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2096 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2097 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2098 // transform the vertex bone weight into the base mesh
2099 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2100 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2101 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2102 // store the weight as the primary weight on this vertex
2103 loadmodel->surfmesh.blends[j] = boneindex;
2104 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = boneindex;
2105 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2106 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2107 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2108 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = 255;
2109 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2110 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2111 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2114 // normals and tangents are calculated after elements are loaded
2116 //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2117 outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2118 intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2119 for (i = 0;i < pheader->numverts;i++)
2121 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2122 // flip T coordinate for OpenGL
2123 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2126 //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2127 //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2128 //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2130 //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2131 //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)
2132 // byteswap, validate, and swap winding order of tris
2133 count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2134 if (pheader->lump_render.length != count)
2135 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2136 renderlist = (int *) (pheader->lump_render.start + pbase);
2137 renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2139 for (i = 0;i < loadmodel->num_surfaces;i++)
2141 int firstvertex, lastvertex;
2142 if (renderlist >= renderlistend)
2143 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2144 count = BigLong(*renderlist);renderlist++;
2145 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2146 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2148 loadmodel->sortedmodelsurfaces[i] = i;
2149 surface = loadmodel->data_surfaces + i;
2150 surface->texture = loadmodel->data_textures + i;
2151 surface->num_firsttriangle = meshtriangles;
2152 surface->num_triangles = count;
2153 meshtriangles += surface->num_triangles;
2155 // load the elements
2156 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2157 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2159 outelements[j*3+2] = BigLong(renderlist[0]);
2160 outelements[j*3+1] = BigLong(renderlist[1]);
2161 outelements[j*3+0] = BigLong(renderlist[2]);
2163 // validate the elements and find the used vertex range
2164 firstvertex = meshvertices;
2166 for (j = 0;j < surface->num_triangles * 3;j++)
2168 if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2169 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2170 firstvertex = min(firstvertex, outelements[j]);
2171 lastvertex = max(lastvertex, outelements[j]);
2173 surface->num_firstvertex = firstvertex;
2174 surface->num_vertices = lastvertex + 1 - firstvertex;
2176 // since zym models do not have named sections, reuse their shader
2177 // name as the section name
2178 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2179 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2181 Mod_FreeSkinFiles(skinfiles);
2182 Mem_Free(vertbonecounts);
2184 Mod_MakeSortedSurfaces(loadmodel);
2186 // compute all the mesh information that was not loaded from the file
2187 if (loadmodel->surfmesh.data_element3s)
2188 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2189 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2190 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2191 Mod_BuildBaseBonePoses();
2192 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);
2193 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);
2194 if (loadmodel->surfmesh.data_neighbor3i)
2195 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2196 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2197 if(mod_alias_force_animated.string[0])
2198 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2200 if (!loadmodel->surfmesh.isanimated)
2202 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2203 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2204 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2205 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2206 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2207 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2210 // because shaders can do somewhat unexpected things, check for unusual features now
2211 for (i = 0;i < loadmodel->num_textures;i++)
2213 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2214 mod->DrawSky = R_Q1BSP_DrawSky;
2215 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2216 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2220 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2222 dpmheader_t *pheader;
2226 unsigned char *pbase;
2227 int i, j, k, meshvertices, meshtriangles;
2228 skinfile_t *skinfiles;
2229 unsigned char *data;
2231 float biggestorigin, tempvec[3], modelscale;
2235 pheader = (dpmheader_t *)buffer;
2236 pbase = (unsigned char *)buffer;
2237 if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2238 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2239 if (BigLong(pheader->type) != 2)
2240 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2242 loadmodel->modeldatatypestring = "DPM";
2244 loadmodel->type = mod_alias;
2245 loadmodel->synctype = ST_RAND;
2248 pheader->type = BigLong(pheader->type);
2249 pheader->filesize = BigLong(pheader->filesize);
2250 pheader->mins[0] = BigFloat(pheader->mins[0]);
2251 pheader->mins[1] = BigFloat(pheader->mins[1]);
2252 pheader->mins[2] = BigFloat(pheader->mins[2]);
2253 pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2254 pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2255 pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2256 pheader->yawradius = BigFloat(pheader->yawradius);
2257 pheader->allradius = BigFloat(pheader->allradius);
2258 pheader->num_bones = BigLong(pheader->num_bones);
2259 pheader->num_meshs = BigLong(pheader->num_meshs);
2260 pheader->num_frames = BigLong(pheader->num_frames);
2261 pheader->ofs_bones = BigLong(pheader->ofs_bones);
2262 pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2263 pheader->ofs_frames = BigLong(pheader->ofs_frames);
2265 if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2267 Con_Printf("%s has no geometry\n", loadmodel->name);
2270 if (pheader->num_frames < 1)
2272 Con_Printf("%s has no frames\n", loadmodel->name);
2276 loadmodel->DrawSky = NULL;
2277 loadmodel->DrawAddWaterPlanes = NULL;
2278 loadmodel->Draw = R_Q1BSP_Draw;
2279 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2280 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2281 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2282 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2283 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2284 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2285 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2286 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2287 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2288 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2289 loadmodel->PointSuperContents = NULL;
2290 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2293 // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2294 for (i = 0;i < 3;i++)
2296 loadmodel->normalmins[i] = pheader->mins[i];
2297 loadmodel->normalmaxs[i] = pheader->maxs[i];
2298 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2299 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2300 loadmodel->rotatedmins[i] = -pheader->allradius;
2301 loadmodel->rotatedmaxs[i] = pheader->allradius;
2303 loadmodel->radius = pheader->allradius;
2304 loadmodel->radius2 = pheader->allradius * pheader->allradius;
2306 // load external .skin files if present
2307 skinfiles = Mod_LoadSkinFiles();
2308 if (loadmodel->numskins < 1)
2309 loadmodel->numskins = 1;
2314 // gather combined statistics from the meshes
2315 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2316 for (i = 0;i < (int)pheader->num_meshs;i++)
2318 int numverts = BigLong(dpmmesh->num_verts);
2319 meshvertices += numverts;
2320 meshtriangles += BigLong(dpmmesh->num_tris);
2324 loadmodel->numframes = pheader->num_frames;
2325 loadmodel->num_bones = pheader->num_bones;
2326 loadmodel->num_poses = loadmodel->numframes;
2327 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
2328 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2329 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2330 // do most allocations as one merged chunk
2331 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));
2332 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2333 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2334 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2335 loadmodel->surfmesh.num_vertices = meshvertices;
2336 loadmodel->surfmesh.num_triangles = meshtriangles;
2337 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2338 if (r_enableshadowvolumes.integer)
2340 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2342 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2343 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2344 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2345 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2346 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2347 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2348 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2349 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2350 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2351 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2352 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2353 loadmodel->surfmesh.num_blends = 0;
2354 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2355 if (meshvertices <= 65536)
2357 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2359 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2360 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2362 for (i = 0;i < loadmodel->numskins;i++)
2364 loadmodel->skinscenes[i].firstframe = i;
2365 loadmodel->skinscenes[i].framecount = 1;
2366 loadmodel->skinscenes[i].loop = true;
2367 loadmodel->skinscenes[i].framerate = 10;
2370 // load the bone info
2371 bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2372 for (i = 0;i < loadmodel->num_bones;i++)
2374 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2375 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2376 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2377 if (loadmodel->data_bones[i].parent >= i)
2378 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2382 frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2383 // figure out scale of model from root bone, for compatibility with old dpmodel versions
2384 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2385 tempvec[0] = BigFloat(poses[0]);
2386 tempvec[1] = BigFloat(poses[1]);
2387 tempvec[2] = BigFloat(poses[2]);
2388 modelscale = VectorLength(tempvec);
2390 for (i = 0;i < loadmodel->numframes;i++)
2392 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2393 loadmodel->animscenes[i].firstframe = i;
2394 loadmodel->animscenes[i].framecount = 1;
2395 loadmodel->animscenes[i].loop = true;
2396 loadmodel->animscenes[i].framerate = 10;
2397 // load the bone poses for this frame
2398 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2399 for (j = 0;j < loadmodel->num_bones*12;j++)
2401 f = fabs(BigFloat(poses[j]));
2402 biggestorigin = max(biggestorigin, f);
2404 // stuff not processed here: mins, maxs, yawradius, allradius
2406 loadmodel->num_posescale = biggestorigin / 32767.0f;
2407 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2408 for (i = 0;i < loadmodel->numframes;i++)
2410 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2411 for (j = 0;j < loadmodel->num_bones;j++)
2414 matrix4x4_t posematrix;
2415 for (k = 0;k < 12;k++)
2416 pose[k] = BigFloat(frameposes[j*12+k]);
2417 // scale child bones to match the root scale
2418 if (loadmodel->data_bones[j].parent >= 0)
2420 pose[3] *= modelscale;
2421 pose[7] *= modelscale;
2422 pose[11] *= modelscale;
2424 // normalize rotation matrix
2425 VectorNormalize(pose + 0);
2426 VectorNormalize(pose + 4);
2427 VectorNormalize(pose + 8);
2428 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2429 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2433 // load the meshes now
2434 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2437 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2438 // (converting from weight-blending skeletal animation to
2439 // deformation-based skeletal animation)
2440 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2441 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2442 for (i = 0;i < loadmodel->num_bones;i++)
2445 for (k = 0;k < 12;k++)
2446 m[k] = BigFloat(poses[i*12+k]);
2447 if (loadmodel->data_bones[i].parent >= 0)
2448 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2450 for (k = 0;k < 12;k++)
2451 bonepose[12*i+k] = m[k];
2453 for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2455 const int *inelements;
2457 const float *intexcoord;
2458 msurface_t *surface;
2460 loadmodel->sortedmodelsurfaces[i] = i;
2461 surface = loadmodel->data_surfaces + i;
2462 surface->texture = loadmodel->data_textures + i;
2463 surface->num_firsttriangle = meshtriangles;
2464 surface->num_triangles = BigLong(dpmmesh->num_tris);
2465 surface->num_firstvertex = meshvertices;
2466 surface->num_vertices = BigLong(dpmmesh->num_verts);
2467 meshvertices += surface->num_vertices;
2468 meshtriangles += surface->num_triangles;
2470 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2471 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2472 for (j = 0;j < surface->num_triangles;j++)
2474 // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2475 outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
2476 outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
2477 outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
2482 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2483 for (j = 0;j < surface->num_vertices*2;j++)
2484 loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2486 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2487 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2489 int weightindex[4] = { 0, 0, 0, 0 };
2490 float weightinfluence[4] = { 0, 0, 0, 0 };
2492 int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2493 data += sizeof(dpmvertex_t);
2494 for (k = 0;k < numweights;k++)
2496 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2497 int boneindex = BigLong(vert->bonenum);
2498 const float *m = bonepose + 12 * boneindex;
2499 float influence = BigFloat(vert->influence);
2500 float relativeorigin[3], relativenormal[3];
2501 relativeorigin[0] = BigFloat(vert->origin[0]);
2502 relativeorigin[1] = BigFloat(vert->origin[1]);
2503 relativeorigin[2] = BigFloat(vert->origin[2]);
2504 relativenormal[0] = BigFloat(vert->normal[0]);
2505 relativenormal[1] = BigFloat(vert->normal[1]);
2506 relativenormal[2] = BigFloat(vert->normal[2]);
2507 // blend the vertex bone weights into the base mesh
2508 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2509 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2510 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2511 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2512 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2513 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2516 // store the first (and often only) weight
2517 weightinfluence[0] = influence;
2518 weightindex[0] = boneindex;
2522 // sort the new weight into this vertex's weight table
2523 // (which only accepts up to 4 bones per vertex)
2524 for (l = 0;l < 4;l++)
2526 if (weightinfluence[l] < influence)
2528 // move weaker influence weights out of the way first
2530 for (l2 = 3;l2 > l;l2--)
2532 weightinfluence[l2] = weightinfluence[l2-1];
2533 weightindex[l2] = weightindex[l2-1];
2535 // store the new weight
2536 weightinfluence[l] = influence;
2537 weightindex[l] = boneindex;
2542 data += sizeof(dpmbonevert_t);
2544 loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2545 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = weightindex[0];
2546 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2547 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2548 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2549 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
2550 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2551 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2552 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2555 // since dpm models do not have named sections, reuse their shader name as the section name
2556 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2558 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2560 if (loadmodel->surfmesh.num_blends < meshvertices)
2561 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2563 Mod_FreeSkinFiles(skinfiles);
2564 Mod_MakeSortedSurfaces(loadmodel);
2566 // compute all the mesh information that was not loaded from the file
2567 if (loadmodel->surfmesh.data_element3s)
2568 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2569 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2570 Mod_BuildBaseBonePoses();
2571 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);
2572 if (loadmodel->surfmesh.data_neighbor3i)
2573 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2574 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2575 if(mod_alias_force_animated.string[0])
2576 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2578 if (!loadmodel->surfmesh.isanimated)
2580 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2581 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2582 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2583 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2584 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2585 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2588 // because shaders can do somewhat unexpected things, check for unusual features now
2589 for (i = 0;i < loadmodel->num_textures;i++)
2591 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2592 mod->DrawSky = R_Q1BSP_DrawSky;
2593 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2594 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2598 // no idea why PSK/PSA files contain weird quaternions but they do...
2599 #define PSKQUATNEGATIONS
2600 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2602 int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2603 int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2604 fs_offset_t filesize;
2609 pskboneinfo_t *bones;
2610 pskrawweights_t *rawweights;
2611 //pskboneinfo_t *animbones;
2612 pskaniminfo_t *anims;
2613 pskanimkeys_t *animkeys;
2614 void *animfilebuffer, *animbuffer, *animbufferend;
2615 unsigned char *data;
2617 skinfile_t *skinfiles;
2618 char animname[MAX_QPATH];
2620 float biggestorigin;
2622 pchunk = (pskchunk_t *)buffer;
2623 if (strcmp(pchunk->id, "ACTRHEAD"))
2624 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2626 loadmodel->modeldatatypestring = "PSK";
2628 loadmodel->type = mod_alias;
2629 loadmodel->DrawSky = NULL;
2630 loadmodel->DrawAddWaterPlanes = NULL;
2631 loadmodel->Draw = R_Q1BSP_Draw;
2632 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2633 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2634 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2635 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2636 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2637 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2638 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2639 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2640 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2641 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2642 loadmodel->PointSuperContents = NULL;
2643 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2644 loadmodel->synctype = ST_RAND;
2646 FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2647 strlcat(animname, ".psa", sizeof(animname));
2648 animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2649 animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2651 animbufferend = animbuffer;
2670 while (buffer < bufferend)
2672 pchunk = (pskchunk_t *)buffer;
2673 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2674 version = LittleLong(pchunk->version);
2675 recordsize = LittleLong(pchunk->recordsize);
2676 numrecords = LittleLong(pchunk->numrecords);
2677 if (developer_extra.integer)
2678 Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2679 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2680 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);
2681 if (!strcmp(pchunk->id, "ACTRHEAD"))
2685 else if (!strcmp(pchunk->id, "PNTS0000"))
2688 if (recordsize != sizeof(*p))
2689 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2690 // byteswap in place and keep the pointer
2691 numpnts = numrecords;
2692 pnts = (pskpnts_t *)buffer;
2693 for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2695 p->origin[0] = LittleFloat(p->origin[0]);
2696 p->origin[1] = LittleFloat(p->origin[1]);
2697 p->origin[2] = LittleFloat(p->origin[2]);
2701 else if (!strcmp(pchunk->id, "VTXW0000"))
2704 if (recordsize != sizeof(*p))
2705 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2706 // byteswap in place and keep the pointer
2707 numvtxw = numrecords;
2708 vtxw = (pskvtxw_t *)buffer;
2709 for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2711 p->pntsindex = LittleShort(p->pntsindex);
2712 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2713 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2714 if (p->pntsindex >= numpnts)
2716 Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2722 else if (!strcmp(pchunk->id, "FACE0000"))
2725 if (recordsize != sizeof(*p))
2726 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2727 // byteswap in place and keep the pointer
2728 numfaces = numrecords;
2729 faces = (pskface_t *)buffer;
2730 for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2732 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2733 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2734 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2735 p->group = LittleLong(p->group);
2736 if (p->vtxwindex[0] >= numvtxw)
2738 Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2739 p->vtxwindex[0] = 0;
2741 if (p->vtxwindex[1] >= numvtxw)
2743 Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2744 p->vtxwindex[1] = 0;
2746 if (p->vtxwindex[2] >= numvtxw)
2748 Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2749 p->vtxwindex[2] = 0;
2754 else if (!strcmp(pchunk->id, "MATT0000"))
2757 if (recordsize != sizeof(*p))
2758 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2759 // byteswap in place and keep the pointer
2760 nummatts = numrecords;
2761 matts = (pskmatt_t *)buffer;
2762 for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2768 else if (!strcmp(pchunk->id, "REFSKELT"))
2771 if (recordsize != sizeof(*p))
2772 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2773 // byteswap in place and keep the pointer
2774 numbones = numrecords;
2775 bones = (pskboneinfo_t *)buffer;
2776 for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2778 p->numchildren = LittleLong(p->numchildren);
2779 p->parent = LittleLong(p->parent);
2780 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2781 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2782 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2783 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2784 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2785 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2786 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2787 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2788 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2789 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2790 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2791 #ifdef PSKQUATNEGATIONS
2794 p->basepose.quat[0] *= -1;
2795 p->basepose.quat[1] *= -1;
2796 p->basepose.quat[2] *= -1;
2800 p->basepose.quat[0] *= 1;
2801 p->basepose.quat[1] *= -1;
2802 p->basepose.quat[2] *= 1;
2805 if (p->parent < 0 || p->parent >= numbones)
2807 Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2813 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2816 if (recordsize != sizeof(*p))
2817 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2818 // byteswap in place and keep the pointer
2819 numrawweights = numrecords;
2820 rawweights = (pskrawweights_t *)buffer;
2821 for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2823 p->weight = LittleFloat(p->weight);
2824 p->pntsindex = LittleLong(p->pntsindex);
2825 p->boneindex = LittleLong(p->boneindex);
2826 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2828 Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2831 if (p->boneindex < 0 || p->boneindex >= numbones)
2833 Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2841 while (animbuffer < animbufferend)
2843 pchunk = (pskchunk_t *)animbuffer;
2844 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2845 version = LittleLong(pchunk->version);
2846 recordsize = LittleLong(pchunk->recordsize);
2847 numrecords = LittleLong(pchunk->numrecords);
2848 if (developer_extra.integer)
2849 Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2850 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2851 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);
2852 if (!strcmp(pchunk->id, "ANIMHEAD"))
2856 else if (!strcmp(pchunk->id, "BONENAMES"))
2859 if (recordsize != sizeof(*p))
2860 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2861 // byteswap in place and keep the pointer
2862 numanimbones = numrecords;
2863 //animbones = (pskboneinfo_t *)animbuffer;
2864 // NOTE: supposedly psa does not need to match the psk model, the
2865 // bones missing from the psa would simply use their base
2866 // positions from the psk, but this is hard for me to implement
2867 // and people can easily make animations that match.
2868 if (numanimbones != numbones)
2869 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2870 for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2872 p->numchildren = LittleLong(p->numchildren);
2873 p->parent = LittleLong(p->parent);
2874 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2875 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2876 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2877 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2878 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2879 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2880 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2881 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2882 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2883 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2884 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2885 #ifdef PSKQUATNEGATIONS
2888 p->basepose.quat[0] *= -1;
2889 p->basepose.quat[1] *= -1;
2890 p->basepose.quat[2] *= -1;
2894 p->basepose.quat[0] *= 1;
2895 p->basepose.quat[1] *= -1;
2896 p->basepose.quat[2] *= 1;
2899 if (p->parent < 0 || p->parent >= numanimbones)
2901 Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2904 // check that bones are the same as in the base
2905 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2906 Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2910 else if (!strcmp(pchunk->id, "ANIMINFO"))
2913 if (recordsize != sizeof(*p))
2914 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2915 // byteswap in place and keep the pointer
2916 numanims = numrecords;
2917 anims = (pskaniminfo_t *)animbuffer;
2918 for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2920 p->numbones = LittleLong(p->numbones);
2921 p->playtime = LittleFloat(p->playtime);
2922 p->fps = LittleFloat(p->fps);
2923 p->firstframe = LittleLong(p->firstframe);
2924 p->numframes = LittleLong(p->numframes);
2925 if (p->numbones != numbones)
2926 Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2930 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2933 if (recordsize != sizeof(*p))
2934 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2935 numanimkeys = numrecords;
2936 animkeys = (pskanimkeys_t *)animbuffer;
2937 for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2939 p->origin[0] = LittleFloat(p->origin[0]);
2940 p->origin[1] = LittleFloat(p->origin[1]);
2941 p->origin[2] = LittleFloat(p->origin[2]);
2942 p->quat[0] = LittleFloat(p->quat[0]);
2943 p->quat[1] = LittleFloat(p->quat[1]);
2944 p->quat[2] = LittleFloat(p->quat[2]);
2945 p->quat[3] = LittleFloat(p->quat[3]);
2946 p->frametime = LittleFloat(p->frametime);
2947 #ifdef PSKQUATNEGATIONS
2948 if (index % numbones)
2963 // TODO: allocate bonepose stuff
2966 Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2969 if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2970 Host_Error("%s: missing required chunks", loadmodel->name);
2974 loadmodel->numframes = 0;
2975 for (index = 0;index < numanims;index++)
2976 loadmodel->numframes += anims[index].numframes;
2977 if (numanimkeys != numbones * loadmodel->numframes)
2978 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2981 loadmodel->numframes = loadmodel->num_poses = 1;
2983 meshvertices = numvtxw;
2984 meshtriangles = numfaces;
2986 // load external .skin files if present
2987 skinfiles = Mod_LoadSkinFiles();
2988 if (loadmodel->numskins < 1)
2989 loadmodel->numskins = 1;
2990 loadmodel->num_bones = numbones;
2991 loadmodel->num_poses = loadmodel->numframes;
2992 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2993 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2994 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2995 loadmodel->surfmesh.num_vertices = meshvertices;
2996 loadmodel->surfmesh.num_triangles = meshtriangles;
2997 // do most allocations as one merged chunk
2998 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);
2999 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
3000 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3001 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3002 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3003 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
3004 if (r_enableshadowvolumes.integer)
3006 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
3008 loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3009 loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3010 loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3011 loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3012 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3013 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3014 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3015 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3016 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3017 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3018 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3019 loadmodel->surfmesh.num_blends = 0;
3020 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3021 if (loadmodel->surfmesh.num_vertices <= 65536)
3023 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
3025 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3026 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
3028 for (i = 0;i < loadmodel->numskins;i++)
3030 loadmodel->skinscenes[i].firstframe = i;
3031 loadmodel->skinscenes[i].framecount = 1;
3032 loadmodel->skinscenes[i].loop = true;
3033 loadmodel->skinscenes[i].framerate = 10;
3037 for (index = 0, i = 0;index < nummatts;index++)
3039 // since psk models do not have named sections, reuse their shader name as the section name
3040 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
3041 loadmodel->sortedmodelsurfaces[index] = index;
3042 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
3043 loadmodel->data_surfaces[index].num_firstvertex = 0;
3044 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
3047 // copy over the vertex locations and texcoords
3048 for (index = 0;index < numvtxw;index++)
3050 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
3051 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
3052 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
3053 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
3054 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
3057 // loading the faces is complicated because we need to sort them into surfaces by mattindex
3058 for (index = 0;index < numfaces;index++)
3059 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
3060 for (index = 0, i = 0;index < nummatts;index++)
3062 loadmodel->data_surfaces[index].num_firsttriangle = i;
3063 i += loadmodel->data_surfaces[index].num_triangles;
3064 loadmodel->data_surfaces[index].num_triangles = 0;
3066 for (index = 0;index < numfaces;index++)
3068 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
3069 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
3070 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
3071 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
3074 // copy over the bones
3075 for (index = 0;index < numbones;index++)
3077 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
3078 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
3079 if (loadmodel->data_bones[index].parent >= index)
3080 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
3083 // convert the basepose data
3084 if (loadmodel->num_bones)
3087 matrix4x4_t *basebonepose;
3088 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
3089 matrix4x4_t bonematrix;
3090 matrix4x4_t tempbonematrix;
3091 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
3092 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
3094 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]);
3095 if (loadmodel->data_bones[boneindex].parent >= 0)
3097 tempbonematrix = bonematrix;
3098 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3100 basebonepose[boneindex] = bonematrix;
3101 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3102 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3104 Mem_Free(basebonepose);
3107 // sort the psk point weights into the vertex weight tables
3108 // (which only accept up to 4 bones per vertex)
3109 for (index = 0;index < numvtxw;index++)
3111 int weightindex[4] = { 0, 0, 0, 0 };
3112 float weightinfluence[4] = { 0, 0, 0, 0 };
3114 for (j = 0;j < numrawweights;j++)
3116 if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3118 int boneindex = rawweights[j].boneindex;
3119 float influence = rawweights[j].weight;
3120 for (l = 0;l < 4;l++)
3122 if (weightinfluence[l] < influence)
3124 // move lower influence weights out of the way first
3126 for (l2 = 3;l2 > l;l2--)
3128 weightinfluence[l2] = weightinfluence[l2-1];
3129 weightindex[l2] = weightindex[l2-1];
3131 // store the new weight
3132 weightinfluence[l] = influence;
3133 weightindex[l] = boneindex;
3139 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3140 loadmodel->surfmesh.data_skeletalindex4ub[index*4 ] = weightindex[0];
3141 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3142 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3143 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3144 loadmodel->surfmesh.data_skeletalweight4ub[index*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
3145 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3146 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3147 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3149 if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3150 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3152 // set up the animscenes based on the anims
3155 for (index = 0, i = 0;index < numanims;index++)
3157 for (j = 0;j < anims[index].numframes;j++, i++)
3159 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3160 loadmodel->animscenes[i].firstframe = i;
3161 loadmodel->animscenes[i].framecount = 1;
3162 loadmodel->animscenes[i].loop = true;
3163 loadmodel->animscenes[i].framerate = anims[index].fps;
3166 // calculate the scaling value for bone origins so they can be compressed to short
3168 for (index = 0;index < numanimkeys;index++)
3170 pskanimkeys_t *k = animkeys + index;
3171 biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3172 biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3173 biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3175 loadmodel->num_posescale = biggestorigin / 32767.0f;
3176 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3178 // load the poses from the animkeys
3179 for (index = 0;index < numanimkeys;index++)
3181 pskanimkeys_t *k = animkeys + index;
3183 Vector4Copy(k->quat, quat);
3185 Vector4Negate(quat, quat);
3186 Vector4Normalize2(quat, quat);
3187 // compress poses to the short[7] format for longterm storage
3188 loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3189 loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3190 loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3191 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3192 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3193 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3194 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3199 strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3200 loadmodel->animscenes[0].firstframe = 0;
3201 loadmodel->animscenes[0].framecount = 1;
3202 loadmodel->animscenes[0].loop = true;
3203 loadmodel->animscenes[0].framerate = 10;
3205 // calculate the scaling value for bone origins so they can be compressed to short
3207 for (index = 0;index < numbones;index++)
3209 pskboneinfo_t *p = bones + index;
3210 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3211 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3212 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3214 loadmodel->num_posescale = biggestorigin / 32767.0f;
3215 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3217 // load the basepose as a frame
3218 for (index = 0;index < numbones;index++)
3220 pskboneinfo_t *p = bones + index;
3222 Vector4Copy(p->basepose.quat, quat);
3224 Vector4Negate(quat, quat);
3225 Vector4Normalize2(quat, quat);
3226 // compress poses to the short[7] format for longterm storage
3227 loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3228 loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3229 loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3230 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3231 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3232 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3233 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3237 Mod_FreeSkinFiles(skinfiles);
3239 Mem_Free(animfilebuffer);
3240 Mod_MakeSortedSurfaces(loadmodel);
3242 // compute all the mesh information that was not loaded from the file
3243 // TODO: honor smoothing groups somehow?
3244 if (loadmodel->surfmesh.data_element3s)
3245 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3246 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3247 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3248 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);
3249 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);
3250 if (loadmodel->surfmesh.data_neighbor3i)
3251 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
3252 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3253 if(mod_alias_force_animated.string[0])
3254 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3256 if (!loadmodel->surfmesh.isanimated)
3258 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3259 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3260 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3261 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3262 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3263 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3266 // because shaders can do somewhat unexpected things, check for unusual features now
3267 for (i = 0;i < loadmodel->num_textures;i++)
3269 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3270 mod->DrawSky = R_Q1BSP_DrawSky;
3271 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3272 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
3276 void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
3278 unsigned char *data;
3280 const unsigned char *pbase, *pend;
3282 skinfile_t *skinfiles;
3283 int i, j, k, meshvertices, meshtriangles;
3284 float biggestorigin;
3285 const unsigned int *inelements;
3287 const int *inneighbors;
3289 float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3290 // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3291 const float *vnormal = NULL;
3292 const float *vposition = NULL;
3293 const float *vtangent = NULL;
3294 const float *vtexcoord = NULL;
3295 const float *vcolor4f = NULL;
3296 const unsigned char *vblendindexes = NULL;
3297 const unsigned char *vblendweights = NULL;
3298 const unsigned char *vcolor4ub = NULL;
3299 const unsigned short *framedata = NULL;
3300 // temporary memory allocations (because the data in the file may be misaligned)
3301 iqmanim_t *anims = NULL;
3302 iqmbounds_t *bounds = NULL;
3303 iqmjoint1_t *joint1 = NULL;
3304 iqmjoint_t *joint = NULL;
3305 iqmmesh_t *meshes = NULL;
3306 iqmpose1_t *pose1 = NULL;
3307 iqmpose_t *pose = NULL;
3308 iqmvertexarray_t *vas = NULL;
3310 pbase = (unsigned char *)buffer;
3311 pend = (unsigned char *)bufferend;
3313 if (pbase + sizeof(iqmheader_t) > pend)
3314 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3316 // copy struct (otherwise it may be misaligned)
3317 // LordHavoc: okay it's definitely not misaligned here, but for consistency...
3318 memcpy(&header, pbase, sizeof(iqmheader_t));
3320 if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3321 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3322 if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3323 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3325 loadmodel->modeldatatypestring = "IQM";
3327 loadmodel->type = mod_alias;
3328 loadmodel->synctype = ST_RAND;
3331 header.version = LittleLong(header.version);
3332 header.filesize = LittleLong(header.filesize);
3333 header.flags = LittleLong(header.flags);
3334 header.num_text = LittleLong(header.num_text);
3335 header.ofs_text = LittleLong(header.ofs_text);
3336 header.num_meshes = LittleLong(header.num_meshes);
3337 header.ofs_meshes = LittleLong(header.ofs_meshes);
3338 header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3339 header.num_vertexes = LittleLong(header.num_vertexes);
3340 header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3341 header.num_triangles = LittleLong(header.num_triangles);
3342 header.ofs_triangles = LittleLong(header.ofs_triangles);
3343 header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3344 header.num_joints = LittleLong(header.num_joints);
3345 header.ofs_joints = LittleLong(header.ofs_joints);
3346 header.num_poses = LittleLong(header.num_poses);
3347 header.ofs_poses = LittleLong(header.ofs_poses);
3348 header.num_anims = LittleLong(header.num_anims);
3349 header.ofs_anims = LittleLong(header.ofs_anims);
3350 header.num_frames = LittleLong(header.num_frames);
3351 header.num_framechannels = LittleLong(header.num_framechannels);
3352 header.ofs_frames = LittleLong(header.ofs_frames);
3353 header.ofs_bounds = LittleLong(header.ofs_bounds);
3354 header.num_comment = LittleLong(header.num_comment);
3355 header.ofs_comment = LittleLong(header.ofs_comment);
3356 header.num_extensions = LittleLong(header.num_extensions);
3357 header.ofs_extensions = LittleLong(header.ofs_extensions);
3359 if (header.version == 1)
3361 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3362 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3364 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3370 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3371 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3373 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3377 if (pbase + header.ofs_text + header.num_text > pend ||
3378 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3379 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3380 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3381 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3382 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3383 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3384 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3385 pbase + header.ofs_comment + header.num_comment > pend)
3387 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3391 // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3392 if (header.num_vertexarrays)
3393 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3394 if (header.num_anims)
3395 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3396 if (header.ofs_bounds)
3397 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3398 if (header.num_meshes)
3399 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3401 for (i = 0;i < (int)header.num_vertexarrays;i++)
3403 iqmvertexarray_t va;
3405 va.type = LittleLong(vas[i].type);
3406 va.flags = LittleLong(vas[i].flags);
3407 va.format = LittleLong(vas[i].format);
3408 va.size = LittleLong(vas[i].size);
3409 va.offset = LittleLong(vas[i].offset);
3410 vsize = header.num_vertexes*va.size;
3413 case IQM_FLOAT: vsize *= sizeof(float); break;
3414 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3417 if (pbase + va.offset + vsize > pend)
3419 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3423 if (va.format == IQM_FLOAT && va.size == 3)
3424 vposition = (const float *)(pbase + va.offset);
3427 if (va.format == IQM_FLOAT && va.size == 2)
3428 vtexcoord = (const float *)(pbase + va.offset);
3431 if (va.format == IQM_FLOAT && va.size == 3)
3432 vnormal = (const float *)(pbase + va.offset);
3435 if (va.format == IQM_FLOAT && va.size == 4)
3436 vtangent = (const float *)(pbase + va.offset);
3438 case IQM_BLENDINDEXES:
3439 if (va.format == IQM_UBYTE && va.size == 4)
3440 vblendindexes = (const unsigned char *)(pbase + va.offset);
3442 case IQM_BLENDWEIGHTS:
3443 if (va.format == IQM_UBYTE && va.size == 4)
3444 vblendweights = (const unsigned char *)(pbase + va.offset);
3447 if (va.format == IQM_FLOAT && va.size == 4)
3448 vcolor4f = (const float *)(pbase + va.offset);
3449 if (va.format == IQM_UBYTE && va.size == 4)
3450 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3454 if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3456 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3460 text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3462 loadmodel->DrawSky = NULL;
3463 loadmodel->DrawAddWaterPlanes = NULL;
3464 loadmodel->Draw = R_Q1BSP_Draw;
3465 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
3466 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
3467 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
3468 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
3469 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
3470 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
3471 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
3472 loadmodel->DrawLight = R_Q1BSP_DrawLight;
3473 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3474 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3475 loadmodel->PointSuperContents = NULL;
3476 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3478 // load external .skin files if present
3479 skinfiles = Mod_LoadSkinFiles();
3480 if (loadmodel->numskins < 1)
3481 loadmodel->numskins = 1;
3483 loadmodel->numframes = max(header.num_anims, 1);
3484 loadmodel->num_bones = header.num_joints;
3485 loadmodel->num_poses = max(header.num_frames, 1);
3486 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header.num_meshes;
3487 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3488 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3490 meshvertices = header.num_vertexes;
3491 meshtriangles = header.num_triangles;
3493 // do most allocations as one merged chunk
3494 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));
3495 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3496 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3497 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3498 loadmodel->surfmesh.num_vertices = meshvertices;
3499 loadmodel->surfmesh.num_triangles = meshtriangles;
3500 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3501 if (r_enableshadowvolumes.integer)
3503 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3505 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3506 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3507 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3508 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3509 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3510 if (vcolor4f || vcolor4ub)
3512 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]);
3514 if (vblendindexes && vblendweights)
3516 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3517 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3519 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3520 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3521 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3522 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3523 if (vblendindexes && vblendweights)
3525 loadmodel->surfmesh.num_blends = 0;
3526 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3528 if (meshvertices <= 65536)
3530 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3532 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3533 if (vblendindexes && vblendweights)
3534 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3536 for (i = 0;i < loadmodel->numskins;i++)
3538 loadmodel->skinscenes[i].firstframe = i;
3539 loadmodel->skinscenes[i].framecount = 1;
3540 loadmodel->skinscenes[i].loop = true;
3541 loadmodel->skinscenes[i].framerate = 10;
3544 // load the bone info
3545 if (header.version == 1)
3547 iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3548 if (loadmodel->num_bones)
3549 joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3550 for (i = 0;i < loadmodel->num_bones;i++)
3552 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3553 joint1[i].name = LittleLong(injoint1[i].name);
3554 joint1[i].parent = LittleLong(injoint1[i].parent);
3555 for (j = 0;j < 3;j++)
3557 joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
3558 joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
3559 joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
3561 strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3562 loadmodel->data_bones[i].parent = joint1[i].parent;
3563 if (loadmodel->data_bones[i].parent >= i)
3564 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3565 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]);
3566 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3567 if (loadmodel->data_bones[i].parent >= 0)
3569 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3570 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3571 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3573 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3578 iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
3579 if (header.num_joints)
3580 joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3581 for (i = 0;i < loadmodel->num_bones;i++)
3583 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3584 joint[i].name = LittleLong(injoint[i].name);
3585 joint[i].parent = LittleLong(injoint[i].parent);
3586 for (j = 0;j < 3;j++)
3588 joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
3589 joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
3590 joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
3592 joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
3593 strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3594 loadmodel->data_bones[i].parent = joint[i].parent;
3595 if (loadmodel->data_bones[i].parent >= i)
3596 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3597 if (joint[i].rotation[3] > 0)
3598 Vector4Negate(joint[i].rotation, joint[i].rotation);
3599 Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3600 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]);
3601 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3602 if (loadmodel->data_bones[i].parent >= 0)
3604 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3605 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3606 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3608 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3612 // set up the animscenes based on the anims
3613 for (i = 0;i < (int)header.num_anims;i++)
3616 anim.name = LittleLong(anims[i].name);
3617 anim.first_frame = LittleLong(anims[i].first_frame);
3618 anim.num_frames = LittleLong(anims[i].num_frames);
3619 anim.framerate = LittleFloat(anims[i].framerate);
3620 anim.flags = LittleLong(anims[i].flags);
3621 strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3622 loadmodel->animscenes[i].firstframe = anim.first_frame;
3623 loadmodel->animscenes[i].framecount = anim.num_frames;
3624 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3625 loadmodel->animscenes[i].framerate = anim.framerate;
3627 if (header.num_anims <= 0)
3629 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3630 loadmodel->animscenes[0].firstframe = 0;
3631 loadmodel->animscenes[0].framecount = 1;
3632 loadmodel->animscenes[0].loop = true;
3633 loadmodel->animscenes[0].framerate = 10;
3636 loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3637 if(mod_alias_force_animated.string[0])
3638 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3641 if (header.version == 1)
3643 iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3644 if (header.num_poses)
3645 pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3646 for (i = 0;i < (int)header.num_poses;i++)
3649 pose1[i].parent = LittleLong(inpose1[i].parent);
3650 pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
3651 for (j = 0;j < 9;j++)
3653 pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
3654 pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
3656 f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3657 f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3658 f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3659 f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3660 f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3661 f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3663 if (header.num_frames <= 0)
3665 for (i = 0;i < loadmodel->num_bones;i++)
3668 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3669 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3670 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3676 iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
3677 if (header.num_poses)
3678 pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3679 for (i = 0;i < (int)header.num_poses;i++)
3682 pose[i].parent = LittleLong(inpose[i].parent);
3683 pose[i].channelmask = LittleLong(inpose[i].channelmask);
3684 for (j = 0;j < 10;j++)
3686 pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
3687 pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
3689 f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3690 f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3691 f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3692 f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3693 f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3694 f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3696 if (header.num_frames <= 0)
3698 for (i = 0;i < loadmodel->num_bones;i++)
3701 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3702 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3703 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3707 loadmodel->num_posescale = biggestorigin / 32767.0f;
3708 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3710 // load the pose data
3711 // this unaligned memory access is safe (LittleShort reads as bytes)
3712 framedata = (const unsigned short *)(pbase + header.ofs_frames);
3713 if (header.version == 1)
3715 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3717 for (j = 0;j < (int)header.num_poses;j++, k++)
3719 float qx, qy, qz, qw;
3720 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));
3721 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));
3722 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));
3723 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3724 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3725 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3726 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3727 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3728 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3729 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3730 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3731 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3732 // skip scale data for now
3733 if(pose1[j].channelmask&64) framedata++;
3734 if(pose1[j].channelmask&128) framedata++;
3735 if(pose1[j].channelmask&256) framedata++;
3738 if (header.num_frames <= 0)
3740 for (i = 0;i < loadmodel->num_bones;i++)
3742 float qx, qy, qz, qw;
3743 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3744 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3745 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3746 qx = joint1[i].rotation[0];
3747 qy = joint1[i].rotation[1];
3748 qz = joint1[i].rotation[2];
3749 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3750 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3751 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3752 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3753 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3754 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3760 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3762 for (j = 0;j < (int)header.num_poses;j++, k++)
3765 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));
3766 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));
3767 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));
3768 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3769 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3770 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3771 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3773 Vector4Negate(rot, rot);
3774 Vector4Normalize2(rot, rot);
3775 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3776 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3777 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3778 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3779 // skip scale data for now
3780 if(pose[j].channelmask&128) framedata++;
3781 if(pose[j].channelmask&256) framedata++;
3782 if(pose[j].channelmask&512) framedata++;
3785 if (header.num_frames <= 0)
3787 for (i = 0;i < loadmodel->num_bones;i++)
3789 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3790 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3791 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3792 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3793 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3794 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3795 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3800 // load bounding box data
3801 if (header.ofs_bounds)
3803 float xyradius = 0, radius = 0;
3804 VectorClear(loadmodel->normalmins);
3805 VectorClear(loadmodel->normalmaxs);
3806 for (i = 0; i < (int)header.num_frames;i++)
3809 bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3810 bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3811 bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3812 bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);
3813 bound.maxs[1] = LittleFloat(bounds[i].maxs[1]);
3814 bound.maxs[2] = LittleFloat(bounds[i].maxs[2]);
3815 bound.xyradius = LittleFloat(bounds[i].xyradius);
3816 bound.radius = LittleFloat(bounds[i].radius);
3819 VectorCopy(bound.mins, loadmodel->normalmins);
3820 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3824 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3825 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3826 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3827 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3828 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3829 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3831 if (bound.xyradius > xyradius)
3832 xyradius = bound.xyradius;
3833 if (bound.radius > radius)
3834 radius = bound.radius;
3836 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3837 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3838 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3839 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3840 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3841 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3842 loadmodel->radius = radius;
3843 loadmodel->radius2 = radius * radius;
3846 // load triangle data
3847 // this unaligned memory access is safe (LittleLong reads as bytes)
3848 inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3849 outelements = loadmodel->surfmesh.data_element3i;
3850 for (i = 0;i < (int)header.num_triangles;i++)
3852 outelements[0] = LittleLong(inelements[0]);
3853 outelements[1] = LittleLong(inelements[1]);
3854 outelements[2] = LittleLong(inelements[2]);
3858 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3860 if (header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
3862 // this unaligned memory access is safe (LittleLong reads as bytes)
3863 inneighbors = (const int *)(pbase + header.ofs_neighbors);
3864 outneighbors = loadmodel->surfmesh.data_neighbor3i;
3865 for (i = 0;i < (int)header.num_triangles;i++)
3867 outneighbors[0] = LittleLong(inneighbors[0]);
3868 outneighbors[1] = LittleLong(inneighbors[1]);
3869 outneighbors[2] = LittleLong(inneighbors[2]);
3876 // this unaligned memory access is safe (LittleFloat reads as bytes)
3877 outvertex = loadmodel->surfmesh.data_vertex3f;
3878 for (i = 0;i < (int)header.num_vertexes;i++)
3880 outvertex[0] = LittleFloat(vposition[0]);
3881 outvertex[1] = LittleFloat(vposition[1]);
3882 outvertex[2] = LittleFloat(vposition[2]);
3887 outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3888 // this unaligned memory access is safe (LittleFloat reads as bytes)
3889 for (i = 0;i < (int)header.num_vertexes;i++)
3891 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3892 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3897 // this unaligned memory access is safe (LittleFloat reads as bytes)
3900 outnormal = loadmodel->surfmesh.data_normal3f;
3901 for (i = 0;i < (int)header.num_vertexes;i++)
3903 outnormal[0] = LittleFloat(vnormal[0]);
3904 outnormal[1] = LittleFloat(vnormal[1]);
3905 outnormal[2] = LittleFloat(vnormal[2]);
3911 // this unaligned memory access is safe (LittleFloat reads as bytes)
3912 if(vnormal && vtangent)
3914 outnormal = loadmodel->surfmesh.data_normal3f;
3915 outsvector = loadmodel->surfmesh.data_svector3f;
3916 outtvector = loadmodel->surfmesh.data_tvector3f;
3917 for (i = 0;i < (int)header.num_vertexes;i++)
3919 outsvector[0] = LittleFloat(vtangent[0]);
3920 outsvector[1] = LittleFloat(vtangent[1]);
3921 outsvector[2] = LittleFloat(vtangent[2]);
3922 if(LittleFloat(vtangent[3]) < 0)
3923 CrossProduct(outsvector, outnormal, outtvector);
3925 CrossProduct(outnormal, outsvector, outtvector);
3933 // this unaligned memory access is safe (all bytes)
3934 if (vblendindexes && vblendweights)
3936 for (i = 0; i < (int)header.num_vertexes;i++)
3938 blendweights_t weights;
3939 memcpy(weights.index, vblendindexes + i*4, 4);
3940 memcpy(weights.influence, vblendweights + i*4, 4);
3941 loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3942 loadmodel->surfmesh.data_skeletalindex4ub[i*4 ] = weights.index[0];
3943 loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3944 loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3945 loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3946 loadmodel->surfmesh.data_skeletalweight4ub[i*4 ] = weights.influence[0];
3947 loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3948 loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3949 loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3955 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3956 // this unaligned memory access is safe (LittleFloat reads as bytes)
3957 for (i = 0;i < (int)header.num_vertexes;i++)
3959 outcolor[0] = LittleFloat(vcolor4f[0]);
3960 outcolor[1] = LittleFloat(vcolor4f[1]);
3961 outcolor[2] = LittleFloat(vcolor4f[2]);
3962 outcolor[3] = LittleFloat(vcolor4f[3]);
3969 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3970 // this unaligned memory access is safe (all bytes)
3971 for (i = 0;i < (int)header.num_vertexes;i++)
3973 outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3974 outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3975 outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3976 outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3983 for (i = 0;i < (int)header.num_meshes;i++)
3986 msurface_t *surface;
3988 mesh.name = LittleLong(meshes[i].name);
3989 mesh.material = LittleLong(meshes[i].material);
3990 mesh.first_vertex = LittleLong(meshes[i].first_vertex);
3991 mesh.num_vertexes = LittleLong(meshes[i].num_vertexes);
3992 mesh.first_triangle = LittleLong(meshes[i].first_triangle);
3993 mesh.num_triangles = LittleLong(meshes[i].num_triangles);
3995 loadmodel->sortedmodelsurfaces[i] = i;
3996 surface = loadmodel->data_surfaces + i;
3997 surface->texture = loadmodel->data_textures + i;
3998 surface->num_firsttriangle = mesh.first_triangle;
3999 surface->num_triangles = mesh.num_triangles;
4000 surface->num_firstvertex = mesh.first_vertex;
4001 surface->num_vertices = mesh.num_vertexes;
4003 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
4006 Mod_FreeSkinFiles(skinfiles);
4007 Mod_MakeSortedSurfaces(loadmodel);
4009 // compute all the mesh information that was not loaded from the file
4010 if (loadmodel->surfmesh.data_element3s)
4011 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
4012 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
4014 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);
4015 if (!vnormal || !vtangent)
4016 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);
4017 if (!header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
4018 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
4019 if (!header.ofs_bounds)
4020 Mod_Alias_CalculateBoundingBox();
4022 if (!loadmodel->surfmesh.isanimated && loadmodel->surfmesh.num_triangles >= 1)
4024 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
4025 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
4026 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
4027 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
4028 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
4029 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
4032 if (joint ) Mem_Free(joint );joint = NULL;
4033 if (joint1 ) Mem_Free(joint1 );joint1 = NULL;
4034 if (pose ) Mem_Free(pose );pose = NULL;
4035 if (pose1 ) Mem_Free(pose1 );pose1 = NULL;
4037 // because shaders can do somewhat unexpected things, check for unusual features now
4038 for (i = 0;i < loadmodel->num_textures;i++)
4040 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
4041 mod->DrawSky = R_Q1BSP_DrawSky;
4042 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
4043 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;