2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "mod_skeletal_animatevertices_generic.h"
26 #include "mod_skeletal_animatevertices_sse.h"
30 static qboolean r_skeletal_use_sse_defined = false;
31 cvar_t r_skeletal_use_sse = {0, "r_skeletal_use_sse", "1", "use SSE for skeletal model animation"};
33 cvar_t r_skeletal_debugbone = {0, "r_skeletal_debugbone", "-1", "development cvar for testing skeletal model code"};
34 cvar_t r_skeletal_debugbonecomponent = {0, "r_skeletal_debugbonecomponent", "3", "development cvar for testing skeletal model code"};
35 cvar_t r_skeletal_debugbonevalue = {0, "r_skeletal_debugbonevalue", "100", "development cvar for testing skeletal model code"};
36 cvar_t r_skeletal_debugtranslatex = {0, "r_skeletal_debugtranslatex", "1", "development cvar for testing skeletal model code"};
37 cvar_t r_skeletal_debugtranslatey = {0, "r_skeletal_debugtranslatey", "1", "development cvar for testing skeletal model code"};
38 cvar_t r_skeletal_debugtranslatez = {0, "r_skeletal_debugtranslatez", "1", "development cvar for testing skeletal model code"};
39 cvar_t mod_alias_supporttagscale = {0, "mod_alias_supporttagscale", "1", "support scaling factors in bone/tag attachment matrices as supported by MD3"};
40 cvar_t mod_alias_force_animated = {0, "mod_alias_force_animated", "", "if set to an non-empty string, overrides the is-animated flag of any alias models (for benchmarking)"};
42 float mod_md3_sin[320];
44 static size_t Mod_Skeletal_AnimateVertices_maxbonepose = 0;
45 static void *Mod_Skeletal_AnimateVertices_bonepose = NULL;
46 void Mod_Skeletal_FreeBuffers(void)
48 if(Mod_Skeletal_AnimateVertices_bonepose)
49 Mem_Free(Mod_Skeletal_AnimateVertices_bonepose);
50 Mod_Skeletal_AnimateVertices_maxbonepose = 0;
51 Mod_Skeletal_AnimateVertices_bonepose = NULL;
53 void *Mod_Skeletal_AnimateVertices_AllocBuffers(size_t nbytes)
55 if(Mod_Skeletal_AnimateVertices_maxbonepose < nbytes)
57 if(Mod_Skeletal_AnimateVertices_bonepose)
58 Mem_Free(Mod_Skeletal_AnimateVertices_bonepose);
59 Mod_Skeletal_AnimateVertices_bonepose = Z_Malloc(nbytes);
60 Mod_Skeletal_AnimateVertices_maxbonepose = nbytes;
62 return Mod_Skeletal_AnimateVertices_bonepose;
65 void Mod_Skeletal_BuildTransforms(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT bonepose, float * RESTRICT boneposerelative)
71 bonepose = (float * RESTRICT) Mod_Skeletal_AnimateVertices_AllocBuffers(sizeof(float[12]) * model->num_bones);
73 if (skeleton && !skeleton->relativetransforms)
76 // interpolate matrices
79 for (i = 0;i < model->num_bones;i++)
81 Matrix4x4_ToArray12FloatD3D(&skeleton->relativetransforms[i], m);
82 if (model->data_bones[i].parent >= 0)
83 R_ConcatTransforms(bonepose + model->data_bones[i].parent * 12, m, bonepose + i * 12);
85 memcpy(bonepose + i * 12, m, sizeof(m));
87 // create a relative deformation matrix to describe displacement
88 // from the base mesh, which is used by the actual weighting
89 R_ConcatTransforms(bonepose + i * 12, model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12);
94 for (i = 0;i < model->num_bones;i++)
96 // blend by transform each quaternion/translation into a dual-quaternion first, then blending
97 const short * RESTRICT firstpose7s = model->data_poses7s + 7 * (frameblend[0].subframe * model->num_bones + i);
98 float firstlerp = frameblend[0].lerp,
99 firsttx = firstpose7s[0], firstty = firstpose7s[1], firsttz = firstpose7s[2],
100 rx = firstpose7s[3] * firstlerp,
101 ry = firstpose7s[4] * firstlerp,
102 rz = firstpose7s[5] * firstlerp,
103 rw = firstpose7s[6] * firstlerp,
104 dx = firsttx*rw + firstty*rz - firsttz*ry,
105 dy = -firsttx*rz + firstty*rw + firsttz*rx,
106 dz = firsttx*ry - firstty*rx + firsttz*rw,
107 dw = -firsttx*rx - firstty*ry - firsttz*rz,
108 scale, sx, sy, sz, sw;
109 for (blends = 1;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
111 const short * RESTRICT blendpose7s = model->data_poses7s + 7 * (frameblend[blends].subframe * model->num_bones + i);
112 float blendlerp = frameblend[blends].lerp,
113 blendtx = blendpose7s[0], blendty = blendpose7s[1], blendtz = blendpose7s[2],
114 qx = blendpose7s[3], qy = blendpose7s[4], qz = blendpose7s[5], qw = blendpose7s[6];
115 if(rx*qx + ry*qy + rz*qz + rw*qw < 0) blendlerp = -blendlerp;
124 dx += blendtx*qw + blendty*qz - blendtz*qy;
125 dy += -blendtx*qz + blendty*qw + blendtz*qx;
126 dz += blendtx*qy - blendty*qx + blendtz*qw;
127 dw += -blendtx*qx - blendty*qy - blendtz*qz;
129 // generate a matrix from the dual-quaternion, implicitly normalizing it in the process
130 scale = 1.0f / (rx*rx + ry*ry + rz*rz + rw*rw);
135 m[0] = sw*rw + sx*rx - sy*ry - sz*rz;
136 m[1] = 2*(sx*ry - sw*rz);
137 m[2] = 2*(sx*rz + sw*ry);
138 m[3] = model->num_posescale*(dx*sw - dy*sz + dz*sy - dw*sx);
139 m[4] = 2*(sx*ry + sw*rz);
140 m[5] = sw*rw + sy*ry - sx*rx - sz*rz;
141 m[6] = 2*(sy*rz - sw*rx);
142 m[7] = model->num_posescale*(dx*sz + dy*sw - dz*sx - dw*sy);
143 m[8] = 2*(sx*rz - sw*ry);
144 m[9] = 2*(sy*rz + sw*rx);
145 m[10] = sw*rw + sz*rz - sx*rx - sy*ry;
146 m[11] = model->num_posescale*(dy*sx + dz*sw - dx*sy - dw*sz);
147 if (i == r_skeletal_debugbone.integer)
148 m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value;
149 m[3] *= r_skeletal_debugtranslatex.value;
150 m[7] *= r_skeletal_debugtranslatey.value;
151 m[11] *= r_skeletal_debugtranslatez.value;
152 if (model->data_bones[i].parent >= 0)
153 R_ConcatTransforms(bonepose + model->data_bones[i].parent * 12, m, bonepose + i * 12);
155 memcpy(bonepose + i * 12, m, sizeof(m));
156 // create a relative deformation matrix to describe displacement
157 // from the base mesh, which is used by the actual weighting
158 R_ConcatTransforms(bonepose + i * 12, model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12);
163 static void Mod_Skeletal_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
166 if (!model->surfmesh.num_vertices)
169 if (!model->num_bones)
171 if (vertex3f) memcpy(vertex3f, model->surfmesh.data_vertex3f, model->surfmesh.num_vertices*sizeof(float[3]));
172 if (normal3f) memcpy(normal3f, model->surfmesh.data_normal3f, model->surfmesh.num_vertices*sizeof(float[3]));
173 if (svector3f) memcpy(svector3f, model->surfmesh.data_svector3f, model->surfmesh.num_vertices*sizeof(float[3]));
174 if (tvector3f) memcpy(tvector3f, model->surfmesh.data_tvector3f, model->surfmesh.num_vertices*sizeof(float[3]));
179 if(r_skeletal_use_sse_defined)
180 if(r_skeletal_use_sse.integer)
182 Mod_Skeletal_AnimateVertices_SSE(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f);
186 Mod_Skeletal_AnimateVertices_Generic(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f);
189 void Mod_AliasInit (void)
192 Cvar_RegisterVariable(&r_skeletal_debugbone);
193 Cvar_RegisterVariable(&r_skeletal_debugbonecomponent);
194 Cvar_RegisterVariable(&r_skeletal_debugbonevalue);
195 Cvar_RegisterVariable(&r_skeletal_debugtranslatex);
196 Cvar_RegisterVariable(&r_skeletal_debugtranslatey);
197 Cvar_RegisterVariable(&r_skeletal_debugtranslatez);
198 Cvar_RegisterVariable(&mod_alias_supporttagscale);
199 Cvar_RegisterVariable(&mod_alias_force_animated);
200 for (i = 0;i < 320;i++)
201 mod_md3_sin[i] = sin(i * M_PI * 2.0f / 256.0);
205 Con_Printf("Skeletal animation uses SSE code path\n");
206 r_skeletal_use_sse_defined = true;
207 Cvar_RegisterVariable(&r_skeletal_use_sse);
210 Con_Printf("Skeletal animation uses generic code path (SSE disabled or not detected)\n");
212 Con_Printf("Skeletal animation uses generic code path (SSE not compiled in)\n");
216 static int Mod_Skeletal_AddBlend(dp_model_t *model, const blendweights_t *newweights)
219 blendweights_t *weights;
220 if(!newweights->influence[1])
221 return newweights->index[0];
222 weights = model->surfmesh.data_blendweights;
223 for (i = 0;i < model->surfmesh.num_blends;i++, weights++)
225 if (!memcmp(weights, newweights, sizeof(blendweights_t)))
226 return model->num_bones + i;
228 model->surfmesh.num_blends++;
229 memcpy(weights, newweights, sizeof(blendweights_t));
230 return model->num_bones + i;
233 static int Mod_Skeletal_CompressBlend(dp_model_t *model, const int *newindex, const float *newinfluence)
237 blendweights_t newweights;
241 for (i = 0;i < 4;i++)
242 scale += newinfluence[i];
243 scale = 255.0f / scale;
245 for (i = 0;i < 4;i++)
247 newweights.index[i] = newindex[i];
248 newweights.influence[i] = (unsigned char)(newinfluence[i] * scale);
249 total += newweights.influence[i];
253 for (i = 0;i < 4;i++)
255 if(newweights.influence[i] > 0 && total > 255)
257 newweights.influence[i]--;
264 for (i = 0; i < 4;i++)
266 if(newweights.influence[i] < 255 && total < 255)
268 newweights.influence[i]++;
273 return Mod_Skeletal_AddBlend(model, &newweights);
276 static void Mod_MD3_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
279 int i, numblends, blendnum;
280 int numverts = model->surfmesh.num_vertices;
282 for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
284 //VectorMA(translate, model->surfmesh.num_morphmdlframetranslate, frameblend[blendnum].lerp, translate);
285 if (frameblend[blendnum].lerp > 0)
286 numblends = blendnum + 1;
288 // special case for the first blend because it avoids some adds and the need to memset the arrays first
289 for (blendnum = 0;blendnum < numblends;blendnum++)
291 const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].subframe;
294 float scale = frameblend[blendnum].lerp * (1.0f / 64.0f);
297 for (i = 0;i < numverts;i++)
299 vertex3f[i * 3 + 0] = verts[i].origin[0] * scale;
300 vertex3f[i * 3 + 1] = verts[i].origin[1] * scale;
301 vertex3f[i * 3 + 2] = verts[i].origin[2] * scale;
306 for (i = 0;i < numverts;i++)
308 vertex3f[i * 3 + 0] += verts[i].origin[0] * scale;
309 vertex3f[i * 3 + 1] += verts[i].origin[1] * scale;
310 vertex3f[i * 3 + 2] += verts[i].origin[2] * scale;
314 // the yaw and pitch stored in md3 models are 8bit quantized angles
315 // (0-255), and as such a lookup table is very well suited to
316 // decoding them, and since cosine is equivalent to sine with an
317 // extra 45 degree rotation, this uses one lookup table for both
318 // sine and cosine with a +64 bias to get cosine.
321 float lerp = frameblend[blendnum].lerp;
324 for (i = 0;i < numverts;i++)
326 normal3f[i * 3 + 0] = mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch ] * lerp;
327 normal3f[i * 3 + 1] = mod_md3_sin[verts[i].yaw ] * mod_md3_sin[verts[i].pitch ] * lerp;
328 normal3f[i * 3 + 2] = mod_md3_sin[verts[i].pitch + 64] * lerp;
333 for (i = 0;i < numverts;i++)
335 normal3f[i * 3 + 0] += mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch ] * lerp;
336 normal3f[i * 3 + 1] += mod_md3_sin[verts[i].yaw ] * mod_md3_sin[verts[i].pitch ] * lerp;
337 normal3f[i * 3 + 2] += mod_md3_sin[verts[i].pitch + 64] * lerp;
343 const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
344 float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
347 for (i = 0;i < numverts;i++, texvecvert++)
349 VectorScale(texvecvert->svec, f, svector3f + i*3);
350 VectorScale(texvecvert->tvec, f, tvector3f + i*3);
355 for (i = 0;i < numverts;i++, texvecvert++)
357 VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
358 VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
364 static void Mod_MDL_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
367 int i, numblends, blendnum;
368 int numverts = model->surfmesh.num_vertices;
370 VectorClear(translate);
372 // blend the frame translates to avoid redundantly doing so on each vertex
373 // (a bit of a brain twister but it works)
374 for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
376 if (model->surfmesh.data_morphmd2framesize6f)
377 VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6 + 3, translate);
379 VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.num_morphmdlframetranslate, translate);
380 if (frameblend[blendnum].lerp > 0)
381 numblends = blendnum + 1;
383 // special case for the first blend because it avoids some adds and the need to memset the arrays first
384 for (blendnum = 0;blendnum < numblends;blendnum++)
386 const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].subframe;
390 if (model->surfmesh.data_morphmd2framesize6f)
391 VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6, frameblend[blendnum].lerp, scale);
393 VectorScale(model->surfmesh.num_morphmdlframescale, frameblend[blendnum].lerp, scale);
396 for (i = 0;i < numverts;i++)
398 vertex3f[i * 3 + 0] = translate[0] + verts[i].v[0] * scale[0];
399 vertex3f[i * 3 + 1] = translate[1] + verts[i].v[1] * scale[1];
400 vertex3f[i * 3 + 2] = translate[2] + verts[i].v[2] * scale[2];
405 for (i = 0;i < numverts;i++)
407 vertex3f[i * 3 + 0] += verts[i].v[0] * scale[0];
408 vertex3f[i * 3 + 1] += verts[i].v[1] * scale[1];
409 vertex3f[i * 3 + 2] += verts[i].v[2] * scale[2];
413 // the vertex normals in mdl models are an index into a table of
414 // 162 unique values, this very crude quantization reduces the
415 // vertex normal to only one byte, which saves a lot of space but
416 // also makes lighting pretty coarse
419 float lerp = frameblend[blendnum].lerp;
422 for (i = 0;i < numverts;i++)
424 const float *vn = m_bytenormals[verts[i].lightnormalindex];
425 VectorScale(vn, lerp, normal3f + i*3);
430 for (i = 0;i < numverts;i++)
432 const float *vn = m_bytenormals[verts[i].lightnormalindex];
433 VectorMA(normal3f + i*3, lerp, vn, normal3f + i*3);
439 const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
440 float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
443 for (i = 0;i < numverts;i++, texvecvert++)
445 VectorScale(texvecvert->svec, f, svector3f + i*3);
446 VectorScale(texvecvert->tvec, f, tvector3f + i*3);
451 for (i = 0;i < numverts;i++, texvecvert++)
453 VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
454 VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
461 int Mod_Alias_GetTagMatrix(const dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, matrix4x4_t *outmatrix)
464 matrix4x4_t parentbonematrix;
465 matrix4x4_t tempbonematrix;
466 matrix4x4_t bonematrix;
467 matrix4x4_t blendmatrix;
474 *outmatrix = identitymatrix;
475 if (skeleton && skeleton->relativetransforms)
477 if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
479 *outmatrix = skeleton->relativetransforms[tagindex];
480 while ((tagindex = model->data_bones[tagindex].parent) >= 0)
483 Matrix4x4_Concat(outmatrix, &skeleton->relativetransforms[tagindex], &temp);
486 else if (model->num_bones)
488 if (tagindex < 0 || tagindex >= model->num_bones)
490 Matrix4x4_Clear(&blendmatrix);
491 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
493 lerp = frameblend[blendindex].lerp;
494 Matrix4x4_FromBonePose7s(&bonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + tagindex));
495 parenttagindex = tagindex;
496 while ((parenttagindex = model->data_bones[parenttagindex].parent) >= 0)
498 Matrix4x4_FromBonePose7s(&parentbonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + parenttagindex));
499 tempbonematrix = bonematrix;
500 Matrix4x4_Concat(&bonematrix, &parentbonematrix, &tempbonematrix);
502 Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
504 *outmatrix = blendmatrix;
506 else if (model->num_tags)
508 if (tagindex < 0 || tagindex >= model->num_tags)
510 for (k = 0;k < 12;k++)
512 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
514 lerp = frameblend[blendindex].lerp;
515 input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
516 for (k = 0;k < 12;k++)
517 blendtag[k] += input[k] * lerp;
519 Matrix4x4_FromArray12FloatGL(outmatrix, blendtag);
522 if(!mod_alias_supporttagscale.integer)
523 Matrix4x4_Normalize3(outmatrix, outmatrix);
528 int Mod_Alias_GetExtendedTagInfoForIndex(const dp_model_t *model, unsigned int skin, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
533 matrix4x4_t bonematrix;
534 matrix4x4_t blendmatrix;
538 if (skeleton && skeleton->relativetransforms)
540 if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
542 *parentindex = skeleton->model->data_bones[tagindex].parent;
543 *tagname = skeleton->model->data_bones[tagindex].name;
544 *tag_localmatrix = skeleton->relativetransforms[tagindex];
547 else if (model->num_bones)
549 if (tagindex < 0 || tagindex >= model->num_bones)
551 *parentindex = model->data_bones[tagindex].parent;
552 *tagname = model->data_bones[tagindex].name;
553 Matrix4x4_Clear(&blendmatrix);
554 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
556 lerp = frameblend[blendindex].lerp;
557 Matrix4x4_FromBonePose7s(&bonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + tagindex));
558 Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
560 *tag_localmatrix = blendmatrix;
563 else if (model->num_tags)
565 if (tagindex < 0 || tagindex >= model->num_tags)
568 *tagname = model->data_tags[tagindex].name;
569 for (k = 0;k < 12;k++)
571 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
573 lerp = frameblend[blendindex].lerp;
574 input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
575 for (k = 0;k < 12;k++)
576 blendtag[k] += input[k] * lerp;
578 Matrix4x4_FromArray12FloatGL(tag_localmatrix, blendtag);
585 int Mod_Alias_GetTagIndexForName(const dp_model_t *model, unsigned int skin, const char *tagname)
588 if(skin >= (unsigned int)model->numskins)
590 if (model->num_bones)
591 for (i = 0;i < model->num_bones;i++)
592 if (!strcasecmp(tagname, model->data_bones[i].name))
595 for (i = 0;i < model->num_tags;i++)
596 if (!strcasecmp(tagname, model->data_tags[i].name))
601 static void Mod_BuildBaseBonePoses(void)
604 matrix4x4_t *basebonepose;
605 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
606 matrix4x4_t bonematrix;
607 matrix4x4_t tempbonematrix;
608 if (!loadmodel->num_bones)
610 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
611 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
613 Matrix4x4_FromBonePose7s(&bonematrix, loadmodel->num_posescale, loadmodel->data_poses7s + 7 * boneindex);
614 if (loadmodel->data_bones[boneindex].parent >= 0)
616 tempbonematrix = bonematrix;
617 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
619 basebonepose[boneindex] = bonematrix;
620 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
621 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
623 Mem_Free(basebonepose);
626 static qboolean Mod_Alias_CalculateBoundingBox(void)
629 qboolean firstvertex = true;
630 float dist, yawradius, radius;
632 qboolean isanimated = false;
633 VectorClear(loadmodel->normalmins);
634 VectorClear(loadmodel->normalmaxs);
637 if (loadmodel->AnimateVertices)
639 float *vertex3f, *refvertex3f;
640 frameblend_t frameblend[MAX_FRAMEBLENDS];
641 memset(frameblend, 0, sizeof(frameblend));
642 frameblend[0].lerp = 1;
643 vertex3f = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]) * 2);
645 for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++)
647 loadmodel->AnimateVertices(loadmodel, frameblend, NULL, vertex3f, NULL, NULL, NULL);
650 // make a copy of the first frame for comparing all others
651 refvertex3f = vertex3f + loadmodel->surfmesh.num_vertices * 3;
652 memcpy(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
656 if (!isanimated && memcmp(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3])))
659 for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
664 VectorCopy(v, loadmodel->normalmins);
665 VectorCopy(v, loadmodel->normalmaxs);
669 if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
670 if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
671 if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
672 if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
673 if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
674 if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
676 dist = v[0] * v[0] + v[1] * v[1];
677 if (yawradius < dist)
689 for (vnum = 0, v = loadmodel->surfmesh.data_vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
694 VectorCopy(v, loadmodel->normalmins);
695 VectorCopy(v, loadmodel->normalmaxs);
699 if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
700 if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
701 if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
702 if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
703 if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
704 if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
706 dist = v[0] * v[0] + v[1] * v[1];
707 if (yawradius < dist)
714 radius = sqrt(radius);
715 yawradius = sqrt(yawradius);
716 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius;
717 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = yawradius;
718 loadmodel->yawmins[2] = loadmodel->normalmins[2];
719 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
720 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
721 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
722 loadmodel->radius = radius;
723 loadmodel->radius2 = radius * radius;
727 static void Mod_Alias_MorphMesh_CompileFrames(void)
730 frameblend_t frameblend[MAX_FRAMEBLENDS];
731 unsigned char *datapointer;
732 memset(frameblend, 0, sizeof(frameblend));
733 frameblend[0].lerp = 1;
734 datapointer = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * (sizeof(float[3]) * 4 + loadmodel->surfmesh.num_morphframes * sizeof(texvecvertex_t)));
735 loadmodel->surfmesh.data_vertex3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
736 loadmodel->surfmesh.data_svector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
737 loadmodel->surfmesh.data_tvector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
738 loadmodel->surfmesh.data_normal3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
739 loadmodel->surfmesh.data_morphtexvecvertex = (texvecvertex_t *)datapointer;datapointer += loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices * sizeof(texvecvertex_t);
740 // this counts down from the last frame to the first so that the final data in surfmesh is for frame zero (which is what the renderer expects to be there)
741 for (i = loadmodel->surfmesh.num_morphframes-1;i >= 0;i--)
743 frameblend[0].subframe = i;
744 loadmodel->AnimateVertices(loadmodel, frameblend, NULL, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_normal3f, NULL, NULL);
745 Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
746 // encode the svector and tvector in 3 byte format for permanent storage
747 for (j = 0;j < loadmodel->surfmesh.num_vertices;j++)
749 VectorScaleCast(loadmodel->surfmesh.data_svector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].svec);
750 VectorScaleCast(loadmodel->surfmesh.data_tvector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].tvec);
755 static void Mod_MDLMD2MD3_TraceLine(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask)
758 float segmentmins[3], segmentmaxs[3];
760 float vertex3fbuf[1024*3];
761 float *vertex3f = vertex3fbuf;
762 memset(trace, 0, sizeof(*trace));
764 trace->hitsupercontentsmask = hitsupercontentsmask;
765 if (model->surfmesh.num_vertices > 1024)
766 vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
767 segmentmins[0] = min(start[0], end[0]) - 1;
768 segmentmins[1] = min(start[1], end[1]) - 1;
769 segmentmins[2] = min(start[2], end[2]) - 1;
770 segmentmaxs[0] = max(start[0], end[0]) + 1;
771 segmentmaxs[1] = max(start[1], end[1]) + 1;
772 segmentmaxs[2] = max(start[2], end[2]) + 1;
773 model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
774 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
775 Collision_TraceLineTriangleMeshFloat(trace, start, end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
776 if (vertex3f != vertex3fbuf)
780 static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask)
783 vec3_t shiftstart, shiftend;
784 float segmentmins[3], segmentmaxs[3];
786 float vertex3fbuf[1024*3];
787 float *vertex3f = vertex3fbuf;
788 colboxbrushf_t thisbrush_start, thisbrush_end;
789 vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
791 if (VectorCompare(boxmins, boxmaxs))
793 VectorAdd(start, boxmins, shiftstart);
794 VectorAdd(end, boxmins, shiftend);
795 Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask);
796 VectorSubtract(trace->endpos, boxmins, trace->endpos);
800 // box trace, performed as brush trace
801 memset(trace, 0, sizeof(*trace));
803 trace->hitsupercontentsmask = hitsupercontentsmask;
804 if (model->surfmesh.num_vertices > 1024)
805 vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
806 segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1;
807 segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1;
808 segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1;
809 segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1;
810 segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1;
811 segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1;
812 VectorAdd(start, boxmins, boxstartmins);
813 VectorAdd(start, boxmaxs, boxstartmaxs);
814 VectorAdd(end, boxmins, boxendmins);
815 VectorAdd(end, boxmaxs, boxendmaxs);
816 Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL);
817 Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL);
818 model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
819 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
820 Collision_TraceBrushTriangleMeshFloat(trace, &thisbrush_start.brush, &thisbrush_end.brush, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
821 if (vertex3f != vertex3fbuf)
825 static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap)
828 for (i = 0;i < inverts;i++)
830 if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
832 j = vertremap[i]; // not onseam
835 j = vertremap[i+inverts]; // onseam
841 static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *vertremap)
843 int i, f, pose, groupframes;
845 daliasframetype_t *pframetype;
846 daliasframe_t *pinframe;
847 daliasgroup_t *group;
848 daliasinterval_t *intervals;
851 scene = loadmodel->animscenes;
852 for (f = 0;f < loadmodel->numframes;f++)
854 pframetype = (daliasframetype_t *)datapointer;
855 datapointer += sizeof(daliasframetype_t);
856 if (LittleLong (pframetype->type) == ALIAS_SINGLE)
858 // a single frame is still treated as a group
865 group = (daliasgroup_t *)datapointer;
866 datapointer += sizeof(daliasgroup_t);
867 groupframes = LittleLong (group->numframes);
869 // intervals (time per frame)
870 intervals = (daliasinterval_t *)datapointer;
871 datapointer += sizeof(daliasinterval_t) * groupframes;
873 interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
874 if (interval < 0.01f)
876 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
881 // get scene name from first frame
882 pinframe = (daliasframe_t *)datapointer;
884 strlcpy(scene->name, pinframe->name, sizeof(scene->name));
885 scene->firstframe = pose;
886 scene->framecount = groupframes;
887 scene->framerate = 1.0f / interval;
892 for (i = 0;i < groupframes;i++)
894 datapointer += sizeof(daliasframe_t);
895 Mod_ConvertAliasVerts(inverts, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphmdlvertex + pose * loadmodel->surfmesh.num_vertices, vertremap);
896 datapointer += sizeof(trivertx_t) * inverts;
902 static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *skinframe)
904 if (cls.state == ca_dedicated)
908 skinframe = R_SkinFrame_LoadMissing();
909 memset(texture, 0, sizeof(*texture));
910 texture->currentframe = texture;
911 //texture->animated = false;
912 texture->numskinframes = 1;
913 texture->skinframerate = 1;
914 texture->skinframes[0] = skinframe;
915 texture->currentskinframe = skinframe;
916 //texture->backgroundnumskinframes = 0;
917 //texture->customblendfunc[0] = 0;
918 //texture->customblendfunc[1] = 0;
919 //texture->surfaceflags = 0;
920 //texture->supercontents = 0;
921 //texture->surfaceparms = 0;
922 //texture->textureflags = 0;
924 texture->basematerialflags = MATERIALFLAG_WALL;
925 texture->basealpha = 1.0f;
926 if (texture->currentskinframe->hasalpha)
927 texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
928 texture->currentmaterialflags = texture->basematerialflags;
929 texture->offsetmapping = OFFSETMAPPING_DEFAULT;
930 texture->offsetscale = 1;
931 texture->offsetbias = 0;
932 texture->specularscalemod = 1;
933 texture->specularpowermod = 1;
934 texture->surfaceflags = 0;
935 texture->supercontents = SUPERCONTENTS_SOLID;
936 if (!(texture->basematerialflags & MATERIALFLAG_BLENDED))
937 texture->supercontents |= SUPERCONTENTS_OPAQUE;
938 texture->transparentsort = TRANSPARENTSORT_DISTANCE;
939 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
940 // JUST GREP FOR "specularscalemod = 1".
943 void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
946 char stripbuf[MAX_QPATH];
947 skinfileitem_t *skinfileitem;
948 if(developer_extra.integer)
949 Con_DPrintf("Looking up texture for %s (default: %s)\n", meshname, shadername);
952 // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
953 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
955 memset(skin, 0, sizeof(*skin));
957 for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
959 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
960 if (!strcmp(skinfileitem->name, meshname))
962 Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf));
963 if(developer_extra.integer)
964 Con_DPrintf("--> got %s from skin file\n", stripbuf);
965 Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
971 // don't render unmentioned meshes
972 Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
973 if(developer_extra.integer)
974 Con_DPrintf("--> skipping\n");
975 skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW;
981 if(developer_extra.integer)
982 Con_DPrintf("--> using default\n");
983 Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf));
984 Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
988 #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);
989 #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);
990 void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
992 int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
993 float scales, scalet, interval;
997 stvert_t *pinstverts;
998 dtriangle_t *pintriangles;
999 daliasskintype_t *pinskintype;
1000 daliasskingroup_t *pinskingroup;
1001 daliasskininterval_t *pinskinintervals;
1002 daliasframetype_t *pinframetype;
1003 daliasgroup_t *pinframegroup;
1004 unsigned char *datapointer, *startframes, *startskins;
1005 char name[MAX_QPATH];
1006 skinframe_t *tempskinframe;
1007 animscene_t *tempskinscenes;
1008 texture_t *tempaliasskins;
1010 int *vertonseam, *vertremap;
1011 skinfile_t *skinfiles;
1014 datapointer = (unsigned char *)buffer;
1015 pinmodel = (mdl_t *)datapointer;
1016 datapointer += sizeof(mdl_t);
1018 version = LittleLong (pinmodel->version);
1019 if (version != ALIAS_VERSION)
1020 Host_Error ("%s has wrong version number (%i should be %i)",
1021 loadmodel->name, version, ALIAS_VERSION);
1023 loadmodel->modeldatatypestring = "MDL";
1025 loadmodel->type = mod_alias;
1026 loadmodel->DrawSky = NULL;
1027 loadmodel->DrawAddWaterPlanes = NULL;
1028 loadmodel->Draw = R_Q1BSP_Draw;
1029 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1030 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1031 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1032 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1033 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1034 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1035 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1036 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1037 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1038 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1039 // FIXME add TraceBrush!
1040 loadmodel->PointSuperContents = NULL;
1041 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1043 loadmodel->num_surfaces = 1;
1044 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1045 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
1046 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1047 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1048 loadmodel->sortedmodelsurfaces[0] = 0;
1050 loadmodel->numskins = LittleLong(pinmodel->numskins);
1051 BOUNDI(loadmodel->numskins,0,65536);
1052 skinwidth = LittleLong (pinmodel->skinwidth);
1053 BOUNDI(skinwidth,0,65536);
1054 skinheight = LittleLong (pinmodel->skinheight);
1055 BOUNDI(skinheight,0,65536);
1056 numverts = LittleLong(pinmodel->numverts);
1057 BOUNDI(numverts,0,65536);
1058 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
1059 BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
1060 loadmodel->numframes = LittleLong(pinmodel->numframes);
1061 BOUNDI(loadmodel->numframes,0,65536);
1062 loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
1063 BOUNDI((int)loadmodel->synctype,0,2);
1064 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1065 i = LittleLong (pinmodel->flags);
1066 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1068 for (i = 0;i < 3;i++)
1070 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
1071 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
1074 startskins = datapointer;
1076 for (i = 0;i < loadmodel->numskins;i++)
1078 pinskintype = (daliasskintype_t *)datapointer;
1079 datapointer += sizeof(daliasskintype_t);
1080 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
1084 pinskingroup = (daliasskingroup_t *)datapointer;
1085 datapointer += sizeof(daliasskingroup_t);
1086 groupskins = LittleLong(pinskingroup->numskins);
1087 datapointer += sizeof(daliasskininterval_t) * groupskins;
1090 for (j = 0;j < groupskins;j++)
1092 datapointer += skinwidth * skinheight;
1097 pinstverts = (stvert_t *)datapointer;
1098 datapointer += sizeof(stvert_t) * numverts;
1100 pintriangles = (dtriangle_t *)datapointer;
1101 datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
1103 startframes = datapointer;
1104 loadmodel->surfmesh.num_morphframes = 0;
1105 for (i = 0;i < loadmodel->numframes;i++)
1107 pinframetype = (daliasframetype_t *)datapointer;
1108 datapointer += sizeof(daliasframetype_t);
1109 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1113 pinframegroup = (daliasgroup_t *)datapointer;
1114 datapointer += sizeof(daliasgroup_t);
1115 groupframes = LittleLong(pinframegroup->numframes);
1116 datapointer += sizeof(daliasinterval_t) * groupframes;
1119 for (j = 0;j < groupframes;j++)
1121 datapointer += sizeof(daliasframe_t);
1122 datapointer += sizeof(trivertx_t) * numverts;
1123 loadmodel->surfmesh.num_morphframes++;
1126 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1128 // store texture coordinates into temporary array, they will be stored
1129 // after usage is determined (triangle data)
1130 vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1131 vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1132 vertonseam = vertremap + numverts * 2;
1134 scales = 1.0 / skinwidth;
1135 scalet = 1.0 / skinheight;
1136 for (i = 0;i < numverts;i++)
1138 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1139 vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales;
1140 vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet;
1141 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1142 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1145 // load triangle data
1146 loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1148 // read the triangle elements
1149 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1150 for (j = 0;j < 3;j++)
1151 loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1152 // validate (note numverts is used because this is the original data)
1153 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1154 // now butcher the elements according to vertonseam and tri->facesfront
1155 // and then compact the vertex set to remove duplicates
1156 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1157 if (!LittleLong(pintriangles[i].facesfront)) // backface
1158 for (j = 0;j < 3;j++)
1159 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1160 loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1162 // (this uses vertremap to count usage to save some memory)
1163 for (i = 0;i < numverts*2;i++)
1165 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1166 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1167 // build remapping table and compact array
1168 loadmodel->surfmesh.num_vertices = 0;
1169 for (i = 0;i < numverts*2;i++)
1173 vertremap[i] = loadmodel->surfmesh.num_vertices;
1174 vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1175 vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1176 loadmodel->surfmesh.num_vertices++;
1179 vertremap[i] = -1; // not used at all
1181 // remap the elements to the new vertex set
1182 for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1183 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1184 // store the texture coordinates
1185 loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1186 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1188 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1189 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1192 // generate ushort elements array if possible
1193 if (loadmodel->surfmesh.num_vertices <= 65536)
1194 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1195 if (loadmodel->surfmesh.data_element3s)
1196 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1197 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1200 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1201 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1202 if (r_enableshadowvolumes.integer)
1204 loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
1206 Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1207 if (loadmodel->surfmesh.data_neighbor3i)
1208 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1209 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1210 Mod_Alias_MorphMesh_CompileFrames();
1213 Mem_Free(vertremap);
1216 skinfiles = Mod_LoadSkinFiles();
1219 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1220 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1221 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1222 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1223 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1224 Mod_FreeSkinFiles(skinfiles);
1225 for (i = 0;i < loadmodel->numskins;i++)
1227 loadmodel->skinscenes[i].firstframe = i;
1228 loadmodel->skinscenes[i].framecount = 1;
1229 loadmodel->skinscenes[i].loop = true;
1230 loadmodel->skinscenes[i].framerate = 10;
1235 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1236 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1237 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1238 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1240 datapointer = startskins;
1241 for (i = 0;i < loadmodel->numskins;i++)
1243 pinskintype = (daliasskintype_t *)datapointer;
1244 datapointer += sizeof(daliasskintype_t);
1246 if (pinskintype->type == ALIAS_SKIN_SINGLE)
1253 pinskingroup = (daliasskingroup_t *)datapointer;
1254 datapointer += sizeof(daliasskingroup_t);
1256 groupskins = LittleLong (pinskingroup->numskins);
1258 pinskinintervals = (daliasskininterval_t *)datapointer;
1259 datapointer += sizeof(daliasskininterval_t) * groupskins;
1261 interval = LittleFloat(pinskinintervals[0].interval);
1262 if (interval < 0.01f)
1264 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1269 dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1270 loadmodel->skinscenes[i].firstframe = totalskins;
1271 loadmodel->skinscenes[i].framecount = groupskins;
1272 loadmodel->skinscenes[i].framerate = 1.0f / interval;
1273 loadmodel->skinscenes[i].loop = true;
1275 for (j = 0;j < groupskins;j++)
1278 dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1280 dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1281 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))
1282 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));
1283 datapointer += skinwidth * skinheight;
1287 // check for skins that don't exist in the model, but do exist as external images
1288 // (this was added because yummyluv kept pestering me about support for it)
1289 // TODO: support shaders here?
1290 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)))
1292 // expand the arrays to make room
1293 tempskinscenes = loadmodel->skinscenes;
1294 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1295 memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1296 Mem_Free(tempskinscenes);
1298 tempaliasskins = loadmodel->data_textures;
1299 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1300 memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1301 Mem_Free(tempaliasskins);
1303 // store the info about the new skin
1304 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, tempskinframe);
1305 strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1306 loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1307 loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1308 loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1309 loadmodel->skinscenes[loadmodel->numskins].loop = true;
1311 //increase skin counts
1312 loadmodel->numskins++;
1315 // fix up the pointers since they are pointing at the old textures array
1316 // FIXME: this is a hack!
1317 for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1318 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1322 surface = loadmodel->data_surfaces;
1323 surface->texture = loadmodel->data_textures;
1324 surface->num_firsttriangle = 0;
1325 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1326 surface->num_firstvertex = 0;
1327 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1329 if(mod_alias_force_animated.string[0])
1330 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1332 if (!loadmodel->surfmesh.isanimated)
1334 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1335 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1336 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1337 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1338 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1339 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1342 // because shaders can do somewhat unexpected things, check for unusual features now
1343 for (i = 0;i < loadmodel->num_textures;i++)
1345 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1346 mod->DrawSky = R_Q1BSP_DrawSky;
1347 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1348 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1352 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
1354 int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1355 float iskinwidth, iskinheight;
1356 unsigned char *data;
1357 msurface_t *surface;
1359 unsigned char *base, *datapointer;
1360 md2frame_t *pinframe;
1362 md2triangle_t *intri;
1363 unsigned short *inst;
1364 struct md2verthash_s
1366 struct md2verthash_s *next;
1370 *hash, **md2verthash, *md2verthashdata;
1371 skinfile_t *skinfiles;
1373 pinmodel = (md2_t *)buffer;
1374 base = (unsigned char *)buffer;
1376 version = LittleLong (pinmodel->version);
1377 if (version != MD2ALIAS_VERSION)
1378 Host_Error ("%s has wrong version number (%i should be %i)",
1379 loadmodel->name, version, MD2ALIAS_VERSION);
1381 loadmodel->modeldatatypestring = "MD2";
1383 loadmodel->type = mod_alias;
1384 loadmodel->DrawSky = NULL;
1385 loadmodel->DrawAddWaterPlanes = NULL;
1386 loadmodel->Draw = R_Q1BSP_Draw;
1387 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1388 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1389 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1390 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1391 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1392 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1393 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1394 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1395 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1396 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1397 loadmodel->PointSuperContents = NULL;
1398 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1400 if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1401 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1402 if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1403 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1404 if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1405 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1406 if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1407 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1409 end = LittleLong(pinmodel->ofs_end);
1410 if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1411 Host_Error ("%s is not a valid model", loadmodel->name);
1412 if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1413 Host_Error ("%s is not a valid model", loadmodel->name);
1414 if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1415 Host_Error ("%s is not a valid model", loadmodel->name);
1416 if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1417 Host_Error ("%s is not a valid model", loadmodel->name);
1418 if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1419 Host_Error ("%s is not a valid model", loadmodel->name);
1421 loadmodel->numskins = LittleLong(pinmodel->num_skins);
1422 numxyz = LittleLong(pinmodel->num_xyz);
1423 numst = LittleLong(pinmodel->num_st);
1424 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1425 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1426 loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1427 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1428 skinwidth = LittleLong(pinmodel->skinwidth);
1429 skinheight = LittleLong(pinmodel->skinheight);
1430 iskinwidth = 1.0f / skinwidth;
1431 iskinheight = 1.0f / skinheight;
1433 loadmodel->num_surfaces = 1;
1434 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1435 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));
1436 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1437 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1438 loadmodel->sortedmodelsurfaces[0] = 0;
1439 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1440 loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1441 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1442 if (r_enableshadowvolumes.integer)
1444 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1447 loadmodel->synctype = ST_RAND;
1450 inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1451 skinfiles = Mod_LoadSkinFiles();
1454 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1455 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1456 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1457 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1458 Mod_FreeSkinFiles(skinfiles);
1460 else if (loadmodel->numskins)
1462 // skins found (most likely not a player model)
1463 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1464 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1465 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1466 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1467 Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
1471 // no skins (most likely a player model)
1472 loadmodel->numskins = 1;
1473 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1474 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1475 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1476 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL);
1479 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1480 for (i = 0;i < loadmodel->numskins;i++)
1482 loadmodel->skinscenes[i].firstframe = i;
1483 loadmodel->skinscenes[i].framecount = 1;
1484 loadmodel->skinscenes[i].loop = true;
1485 loadmodel->skinscenes[i].framerate = 10;
1488 // load the triangles and stvert data
1489 inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1490 intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1491 md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1492 md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1493 // swap the triangle list
1494 loadmodel->surfmesh.num_vertices = 0;
1495 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1497 for (j = 0;j < 3;j++)
1499 xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1500 st = (unsigned short) LittleShort (intri[i].index_st[j]);
1503 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1508 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1511 hashindex = (xyz * 256 + st) & 65535;
1512 for (hash = md2verthash[hashindex];hash;hash = hash->next)
1513 if (hash->xyz == xyz && hash->st == st)
1517 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1520 hash->next = md2verthash[hashindex];
1521 md2verthash[hashindex] = hash;
1523 loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1527 vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1528 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));
1529 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1530 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1531 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1534 hash = md2verthashdata + i;
1535 vertremap[i] = hash->xyz;
1536 sts = LittleShort(inst[hash->st*2+0]);
1537 stt = LittleShort(inst[hash->st*2+1]);
1538 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1540 Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1544 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1545 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1548 Mem_Free(md2verthash);
1549 Mem_Free(md2verthashdata);
1551 // generate ushort elements array if possible
1552 if (loadmodel->surfmesh.num_vertices <= 65536)
1553 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1554 if (loadmodel->surfmesh.data_element3s)
1555 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1556 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1559 datapointer = (base + LittleLong(pinmodel->ofs_frames));
1560 for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1565 pinframe = (md2frame_t *)datapointer;
1566 datapointer += sizeof(md2frame_t);
1567 // store the frame scale/translate into the appropriate array
1568 for (j = 0;j < 3;j++)
1570 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1571 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1573 // convert the vertices
1574 v = (trivertx_t *)datapointer;
1575 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1576 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1577 out[k] = v[vertremap[k]];
1578 datapointer += numxyz * sizeof(trivertx_t);
1580 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1581 loadmodel->animscenes[i].firstframe = i;
1582 loadmodel->animscenes[i].framecount = 1;
1583 loadmodel->animscenes[i].framerate = 10;
1584 loadmodel->animscenes[i].loop = true;
1587 Mem_Free(vertremap);
1589 if (loadmodel->surfmesh.data_neighbor3i)
1590 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1591 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1592 Mod_Alias_MorphMesh_CompileFrames();
1593 if(mod_alias_force_animated.string[0])
1594 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1596 surface = loadmodel->data_surfaces;
1597 surface->texture = loadmodel->data_textures;
1598 surface->num_firsttriangle = 0;
1599 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1600 surface->num_firstvertex = 0;
1601 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1603 if (!loadmodel->surfmesh.isanimated)
1605 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1606 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1607 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1608 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1609 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1610 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1613 // because shaders can do somewhat unexpected things, check for unusual features now
1614 for (i = 0;i < loadmodel->num_textures;i++)
1616 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1617 mod->DrawSky = R_Q1BSP_DrawSky;
1618 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1619 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1623 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
1625 int i, j, k, version, meshvertices, meshtriangles;
1626 unsigned char *data;
1627 msurface_t *surface;
1628 md3modelheader_t *pinmodel;
1629 md3frameinfo_t *pinframe;
1632 skinfile_t *skinfiles;
1634 pinmodel = (md3modelheader_t *)buffer;
1636 if (memcmp(pinmodel->identifier, "IDP3", 4))
1637 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1638 version = LittleLong (pinmodel->version);
1639 if (version != MD3VERSION)
1640 Host_Error ("%s has wrong version number (%i should be %i)",
1641 loadmodel->name, version, MD3VERSION);
1643 skinfiles = Mod_LoadSkinFiles();
1644 if (loadmodel->numskins < 1)
1645 loadmodel->numskins = 1;
1647 loadmodel->modeldatatypestring = "MD3";
1649 loadmodel->type = mod_alias;
1650 loadmodel->DrawSky = NULL;
1651 loadmodel->DrawAddWaterPlanes = NULL;
1652 loadmodel->Draw = R_Q1BSP_Draw;
1653 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1654 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1655 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1656 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1657 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1658 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1659 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1660 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1661 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1662 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1663 loadmodel->PointSuperContents = NULL;
1664 loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1665 loadmodel->synctype = ST_RAND;
1666 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1667 i = LittleLong (pinmodel->flags);
1668 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1670 // set up some global info about the model
1671 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1672 loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1674 // make skinscenes for the skins (no groups)
1675 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1676 for (i = 0;i < loadmodel->numskins;i++)
1678 loadmodel->skinscenes[i].firstframe = i;
1679 loadmodel->skinscenes[i].framecount = 1;
1680 loadmodel->skinscenes[i].loop = true;
1681 loadmodel->skinscenes[i].framerate = 10;
1685 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1686 for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1688 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1689 loadmodel->animscenes[i].firstframe = i;
1690 loadmodel->animscenes[i].framecount = 1;
1691 loadmodel->animscenes[i].framerate = 10;
1692 loadmodel->animscenes[i].loop = true;
1696 loadmodel->num_tagframes = loadmodel->numframes;
1697 loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1698 loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1699 for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1701 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1702 for (j = 0;j < 9;j++)
1703 loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1704 for (j = 0;j < 3;j++)
1705 loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1706 //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);
1712 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)))
1714 if (memcmp(pinmesh->identifier, "IDP3", 4))
1715 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1716 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1717 Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1718 meshvertices += LittleLong(pinmesh->num_vertices);
1719 meshtriangles += LittleLong(pinmesh->num_triangles);
1722 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1723 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1724 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1725 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));
1726 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1727 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1728 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1729 loadmodel->surfmesh.num_vertices = meshvertices;
1730 loadmodel->surfmesh.num_triangles = meshtriangles;
1731 loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1732 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1733 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1734 if (r_enableshadowvolumes.integer)
1736 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1738 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1739 loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1740 if (meshvertices <= 65536)
1742 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1747 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)))
1749 if (memcmp(pinmesh->identifier, "IDP3", 4))
1750 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1751 loadmodel->sortedmodelsurfaces[i] = i;
1752 surface = loadmodel->data_surfaces + i;
1753 surface->texture = loadmodel->data_textures + i;
1754 surface->num_firsttriangle = meshtriangles;
1755 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1756 surface->num_firstvertex = meshvertices;
1757 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1758 meshvertices += surface->num_vertices;
1759 meshtriangles += surface->num_triangles;
1761 for (j = 0;j < surface->num_triangles * 3;j++)
1762 loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1763 for (j = 0;j < surface->num_vertices;j++)
1765 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1766 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1768 for (j = 0;j < loadmodel->numframes;j++)
1770 const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1771 md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1772 for (k = 0;k < surface->num_vertices;k++, in++, out++)
1774 out->origin[0] = LittleShort(in->origin[0]);
1775 out->origin[1] = LittleShort(in->origin[1]);
1776 out->origin[2] = LittleShort(in->origin[2]);
1777 out->pitch = in->pitch;
1782 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1784 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1786 if (loadmodel->surfmesh.data_element3s)
1787 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1788 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1789 if (loadmodel->surfmesh.data_neighbor3i)
1790 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1791 Mod_Alias_MorphMesh_CompileFrames();
1792 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1793 Mod_FreeSkinFiles(skinfiles);
1794 Mod_MakeSortedSurfaces(loadmodel);
1795 if(mod_alias_force_animated.string[0])
1796 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1798 if (!loadmodel->surfmesh.isanimated)
1800 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1801 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1802 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1803 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1804 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1805 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1808 // because shaders can do somewhat unexpected things, check for unusual features now
1809 for (i = 0;i < loadmodel->num_textures;i++)
1811 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1812 mod->DrawSky = R_Q1BSP_DrawSky;
1813 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1814 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1818 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1820 zymtype1header_t *pinmodel, *pheader;
1821 unsigned char *pbase;
1822 int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1823 float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1824 zymvertex_t *verts, *vertdata;
1828 skinfile_t *skinfiles;
1829 unsigned char *data;
1830 msurface_t *surface;
1832 pinmodel = (zymtype1header_t *)buffer;
1833 pbase = (unsigned char *)buffer;
1834 if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1835 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1836 if (BigLong(pinmodel->type) != 1)
1837 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1839 loadmodel->modeldatatypestring = "ZYM";
1841 loadmodel->type = mod_alias;
1842 loadmodel->synctype = ST_RAND;
1846 pheader->type = BigLong(pinmodel->type);
1847 pheader->filesize = BigLong(pinmodel->filesize);
1848 pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1849 pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1850 pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1851 pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1852 pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1853 pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1854 pheader->radius = BigFloat(pinmodel->radius);
1855 pheader->numverts = BigLong(pinmodel->numverts);
1856 pheader->numtris = BigLong(pinmodel->numtris);
1857 pheader->numshaders = BigLong(pinmodel->numshaders);
1858 pheader->numbones = BigLong(pinmodel->numbones);
1859 pheader->numscenes = BigLong(pinmodel->numscenes);
1860 pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1861 pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1862 pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1863 pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1864 pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1865 pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1866 pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1867 pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1868 pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1869 pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1870 pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1871 pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1872 pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1873 pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1874 pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1875 pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1876 pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1877 pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1879 if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1881 Con_Printf("%s has no geometry\n", loadmodel->name);
1884 if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1886 Con_Printf("%s has no animations\n", loadmodel->name);
1890 loadmodel->DrawSky = NULL;
1891 loadmodel->DrawAddWaterPlanes = NULL;
1892 loadmodel->Draw = R_Q1BSP_Draw;
1893 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1894 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1895 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1896 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1897 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1898 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1899 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1900 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1901 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1902 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1903 loadmodel->PointSuperContents = NULL;
1904 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1906 loadmodel->numframes = pheader->numscenes;
1907 loadmodel->num_surfaces = pheader->numshaders;
1909 skinfiles = Mod_LoadSkinFiles();
1910 if (loadmodel->numskins < 1)
1911 loadmodel->numskins = 1;
1913 // make skinscenes for the skins (no groups)
1914 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1915 for (i = 0;i < loadmodel->numskins;i++)
1917 loadmodel->skinscenes[i].firstframe = i;
1918 loadmodel->skinscenes[i].framecount = 1;
1919 loadmodel->skinscenes[i].loop = true;
1920 loadmodel->skinscenes[i].framerate = 10;
1924 // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
1925 modelradius = pheader->radius;
1926 for (i = 0;i < 3;i++)
1928 loadmodel->normalmins[i] = pheader->mins[i];
1929 loadmodel->normalmaxs[i] = pheader->maxs[i];
1930 loadmodel->rotatedmins[i] = -modelradius;
1931 loadmodel->rotatedmaxs[i] = modelradius;
1933 corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1934 corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1935 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1936 if (loadmodel->yawmaxs[0] > modelradius)
1937 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1938 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1939 loadmodel->yawmins[2] = loadmodel->normalmins[2];
1940 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1941 loadmodel->radius = modelradius;
1942 loadmodel->radius2 = modelradius * modelradius;
1944 // go through the lumps, swapping things
1946 //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1947 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1948 scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1949 numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1950 for (i = 0;i < pheader->numscenes;i++)
1952 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1953 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1954 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1955 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1956 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1957 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1958 Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1959 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1960 Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1961 if (loadmodel->animscenes[i].framerate < 0)
1962 Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1966 //zymlump_t lump_bones; // zymbone_t bone[numbones];
1967 loadmodel->num_bones = pheader->numbones;
1968 loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1969 bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1970 for (i = 0;i < pheader->numbones;i++)
1972 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1973 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1974 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1975 if (loadmodel->data_bones[i].parent >= i)
1976 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1979 //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1980 vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1981 bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1982 for (i = 0;i < pheader->numverts;i++)
1984 vertbonecounts[i] = BigLong(bonecount[i]);
1985 if (vertbonecounts[i] != 1)
1986 Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1989 loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1991 meshvertices = pheader->numverts;
1992 meshtriangles = pheader->numtris;
1994 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1995 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1996 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1997 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]));
1998 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1999 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2000 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2001 loadmodel->surfmesh.num_vertices = meshvertices;
2002 loadmodel->surfmesh.num_triangles = meshtriangles;
2003 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2004 if (r_enableshadowvolumes.integer)
2006 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2008 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2009 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2010 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2011 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2012 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2013 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2014 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2015 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2016 loadmodel->surfmesh.num_blends = 0;
2017 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2018 if (loadmodel->surfmesh.num_vertices <= 65536)
2020 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2022 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2023 loadmodel->surfmesh.data_blendweights = NULL;
2025 //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
2026 poses = (float *) (pheader->lump_poses.start + pbase);
2027 // figure out scale of model from root bone, for compatibility with old zmodel versions
2028 tempvec[0] = BigFloat(poses[0]);
2029 tempvec[1] = BigFloat(poses[1]);
2030 tempvec[2] = BigFloat(poses[2]);
2031 modelscale = VectorLength(tempvec);
2033 for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
2035 f = fabs(BigFloat(poses[i]));
2036 biggestorigin = max(biggestorigin, f);
2038 loadmodel->num_posescale = biggestorigin / 32767.0f;
2039 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2040 for (i = 0;i < numposes;i++)
2042 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
2043 for (j = 0;j < loadmodel->num_bones;j++)
2046 matrix4x4_t posematrix;
2047 for (k = 0;k < 12;k++)
2048 pose[k] = BigFloat(frameposes[j*12+k]);
2049 //if (j < loadmodel->num_bones)
2050 // 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));
2051 // scale child bones to match the root scale
2052 if (loadmodel->data_bones[j].parent >= 0)
2054 pose[3] *= modelscale;
2055 pose[7] *= modelscale;
2056 pose[11] *= modelscale;
2058 // normalize rotation matrix
2059 VectorNormalize(pose + 0);
2060 VectorNormalize(pose + 4);
2061 VectorNormalize(pose + 8);
2062 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2063 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2067 //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2068 verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2069 vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2070 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2071 // (converting from weight-blending skeletal animation to
2072 // deformation-based skeletal animation)
2073 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2074 for (i = 0;i < loadmodel->num_bones;i++)
2077 for (k = 0;k < 12;k++)
2078 m[k] = BigFloat(poses[i*12+k]);
2079 if (loadmodel->data_bones[i].parent >= 0)
2080 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2082 for (k = 0;k < 12;k++)
2083 bonepose[12*i+k] = m[k];
2085 for (j = 0;j < pheader->numverts;j++)
2087 // this format really should have had a per vertexweight weight value...
2088 // but since it does not, the weighting is completely ignored and
2089 // only one weight is allowed per vertex
2090 int boneindex = BigLong(vertdata[j].bonenum);
2091 const float *m = bonepose + 12 * boneindex;
2092 float relativeorigin[3];
2093 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2094 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2095 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2096 // transform the vertex bone weight into the base mesh
2097 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2098 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2099 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2100 // store the weight as the primary weight on this vertex
2101 loadmodel->surfmesh.blends[j] = boneindex;
2102 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = boneindex;
2103 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2104 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2105 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2106 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = 255;
2107 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2108 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2109 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2112 // normals and tangents are calculated after elements are loaded
2114 //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2115 outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2116 intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2117 for (i = 0;i < pheader->numverts;i++)
2119 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2120 // flip T coordinate for OpenGL
2121 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2124 //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2125 //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2126 //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2128 //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2129 //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)
2130 // byteswap, validate, and swap winding order of tris
2131 count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2132 if (pheader->lump_render.length != count)
2133 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2134 renderlist = (int *) (pheader->lump_render.start + pbase);
2135 renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2137 for (i = 0;i < loadmodel->num_surfaces;i++)
2139 int firstvertex, lastvertex;
2140 if (renderlist >= renderlistend)
2141 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2142 count = BigLong(*renderlist);renderlist++;
2143 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2144 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2146 loadmodel->sortedmodelsurfaces[i] = i;
2147 surface = loadmodel->data_surfaces + i;
2148 surface->texture = loadmodel->data_textures + i;
2149 surface->num_firsttriangle = meshtriangles;
2150 surface->num_triangles = count;
2151 meshtriangles += surface->num_triangles;
2153 // load the elements
2154 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2155 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2157 outelements[j*3+2] = BigLong(renderlist[0]);
2158 outelements[j*3+1] = BigLong(renderlist[1]);
2159 outelements[j*3+0] = BigLong(renderlist[2]);
2161 // validate the elements and find the used vertex range
2162 firstvertex = meshvertices;
2164 for (j = 0;j < surface->num_triangles * 3;j++)
2166 if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2167 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2168 firstvertex = min(firstvertex, outelements[j]);
2169 lastvertex = max(lastvertex, outelements[j]);
2171 surface->num_firstvertex = firstvertex;
2172 surface->num_vertices = lastvertex + 1 - firstvertex;
2174 // since zym models do not have named sections, reuse their shader
2175 // name as the section name
2176 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2177 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2179 Mod_FreeSkinFiles(skinfiles);
2180 Mem_Free(vertbonecounts);
2182 Mod_MakeSortedSurfaces(loadmodel);
2184 // compute all the mesh information that was not loaded from the file
2185 if (loadmodel->surfmesh.data_element3s)
2186 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2187 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2188 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2189 Mod_BuildBaseBonePoses();
2190 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);
2191 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);
2192 if (loadmodel->surfmesh.data_neighbor3i)
2193 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2194 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2195 if(mod_alias_force_animated.string[0])
2196 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2198 if (!loadmodel->surfmesh.isanimated)
2200 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2201 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2202 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2203 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2204 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2205 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2208 // because shaders can do somewhat unexpected things, check for unusual features now
2209 for (i = 0;i < loadmodel->num_textures;i++)
2211 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2212 mod->DrawSky = R_Q1BSP_DrawSky;
2213 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2214 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2218 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2220 dpmheader_t *pheader;
2224 unsigned char *pbase;
2225 int i, j, k, meshvertices, meshtriangles;
2226 skinfile_t *skinfiles;
2227 unsigned char *data;
2229 float biggestorigin, tempvec[3], modelscale;
2233 pheader = (dpmheader_t *)buffer;
2234 pbase = (unsigned char *)buffer;
2235 if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2236 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2237 if (BigLong(pheader->type) != 2)
2238 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2240 loadmodel->modeldatatypestring = "DPM";
2242 loadmodel->type = mod_alias;
2243 loadmodel->synctype = ST_RAND;
2246 pheader->type = BigLong(pheader->type);
2247 pheader->filesize = BigLong(pheader->filesize);
2248 pheader->mins[0] = BigFloat(pheader->mins[0]);
2249 pheader->mins[1] = BigFloat(pheader->mins[1]);
2250 pheader->mins[2] = BigFloat(pheader->mins[2]);
2251 pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2252 pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2253 pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2254 pheader->yawradius = BigFloat(pheader->yawradius);
2255 pheader->allradius = BigFloat(pheader->allradius);
2256 pheader->num_bones = BigLong(pheader->num_bones);
2257 pheader->num_meshs = BigLong(pheader->num_meshs);
2258 pheader->num_frames = BigLong(pheader->num_frames);
2259 pheader->ofs_bones = BigLong(pheader->ofs_bones);
2260 pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2261 pheader->ofs_frames = BigLong(pheader->ofs_frames);
2263 if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2265 Con_Printf("%s has no geometry\n", loadmodel->name);
2268 if (pheader->num_frames < 1)
2270 Con_Printf("%s has no frames\n", loadmodel->name);
2274 loadmodel->DrawSky = NULL;
2275 loadmodel->DrawAddWaterPlanes = NULL;
2276 loadmodel->Draw = R_Q1BSP_Draw;
2277 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2278 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2279 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2280 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2281 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2282 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2283 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2284 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2285 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2286 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2287 loadmodel->PointSuperContents = NULL;
2288 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2291 // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2292 for (i = 0;i < 3;i++)
2294 loadmodel->normalmins[i] = pheader->mins[i];
2295 loadmodel->normalmaxs[i] = pheader->maxs[i];
2296 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2297 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2298 loadmodel->rotatedmins[i] = -pheader->allradius;
2299 loadmodel->rotatedmaxs[i] = pheader->allradius;
2301 loadmodel->radius = pheader->allradius;
2302 loadmodel->radius2 = pheader->allradius * pheader->allradius;
2304 // load external .skin files if present
2305 skinfiles = Mod_LoadSkinFiles();
2306 if (loadmodel->numskins < 1)
2307 loadmodel->numskins = 1;
2312 // gather combined statistics from the meshes
2313 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2314 for (i = 0;i < (int)pheader->num_meshs;i++)
2316 int numverts = BigLong(dpmmesh->num_verts);
2317 meshvertices += numverts;
2318 meshtriangles += BigLong(dpmmesh->num_tris);
2322 loadmodel->numframes = pheader->num_frames;
2323 loadmodel->num_bones = pheader->num_bones;
2324 loadmodel->num_poses = loadmodel->numframes;
2325 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
2326 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2327 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2328 // do most allocations as one merged chunk
2329 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));
2330 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2331 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2332 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2333 loadmodel->surfmesh.num_vertices = meshvertices;
2334 loadmodel->surfmesh.num_triangles = meshtriangles;
2335 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2336 if (r_enableshadowvolumes.integer)
2338 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2340 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2341 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2342 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2343 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2344 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2345 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2346 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2347 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2348 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2349 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2350 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2351 loadmodel->surfmesh.num_blends = 0;
2352 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2353 if (meshvertices <= 65536)
2355 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2357 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2358 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2360 for (i = 0;i < loadmodel->numskins;i++)
2362 loadmodel->skinscenes[i].firstframe = i;
2363 loadmodel->skinscenes[i].framecount = 1;
2364 loadmodel->skinscenes[i].loop = true;
2365 loadmodel->skinscenes[i].framerate = 10;
2368 // load the bone info
2369 bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2370 for (i = 0;i < loadmodel->num_bones;i++)
2372 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2373 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2374 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2375 if (loadmodel->data_bones[i].parent >= i)
2376 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2380 frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2381 // figure out scale of model from root bone, for compatibility with old dpmodel versions
2382 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2383 tempvec[0] = BigFloat(poses[0]);
2384 tempvec[1] = BigFloat(poses[1]);
2385 tempvec[2] = BigFloat(poses[2]);
2386 modelscale = VectorLength(tempvec);
2388 for (i = 0;i < loadmodel->numframes;i++)
2390 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2391 loadmodel->animscenes[i].firstframe = i;
2392 loadmodel->animscenes[i].framecount = 1;
2393 loadmodel->animscenes[i].loop = true;
2394 loadmodel->animscenes[i].framerate = 10;
2395 // load the bone poses for this frame
2396 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2397 for (j = 0;j < loadmodel->num_bones*12;j++)
2399 f = fabs(BigFloat(poses[j]));
2400 biggestorigin = max(biggestorigin, f);
2402 // stuff not processed here: mins, maxs, yawradius, allradius
2404 loadmodel->num_posescale = biggestorigin / 32767.0f;
2405 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2406 for (i = 0;i < loadmodel->numframes;i++)
2408 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2409 for (j = 0;j < loadmodel->num_bones;j++)
2412 matrix4x4_t posematrix;
2413 for (k = 0;k < 12;k++)
2414 pose[k] = BigFloat(frameposes[j*12+k]);
2415 // scale child bones to match the root scale
2416 if (loadmodel->data_bones[j].parent >= 0)
2418 pose[3] *= modelscale;
2419 pose[7] *= modelscale;
2420 pose[11] *= modelscale;
2422 // normalize rotation matrix
2423 VectorNormalize(pose + 0);
2424 VectorNormalize(pose + 4);
2425 VectorNormalize(pose + 8);
2426 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2427 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2431 // load the meshes now
2432 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2435 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2436 // (converting from weight-blending skeletal animation to
2437 // deformation-based skeletal animation)
2438 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2439 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2440 for (i = 0;i < loadmodel->num_bones;i++)
2443 for (k = 0;k < 12;k++)
2444 m[k] = BigFloat(poses[i*12+k]);
2445 if (loadmodel->data_bones[i].parent >= 0)
2446 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2448 for (k = 0;k < 12;k++)
2449 bonepose[12*i+k] = m[k];
2451 for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2453 const int *inelements;
2455 const float *intexcoord;
2456 msurface_t *surface;
2458 loadmodel->sortedmodelsurfaces[i] = i;
2459 surface = loadmodel->data_surfaces + i;
2460 surface->texture = loadmodel->data_textures + i;
2461 surface->num_firsttriangle = meshtriangles;
2462 surface->num_triangles = BigLong(dpmmesh->num_tris);
2463 surface->num_firstvertex = meshvertices;
2464 surface->num_vertices = BigLong(dpmmesh->num_verts);
2465 meshvertices += surface->num_vertices;
2466 meshtriangles += surface->num_triangles;
2468 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2469 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2470 for (j = 0;j < surface->num_triangles;j++)
2472 // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2473 outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
2474 outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
2475 outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
2480 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2481 for (j = 0;j < surface->num_vertices*2;j++)
2482 loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2484 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2485 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2487 int weightindex[4] = { 0, 0, 0, 0 };
2488 float weightinfluence[4] = { 0, 0, 0, 0 };
2490 int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2491 data += sizeof(dpmvertex_t);
2492 for (k = 0;k < numweights;k++)
2494 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2495 int boneindex = BigLong(vert->bonenum);
2496 const float *m = bonepose + 12 * boneindex;
2497 float influence = BigFloat(vert->influence);
2498 float relativeorigin[3], relativenormal[3];
2499 relativeorigin[0] = BigFloat(vert->origin[0]);
2500 relativeorigin[1] = BigFloat(vert->origin[1]);
2501 relativeorigin[2] = BigFloat(vert->origin[2]);
2502 relativenormal[0] = BigFloat(vert->normal[0]);
2503 relativenormal[1] = BigFloat(vert->normal[1]);
2504 relativenormal[2] = BigFloat(vert->normal[2]);
2505 // blend the vertex bone weights into the base mesh
2506 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2507 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2508 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2509 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2510 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2511 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2514 // store the first (and often only) weight
2515 weightinfluence[0] = influence;
2516 weightindex[0] = boneindex;
2520 // sort the new weight into this vertex's weight table
2521 // (which only accepts up to 4 bones per vertex)
2522 for (l = 0;l < 4;l++)
2524 if (weightinfluence[l] < influence)
2526 // move weaker influence weights out of the way first
2528 for (l2 = 3;l2 > l;l2--)
2530 weightinfluence[l2] = weightinfluence[l2-1];
2531 weightindex[l2] = weightindex[l2-1];
2533 // store the new weight
2534 weightinfluence[l] = influence;
2535 weightindex[l] = boneindex;
2540 data += sizeof(dpmbonevert_t);
2542 loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2543 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = weightindex[0];
2544 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2545 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2546 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2547 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
2548 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2549 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2550 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2553 // since dpm models do not have named sections, reuse their shader name as the section name
2554 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2556 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2558 if (loadmodel->surfmesh.num_blends < meshvertices)
2559 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2561 Mod_FreeSkinFiles(skinfiles);
2562 Mod_MakeSortedSurfaces(loadmodel);
2564 // compute all the mesh information that was not loaded from the file
2565 if (loadmodel->surfmesh.data_element3s)
2566 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2567 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2568 Mod_BuildBaseBonePoses();
2569 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);
2570 if (loadmodel->surfmesh.data_neighbor3i)
2571 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2572 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2573 if(mod_alias_force_animated.string[0])
2574 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2576 if (!loadmodel->surfmesh.isanimated)
2578 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2579 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2580 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2581 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2582 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2583 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2586 // because shaders can do somewhat unexpected things, check for unusual features now
2587 for (i = 0;i < loadmodel->num_textures;i++)
2589 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2590 mod->DrawSky = R_Q1BSP_DrawSky;
2591 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2592 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2596 // no idea why PSK/PSA files contain weird quaternions but they do...
2597 #define PSKQUATNEGATIONS
2598 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2600 int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2601 int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2602 fs_offset_t filesize;
2607 pskboneinfo_t *bones;
2608 pskrawweights_t *rawweights;
2609 //pskboneinfo_t *animbones;
2610 pskaniminfo_t *anims;
2611 pskanimkeys_t *animkeys;
2612 void *animfilebuffer, *animbuffer, *animbufferend;
2613 unsigned char *data;
2615 skinfile_t *skinfiles;
2616 char animname[MAX_QPATH];
2618 float biggestorigin;
2620 pchunk = (pskchunk_t *)buffer;
2621 if (strcmp(pchunk->id, "ACTRHEAD"))
2622 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2624 loadmodel->modeldatatypestring = "PSK";
2626 loadmodel->type = mod_alias;
2627 loadmodel->DrawSky = NULL;
2628 loadmodel->DrawAddWaterPlanes = NULL;
2629 loadmodel->Draw = R_Q1BSP_Draw;
2630 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2631 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2632 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2633 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2634 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2635 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2636 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2637 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2638 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2639 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2640 loadmodel->PointSuperContents = NULL;
2641 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2642 loadmodel->synctype = ST_RAND;
2644 FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2645 strlcat(animname, ".psa", sizeof(animname));
2646 animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2647 animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2649 animbufferend = animbuffer;
2668 while (buffer < bufferend)
2670 pchunk = (pskchunk_t *)buffer;
2671 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2672 version = LittleLong(pchunk->version);
2673 recordsize = LittleLong(pchunk->recordsize);
2674 numrecords = LittleLong(pchunk->numrecords);
2675 if (developer_extra.integer)
2676 Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2677 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2678 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);
2679 if (!strcmp(pchunk->id, "ACTRHEAD"))
2683 else if (!strcmp(pchunk->id, "PNTS0000"))
2686 if (recordsize != sizeof(*p))
2687 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2688 // byteswap in place and keep the pointer
2689 numpnts = numrecords;
2690 pnts = (pskpnts_t *)buffer;
2691 for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2693 p->origin[0] = LittleFloat(p->origin[0]);
2694 p->origin[1] = LittleFloat(p->origin[1]);
2695 p->origin[2] = LittleFloat(p->origin[2]);
2699 else if (!strcmp(pchunk->id, "VTXW0000"))
2702 if (recordsize != sizeof(*p))
2703 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2704 // byteswap in place and keep the pointer
2705 numvtxw = numrecords;
2706 vtxw = (pskvtxw_t *)buffer;
2707 for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2709 p->pntsindex = LittleShort(p->pntsindex);
2710 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2711 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2712 if (p->pntsindex >= numpnts)
2714 Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2720 else if (!strcmp(pchunk->id, "FACE0000"))
2723 if (recordsize != sizeof(*p))
2724 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2725 // byteswap in place and keep the pointer
2726 numfaces = numrecords;
2727 faces = (pskface_t *)buffer;
2728 for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2730 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2731 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2732 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2733 p->group = LittleLong(p->group);
2734 if (p->vtxwindex[0] >= numvtxw)
2736 Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2737 p->vtxwindex[0] = 0;
2739 if (p->vtxwindex[1] >= numvtxw)
2741 Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2742 p->vtxwindex[1] = 0;
2744 if (p->vtxwindex[2] >= numvtxw)
2746 Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2747 p->vtxwindex[2] = 0;
2752 else if (!strcmp(pchunk->id, "MATT0000"))
2755 if (recordsize != sizeof(*p))
2756 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2757 // byteswap in place and keep the pointer
2758 nummatts = numrecords;
2759 matts = (pskmatt_t *)buffer;
2760 for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2766 else if (!strcmp(pchunk->id, "REFSKELT"))
2769 if (recordsize != sizeof(*p))
2770 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2771 // byteswap in place and keep the pointer
2772 numbones = numrecords;
2773 bones = (pskboneinfo_t *)buffer;
2774 for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2776 p->numchildren = LittleLong(p->numchildren);
2777 p->parent = LittleLong(p->parent);
2778 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2779 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2780 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2781 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2782 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2783 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2784 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2785 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2786 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2787 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2788 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2789 #ifdef PSKQUATNEGATIONS
2792 p->basepose.quat[0] *= -1;
2793 p->basepose.quat[1] *= -1;
2794 p->basepose.quat[2] *= -1;
2798 p->basepose.quat[0] *= 1;
2799 p->basepose.quat[1] *= -1;
2800 p->basepose.quat[2] *= 1;
2803 if (p->parent < 0 || p->parent >= numbones)
2805 Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2811 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2814 if (recordsize != sizeof(*p))
2815 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2816 // byteswap in place and keep the pointer
2817 numrawweights = numrecords;
2818 rawweights = (pskrawweights_t *)buffer;
2819 for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2821 p->weight = LittleFloat(p->weight);
2822 p->pntsindex = LittleLong(p->pntsindex);
2823 p->boneindex = LittleLong(p->boneindex);
2824 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2826 Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2829 if (p->boneindex < 0 || p->boneindex >= numbones)
2831 Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2839 while (animbuffer < animbufferend)
2841 pchunk = (pskchunk_t *)animbuffer;
2842 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2843 version = LittleLong(pchunk->version);
2844 recordsize = LittleLong(pchunk->recordsize);
2845 numrecords = LittleLong(pchunk->numrecords);
2846 if (developer_extra.integer)
2847 Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2848 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2849 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);
2850 if (!strcmp(pchunk->id, "ANIMHEAD"))
2854 else if (!strcmp(pchunk->id, "BONENAMES"))
2857 if (recordsize != sizeof(*p))
2858 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2859 // byteswap in place and keep the pointer
2860 numanimbones = numrecords;
2861 //animbones = (pskboneinfo_t *)animbuffer;
2862 // NOTE: supposedly psa does not need to match the psk model, the
2863 // bones missing from the psa would simply use their base
2864 // positions from the psk, but this is hard for me to implement
2865 // and people can easily make animations that match.
2866 if (numanimbones != numbones)
2867 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2868 for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2870 p->numchildren = LittleLong(p->numchildren);
2871 p->parent = LittleLong(p->parent);
2872 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2873 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2874 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2875 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2876 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2877 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2878 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2879 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2880 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2881 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2882 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2883 #ifdef PSKQUATNEGATIONS
2886 p->basepose.quat[0] *= -1;
2887 p->basepose.quat[1] *= -1;
2888 p->basepose.quat[2] *= -1;
2892 p->basepose.quat[0] *= 1;
2893 p->basepose.quat[1] *= -1;
2894 p->basepose.quat[2] *= 1;
2897 if (p->parent < 0 || p->parent >= numanimbones)
2899 Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2902 // check that bones are the same as in the base
2903 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2904 Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2908 else if (!strcmp(pchunk->id, "ANIMINFO"))
2911 if (recordsize != sizeof(*p))
2912 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2913 // byteswap in place and keep the pointer
2914 numanims = numrecords;
2915 anims = (pskaniminfo_t *)animbuffer;
2916 for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2918 p->numbones = LittleLong(p->numbones);
2919 p->playtime = LittleFloat(p->playtime);
2920 p->fps = LittleFloat(p->fps);
2921 p->firstframe = LittleLong(p->firstframe);
2922 p->numframes = LittleLong(p->numframes);
2923 if (p->numbones != numbones)
2924 Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2928 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2931 if (recordsize != sizeof(*p))
2932 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2933 numanimkeys = numrecords;
2934 animkeys = (pskanimkeys_t *)animbuffer;
2935 for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2937 p->origin[0] = LittleFloat(p->origin[0]);
2938 p->origin[1] = LittleFloat(p->origin[1]);
2939 p->origin[2] = LittleFloat(p->origin[2]);
2940 p->quat[0] = LittleFloat(p->quat[0]);
2941 p->quat[1] = LittleFloat(p->quat[1]);
2942 p->quat[2] = LittleFloat(p->quat[2]);
2943 p->quat[3] = LittleFloat(p->quat[3]);
2944 p->frametime = LittleFloat(p->frametime);
2945 #ifdef PSKQUATNEGATIONS
2946 if (index % numbones)
2961 // TODO: allocate bonepose stuff
2964 Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2967 if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2968 Host_Error("%s: missing required chunks", loadmodel->name);
2972 loadmodel->numframes = 0;
2973 for (index = 0;index < numanims;index++)
2974 loadmodel->numframes += anims[index].numframes;
2975 if (numanimkeys != numbones * loadmodel->numframes)
2976 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2979 loadmodel->numframes = loadmodel->num_poses = 1;
2981 meshvertices = numvtxw;
2982 meshtriangles = numfaces;
2984 // load external .skin files if present
2985 skinfiles = Mod_LoadSkinFiles();
2986 if (loadmodel->numskins < 1)
2987 loadmodel->numskins = 1;
2988 loadmodel->num_bones = numbones;
2989 loadmodel->num_poses = loadmodel->numframes;
2990 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2991 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2992 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2993 loadmodel->surfmesh.num_vertices = meshvertices;
2994 loadmodel->surfmesh.num_triangles = meshtriangles;
2995 // do most allocations as one merged chunk
2996 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);
2997 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2998 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2999 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3000 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3001 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
3002 if (r_enableshadowvolumes.integer)
3004 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
3006 loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3007 loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3008 loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3009 loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3010 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3011 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3012 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3013 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3014 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3015 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3016 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3017 loadmodel->surfmesh.num_blends = 0;
3018 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3019 if (loadmodel->surfmesh.num_vertices <= 65536)
3021 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
3023 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3024 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
3026 for (i = 0;i < loadmodel->numskins;i++)
3028 loadmodel->skinscenes[i].firstframe = i;
3029 loadmodel->skinscenes[i].framecount = 1;
3030 loadmodel->skinscenes[i].loop = true;
3031 loadmodel->skinscenes[i].framerate = 10;
3035 for (index = 0, i = 0;index < nummatts;index++)
3037 // since psk models do not have named sections, reuse their shader name as the section name
3038 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
3039 loadmodel->sortedmodelsurfaces[index] = index;
3040 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
3041 loadmodel->data_surfaces[index].num_firstvertex = 0;
3042 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
3045 // copy over the vertex locations and texcoords
3046 for (index = 0;index < numvtxw;index++)
3048 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
3049 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
3050 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
3051 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
3052 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
3055 // loading the faces is complicated because we need to sort them into surfaces by mattindex
3056 for (index = 0;index < numfaces;index++)
3057 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
3058 for (index = 0, i = 0;index < nummatts;index++)
3060 loadmodel->data_surfaces[index].num_firsttriangle = i;
3061 i += loadmodel->data_surfaces[index].num_triangles;
3062 loadmodel->data_surfaces[index].num_triangles = 0;
3064 for (index = 0;index < numfaces;index++)
3066 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
3067 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
3068 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
3069 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
3072 // copy over the bones
3073 for (index = 0;index < numbones;index++)
3075 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
3076 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
3077 if (loadmodel->data_bones[index].parent >= index)
3078 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
3081 // convert the basepose data
3082 if (loadmodel->num_bones)
3085 matrix4x4_t *basebonepose;
3086 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
3087 matrix4x4_t bonematrix;
3088 matrix4x4_t tempbonematrix;
3089 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
3090 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
3092 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]);
3093 if (loadmodel->data_bones[boneindex].parent >= 0)
3095 tempbonematrix = bonematrix;
3096 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3098 basebonepose[boneindex] = bonematrix;
3099 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3100 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3102 Mem_Free(basebonepose);
3105 // sort the psk point weights into the vertex weight tables
3106 // (which only accept up to 4 bones per vertex)
3107 for (index = 0;index < numvtxw;index++)
3109 int weightindex[4] = { 0, 0, 0, 0 };
3110 float weightinfluence[4] = { 0, 0, 0, 0 };
3112 for (j = 0;j < numrawweights;j++)
3114 if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3116 int boneindex = rawweights[j].boneindex;
3117 float influence = rawweights[j].weight;
3118 for (l = 0;l < 4;l++)
3120 if (weightinfluence[l] < influence)
3122 // move lower influence weights out of the way first
3124 for (l2 = 3;l2 > l;l2--)
3126 weightinfluence[l2] = weightinfluence[l2-1];
3127 weightindex[l2] = weightindex[l2-1];
3129 // store the new weight
3130 weightinfluence[l] = influence;
3131 weightindex[l] = boneindex;
3137 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3138 loadmodel->surfmesh.data_skeletalindex4ub[index*4 ] = weightindex[0];
3139 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3140 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3141 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3142 loadmodel->surfmesh.data_skeletalweight4ub[index*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
3143 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3144 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3145 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3147 if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3148 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3150 // set up the animscenes based on the anims
3153 for (index = 0, i = 0;index < numanims;index++)
3155 for (j = 0;j < anims[index].numframes;j++, i++)
3157 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3158 loadmodel->animscenes[i].firstframe = i;
3159 loadmodel->animscenes[i].framecount = 1;
3160 loadmodel->animscenes[i].loop = true;
3161 loadmodel->animscenes[i].framerate = anims[index].fps;
3164 // calculate the scaling value for bone origins so they can be compressed to short
3166 for (index = 0;index < numanimkeys;index++)
3168 pskanimkeys_t *k = animkeys + index;
3169 biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3170 biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3171 biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3173 loadmodel->num_posescale = biggestorigin / 32767.0f;
3174 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3176 // load the poses from the animkeys
3177 for (index = 0;index < numanimkeys;index++)
3179 pskanimkeys_t *k = animkeys + index;
3181 Vector4Copy(k->quat, quat);
3183 Vector4Negate(quat, quat);
3184 Vector4Normalize2(quat, quat);
3185 // compress poses to the short[7] format for longterm storage
3186 loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3187 loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3188 loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3189 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3190 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3191 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3192 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3197 strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3198 loadmodel->animscenes[0].firstframe = 0;
3199 loadmodel->animscenes[0].framecount = 1;
3200 loadmodel->animscenes[0].loop = true;
3201 loadmodel->animscenes[0].framerate = 10;
3203 // calculate the scaling value for bone origins so they can be compressed to short
3205 for (index = 0;index < numbones;index++)
3207 pskboneinfo_t *p = bones + index;
3208 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3209 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3210 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3212 loadmodel->num_posescale = biggestorigin / 32767.0f;
3213 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3215 // load the basepose as a frame
3216 for (index = 0;index < numbones;index++)
3218 pskboneinfo_t *p = bones + index;
3220 Vector4Copy(p->basepose.quat, quat);
3222 Vector4Negate(quat, quat);
3223 Vector4Normalize2(quat, quat);
3224 // compress poses to the short[7] format for longterm storage
3225 loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3226 loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3227 loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3228 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3229 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3230 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3231 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3235 Mod_FreeSkinFiles(skinfiles);
3237 Mem_Free(animfilebuffer);
3238 Mod_MakeSortedSurfaces(loadmodel);
3240 // compute all the mesh information that was not loaded from the file
3241 // TODO: honor smoothing groups somehow?
3242 if (loadmodel->surfmesh.data_element3s)
3243 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3244 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3245 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3246 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);
3247 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);
3248 if (loadmodel->surfmesh.data_neighbor3i)
3249 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
3250 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3251 if(mod_alias_force_animated.string[0])
3252 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3254 if (!loadmodel->surfmesh.isanimated)
3256 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3257 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3258 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3259 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3260 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3261 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3264 // because shaders can do somewhat unexpected things, check for unusual features now
3265 for (i = 0;i < loadmodel->num_textures;i++)
3267 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3268 mod->DrawSky = R_Q1BSP_DrawSky;
3269 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3270 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
3274 void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
3276 unsigned char *data;
3278 const unsigned char *pbase, *pend;
3280 skinfile_t *skinfiles;
3281 int i, j, k, meshvertices, meshtriangles;
3282 float biggestorigin;
3283 const unsigned int *inelements;
3285 const int *inneighbors;
3287 float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3288 // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3289 const float *vnormal = NULL;
3290 const float *vposition = NULL;
3291 const float *vtangent = NULL;
3292 const float *vtexcoord = NULL;
3293 const float *vcolor4f = NULL;
3294 const unsigned char *vblendindexes = NULL;
3295 const unsigned char *vblendweights = NULL;
3296 const unsigned char *vcolor4ub = NULL;
3297 const unsigned short *framedata = NULL;
3298 // temporary memory allocations (because the data in the file may be misaligned)
3299 iqmanim_t *anims = NULL;
3300 iqmbounds_t *bounds = NULL;
3301 iqmjoint1_t *joint1 = NULL;
3302 iqmjoint_t *joint = NULL;
3303 iqmmesh_t *meshes = NULL;
3304 iqmpose1_t *pose1 = NULL;
3305 iqmpose_t *pose = NULL;
3306 iqmvertexarray_t *vas = NULL;
3308 pbase = (unsigned char *)buffer;
3309 pend = (unsigned char *)bufferend;
3311 if (pbase + sizeof(iqmheader_t) > pend)
3312 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3314 // copy struct (otherwise it may be misaligned)
3315 // LordHavoc: okay it's definitely not misaligned here, but for consistency...
3316 memcpy(&header, pbase, sizeof(iqmheader_t));
3318 if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3319 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3320 if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3321 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3323 loadmodel->modeldatatypestring = "IQM";
3325 loadmodel->type = mod_alias;
3326 loadmodel->synctype = ST_RAND;
3329 header.version = LittleLong(header.version);
3330 header.filesize = LittleLong(header.filesize);
3331 header.flags = LittleLong(header.flags);
3332 header.num_text = LittleLong(header.num_text);
3333 header.ofs_text = LittleLong(header.ofs_text);
3334 header.num_meshes = LittleLong(header.num_meshes);
3335 header.ofs_meshes = LittleLong(header.ofs_meshes);
3336 header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3337 header.num_vertexes = LittleLong(header.num_vertexes);
3338 header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3339 header.num_triangles = LittleLong(header.num_triangles);
3340 header.ofs_triangles = LittleLong(header.ofs_triangles);
3341 header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3342 header.num_joints = LittleLong(header.num_joints);
3343 header.ofs_joints = LittleLong(header.ofs_joints);
3344 header.num_poses = LittleLong(header.num_poses);
3345 header.ofs_poses = LittleLong(header.ofs_poses);
3346 header.num_anims = LittleLong(header.num_anims);
3347 header.ofs_anims = LittleLong(header.ofs_anims);
3348 header.num_frames = LittleLong(header.num_frames);
3349 header.num_framechannels = LittleLong(header.num_framechannels);
3350 header.ofs_frames = LittleLong(header.ofs_frames);
3351 header.ofs_bounds = LittleLong(header.ofs_bounds);
3352 header.num_comment = LittleLong(header.num_comment);
3353 header.ofs_comment = LittleLong(header.ofs_comment);
3354 header.num_extensions = LittleLong(header.num_extensions);
3355 header.ofs_extensions = LittleLong(header.ofs_extensions);
3357 if (header.version == 1)
3359 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3360 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3362 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3368 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3369 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3371 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3375 if (pbase + header.ofs_text + header.num_text > pend ||
3376 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3377 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3378 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3379 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3380 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3381 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3382 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3383 pbase + header.ofs_comment + header.num_comment > pend)
3385 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3389 // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3390 if (header.num_vertexarrays)
3391 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3392 if (header.num_anims)
3393 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3394 if (header.ofs_bounds)
3395 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3396 if (header.num_meshes)
3397 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3399 for (i = 0;i < (int)header.num_vertexarrays;i++)
3401 iqmvertexarray_t va;
3403 va.type = LittleLong(vas[i].type);
3404 va.flags = LittleLong(vas[i].flags);
3405 va.format = LittleLong(vas[i].format);
3406 va.size = LittleLong(vas[i].size);
3407 va.offset = LittleLong(vas[i].offset);
3408 vsize = header.num_vertexes*va.size;
3411 case IQM_FLOAT: vsize *= sizeof(float); break;
3412 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3415 if (pbase + va.offset + vsize > pend)
3417 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3421 if (va.format == IQM_FLOAT && va.size == 3)
3422 vposition = (const float *)(pbase + va.offset);
3425 if (va.format == IQM_FLOAT && va.size == 2)
3426 vtexcoord = (const float *)(pbase + va.offset);
3429 if (va.format == IQM_FLOAT && va.size == 3)
3430 vnormal = (const float *)(pbase + va.offset);
3433 if (va.format == IQM_FLOAT && va.size == 4)
3434 vtangent = (const float *)(pbase + va.offset);
3436 case IQM_BLENDINDEXES:
3437 if (va.format == IQM_UBYTE && va.size == 4)
3438 vblendindexes = (const unsigned char *)(pbase + va.offset);
3440 case IQM_BLENDWEIGHTS:
3441 if (va.format == IQM_UBYTE && va.size == 4)
3442 vblendweights = (const unsigned char *)(pbase + va.offset);
3445 if (va.format == IQM_FLOAT && va.size == 4)
3446 vcolor4f = (const float *)(pbase + va.offset);
3447 if (va.format == IQM_UBYTE && va.size == 4)
3448 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3452 if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3454 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3458 text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3460 loadmodel->DrawSky = NULL;
3461 loadmodel->DrawAddWaterPlanes = NULL;
3462 loadmodel->Draw = R_Q1BSP_Draw;
3463 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
3464 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
3465 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
3466 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
3467 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
3468 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
3469 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
3470 loadmodel->DrawLight = R_Q1BSP_DrawLight;
3471 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3472 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3473 loadmodel->PointSuperContents = NULL;
3474 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3476 // load external .skin files if present
3477 skinfiles = Mod_LoadSkinFiles();
3478 if (loadmodel->numskins < 1)
3479 loadmodel->numskins = 1;
3481 loadmodel->numframes = max(header.num_anims, 1);
3482 loadmodel->num_bones = header.num_joints;
3483 loadmodel->num_poses = max(header.num_frames, 1);
3484 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header.num_meshes;
3485 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3486 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3488 meshvertices = header.num_vertexes;
3489 meshtriangles = header.num_triangles;
3491 // do most allocations as one merged chunk
3492 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));
3493 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3494 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3495 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3496 loadmodel->surfmesh.num_vertices = meshvertices;
3497 loadmodel->surfmesh.num_triangles = meshtriangles;
3498 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3499 if (r_enableshadowvolumes.integer)
3501 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3503 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3504 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3505 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3506 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3507 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3508 if (vcolor4f || vcolor4ub)
3510 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]);
3512 if (vblendindexes && vblendweights)
3514 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3515 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3517 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3518 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3519 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3520 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3521 if (vblendindexes && vblendweights)
3523 loadmodel->surfmesh.num_blends = 0;
3524 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3526 if (meshvertices <= 65536)
3528 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3530 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3531 if (vblendindexes && vblendweights)
3532 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3534 for (i = 0;i < loadmodel->numskins;i++)
3536 loadmodel->skinscenes[i].firstframe = i;
3537 loadmodel->skinscenes[i].framecount = 1;
3538 loadmodel->skinscenes[i].loop = true;
3539 loadmodel->skinscenes[i].framerate = 10;
3542 // load the bone info
3543 if (header.version == 1)
3545 iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3546 if (loadmodel->num_bones)
3547 joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3548 for (i = 0;i < loadmodel->num_bones;i++)
3550 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3551 joint1[i].name = LittleLong(injoint1[i].name);
3552 joint1[i].parent = LittleLong(injoint1[i].parent);
3553 for (j = 0;j < 3;j++)
3555 joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
3556 joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
3557 joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
3559 strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3560 loadmodel->data_bones[i].parent = joint1[i].parent;
3561 if (loadmodel->data_bones[i].parent >= i)
3562 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3563 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]);
3564 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3565 if (loadmodel->data_bones[i].parent >= 0)
3567 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3568 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3569 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3571 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3576 iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
3577 if (header.num_joints)
3578 joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3579 for (i = 0;i < loadmodel->num_bones;i++)
3581 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3582 joint[i].name = LittleLong(injoint[i].name);
3583 joint[i].parent = LittleLong(injoint[i].parent);
3584 for (j = 0;j < 3;j++)
3586 joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
3587 joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
3588 joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
3590 joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
3591 strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3592 loadmodel->data_bones[i].parent = joint[i].parent;
3593 if (loadmodel->data_bones[i].parent >= i)
3594 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3595 if (joint[i].rotation[3] > 0)
3596 Vector4Negate(joint[i].rotation, joint[i].rotation);
3597 Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3598 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]);
3599 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3600 if (loadmodel->data_bones[i].parent >= 0)
3602 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3603 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3604 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3606 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3610 // set up the animscenes based on the anims
3611 for (i = 0;i < (int)header.num_anims;i++)
3614 anim.name = LittleLong(anims[i].name);
3615 anim.first_frame = LittleLong(anims[i].first_frame);
3616 anim.num_frames = LittleLong(anims[i].num_frames);
3617 anim.framerate = LittleFloat(anims[i].framerate);
3618 anim.flags = LittleLong(anims[i].flags);
3619 strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3620 loadmodel->animscenes[i].firstframe = anim.first_frame;
3621 loadmodel->animscenes[i].framecount = anim.num_frames;
3622 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3623 loadmodel->animscenes[i].framerate = anim.framerate;
3625 if (header.num_anims <= 0)
3627 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3628 loadmodel->animscenes[0].firstframe = 0;
3629 loadmodel->animscenes[0].framecount = 1;
3630 loadmodel->animscenes[0].loop = true;
3631 loadmodel->animscenes[0].framerate = 10;
3634 loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3635 if(mod_alias_force_animated.string[0])
3636 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3639 if (header.version == 1)
3641 iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3642 if (header.num_poses)
3643 pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3644 for (i = 0;i < (int)header.num_poses;i++)
3647 pose1[i].parent = LittleLong(inpose1[i].parent);
3648 pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
3649 for (j = 0;j < 9;j++)
3651 pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
3652 pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
3654 f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3655 f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3656 f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3657 f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3658 f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3659 f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3661 if (header.num_frames <= 0)
3663 for (i = 0;i < loadmodel->num_bones;i++)
3666 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3667 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3668 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3674 iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
3675 if (header.num_poses)
3676 pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3677 for (i = 0;i < (int)header.num_poses;i++)
3680 pose[i].parent = LittleLong(inpose[i].parent);
3681 pose[i].channelmask = LittleLong(inpose[i].channelmask);
3682 for (j = 0;j < 10;j++)
3684 pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
3685 pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
3687 f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3688 f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3689 f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3690 f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3691 f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3692 f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3694 if (header.num_frames <= 0)
3696 for (i = 0;i < loadmodel->num_bones;i++)
3699 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3700 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3701 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3705 loadmodel->num_posescale = biggestorigin / 32767.0f;
3706 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3708 // load the pose data
3709 // this unaligned memory access is safe (LittleShort reads as bytes)
3710 framedata = (const unsigned short *)(pbase + header.ofs_frames);
3711 if (header.version == 1)
3713 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3715 for (j = 0;j < (int)header.num_poses;j++, k++)
3717 float qx, qy, qz, qw;
3718 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));
3719 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));
3720 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));
3721 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3722 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3723 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3724 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3725 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3726 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3727 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3728 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3729 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3730 // skip scale data for now
3731 if(pose1[j].channelmask&64) framedata++;
3732 if(pose1[j].channelmask&128) framedata++;
3733 if(pose1[j].channelmask&256) framedata++;
3736 if (header.num_frames <= 0)
3738 for (i = 0;i < loadmodel->num_bones;i++)
3740 float qx, qy, qz, qw;
3741 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3742 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3743 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3744 qx = joint1[i].rotation[0];
3745 qy = joint1[i].rotation[1];
3746 qz = joint1[i].rotation[2];
3747 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3748 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3749 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3750 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3751 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3752 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3758 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3760 for (j = 0;j < (int)header.num_poses;j++, k++)
3763 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));
3764 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));
3765 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));
3766 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3767 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3768 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3769 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3771 Vector4Negate(rot, rot);
3772 Vector4Normalize2(rot, rot);
3773 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3774 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3775 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3776 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3777 // skip scale data for now
3778 if(pose[j].channelmask&128) framedata++;
3779 if(pose[j].channelmask&256) framedata++;
3780 if(pose[j].channelmask&512) framedata++;
3783 if (header.num_frames <= 0)
3785 for (i = 0;i < loadmodel->num_bones;i++)
3787 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3788 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3789 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3790 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3791 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3792 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3793 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3798 // load bounding box data
3799 if (header.ofs_bounds)
3801 float xyradius = 0, radius = 0;
3802 VectorClear(loadmodel->normalmins);
3803 VectorClear(loadmodel->normalmaxs);
3804 for (i = 0; i < (int)header.num_frames;i++)
3807 bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3808 bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3809 bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3810 bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);
3811 bound.maxs[1] = LittleFloat(bounds[i].maxs[1]);
3812 bound.maxs[2] = LittleFloat(bounds[i].maxs[2]);
3813 bound.xyradius = LittleFloat(bounds[i].xyradius);
3814 bound.radius = LittleFloat(bounds[i].radius);
3817 VectorCopy(bound.mins, loadmodel->normalmins);
3818 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3822 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3823 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3824 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3825 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3826 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3827 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3829 if (bound.xyradius > xyradius)
3830 xyradius = bound.xyradius;
3831 if (bound.radius > radius)
3832 radius = bound.radius;
3834 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3835 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3836 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3837 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3838 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3839 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3840 loadmodel->radius = radius;
3841 loadmodel->radius2 = radius * radius;
3844 // load triangle data
3845 // this unaligned memory access is safe (LittleLong reads as bytes)
3846 inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3847 outelements = loadmodel->surfmesh.data_element3i;
3848 for (i = 0;i < (int)header.num_triangles;i++)
3850 outelements[0] = LittleLong(inelements[0]);
3851 outelements[1] = LittleLong(inelements[1]);
3852 outelements[2] = LittleLong(inelements[2]);
3856 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3858 if (header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
3860 // this unaligned memory access is safe (LittleLong reads as bytes)
3861 inneighbors = (const int *)(pbase + header.ofs_neighbors);
3862 outneighbors = loadmodel->surfmesh.data_neighbor3i;
3863 for (i = 0;i < (int)header.num_triangles;i++)
3865 outneighbors[0] = LittleLong(inneighbors[0]);
3866 outneighbors[1] = LittleLong(inneighbors[1]);
3867 outneighbors[2] = LittleLong(inneighbors[2]);
3874 // this unaligned memory access is safe (LittleFloat reads as bytes)
3875 outvertex = loadmodel->surfmesh.data_vertex3f;
3876 for (i = 0;i < (int)header.num_vertexes;i++)
3878 outvertex[0] = LittleFloat(vposition[0]);
3879 outvertex[1] = LittleFloat(vposition[1]);
3880 outvertex[2] = LittleFloat(vposition[2]);
3885 outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3886 // this unaligned memory access is safe (LittleFloat reads as bytes)
3887 for (i = 0;i < (int)header.num_vertexes;i++)
3889 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3890 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3895 // this unaligned memory access is safe (LittleFloat reads as bytes)
3898 outnormal = loadmodel->surfmesh.data_normal3f;
3899 for (i = 0;i < (int)header.num_vertexes;i++)
3901 outnormal[0] = LittleFloat(vnormal[0]);
3902 outnormal[1] = LittleFloat(vnormal[1]);
3903 outnormal[2] = LittleFloat(vnormal[2]);
3909 // this unaligned memory access is safe (LittleFloat reads as bytes)
3910 if(vnormal && vtangent)
3912 outnormal = loadmodel->surfmesh.data_normal3f;
3913 outsvector = loadmodel->surfmesh.data_svector3f;
3914 outtvector = loadmodel->surfmesh.data_tvector3f;
3915 for (i = 0;i < (int)header.num_vertexes;i++)
3917 outsvector[0] = LittleFloat(vtangent[0]);
3918 outsvector[1] = LittleFloat(vtangent[1]);
3919 outsvector[2] = LittleFloat(vtangent[2]);
3920 if(LittleFloat(vtangent[3]) < 0)
3921 CrossProduct(outsvector, outnormal, outtvector);
3923 CrossProduct(outnormal, outsvector, outtvector);
3931 // this unaligned memory access is safe (all bytes)
3932 if (vblendindexes && vblendweights)
3934 for (i = 0; i < (int)header.num_vertexes;i++)
3936 blendweights_t weights;
3937 memcpy(weights.index, vblendindexes + i*4, 4);
3938 memcpy(weights.influence, vblendweights + i*4, 4);
3939 loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3940 loadmodel->surfmesh.data_skeletalindex4ub[i*4 ] = weights.index[0];
3941 loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3942 loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3943 loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3944 loadmodel->surfmesh.data_skeletalweight4ub[i*4 ] = weights.influence[0];
3945 loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3946 loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3947 loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3953 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3954 // this unaligned memory access is safe (LittleFloat reads as bytes)
3955 for (i = 0;i < (int)header.num_vertexes;i++)
3957 outcolor[0] = LittleFloat(vcolor4f[0]);
3958 outcolor[1] = LittleFloat(vcolor4f[1]);
3959 outcolor[2] = LittleFloat(vcolor4f[2]);
3960 outcolor[3] = LittleFloat(vcolor4f[3]);
3967 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3968 // this unaligned memory access is safe (all bytes)
3969 for (i = 0;i < (int)header.num_vertexes;i++)
3971 outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3972 outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3973 outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3974 outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3981 for (i = 0;i < (int)header.num_meshes;i++)
3984 msurface_t *surface;
3986 mesh.name = LittleLong(meshes[i].name);
3987 mesh.material = LittleLong(meshes[i].material);
3988 mesh.first_vertex = LittleLong(meshes[i].first_vertex);
3989 mesh.num_vertexes = LittleLong(meshes[i].num_vertexes);
3990 mesh.first_triangle = LittleLong(meshes[i].first_triangle);
3991 mesh.num_triangles = LittleLong(meshes[i].num_triangles);
3993 loadmodel->sortedmodelsurfaces[i] = i;
3994 surface = loadmodel->data_surfaces + i;
3995 surface->texture = loadmodel->data_textures + i;
3996 surface->num_firsttriangle = mesh.first_triangle;
3997 surface->num_triangles = mesh.num_triangles;
3998 surface->num_firstvertex = mesh.first_vertex;
3999 surface->num_vertices = mesh.num_vertexes;
4001 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
4004 Mod_FreeSkinFiles(skinfiles);
4005 Mod_MakeSortedSurfaces(loadmodel);
4007 // compute all the mesh information that was not loaded from the file
4008 if (loadmodel->surfmesh.data_element3s)
4009 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
4010 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
4012 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);
4013 if (!vnormal || !vtangent)
4014 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);
4015 if (!header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
4016 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
4017 if (!header.ofs_bounds)
4018 Mod_Alias_CalculateBoundingBox();
4020 if (!loadmodel->surfmesh.isanimated && loadmodel->surfmesh.num_triangles >= 1)
4022 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
4023 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
4024 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
4025 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
4026 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
4027 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
4030 if (joint ) Mem_Free(joint );joint = NULL;
4031 if (joint1 ) Mem_Free(joint1 );joint1 = NULL;
4032 if (pose ) Mem_Free(pose );pose = NULL;
4033 if (pose1 ) Mem_Free(pose1 );pose1 = NULL;
4035 // because shaders can do somewhat unexpected things, check for unusual features now
4036 for (i = 0;i < loadmodel->num_textures;i++)
4038 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
4039 mod->DrawSky = R_Q1BSP_DrawSky;
4040 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
4041 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;