2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "mod_skeletal_animatevertices_generic.h"
26 #include "mod_skeletal_animatevertices_sse.h"
30 static qboolean r_skeletal_use_sse_defined = false;
31 cvar_t r_skeletal_use_sse = {0, "r_skeletal_use_sse", "1", "use SSE for skeletal model animation"};
33 cvar_t r_skeletal_debugbone = {0, "r_skeletal_debugbone", "-1", "development cvar for testing skeletal model code"};
34 cvar_t r_skeletal_debugbonecomponent = {0, "r_skeletal_debugbonecomponent", "3", "development cvar for testing skeletal model code"};
35 cvar_t r_skeletal_debugbonevalue = {0, "r_skeletal_debugbonevalue", "100", "development cvar for testing skeletal model code"};
36 cvar_t r_skeletal_debugtranslatex = {0, "r_skeletal_debugtranslatex", "1", "development cvar for testing skeletal model code"};
37 cvar_t r_skeletal_debugtranslatey = {0, "r_skeletal_debugtranslatey", "1", "development cvar for testing skeletal model code"};
38 cvar_t r_skeletal_debugtranslatez = {0, "r_skeletal_debugtranslatez", "1", "development cvar for testing skeletal model code"};
39 cvar_t mod_alias_supporttagscale = {0, "mod_alias_supporttagscale", "1", "support scaling factors in bone/tag attachment matrices as supported by MD3"};
40 cvar_t mod_alias_force_animated = {0, "mod_alias_force_animated", "", "if set to an non-empty string, overrides the is-animated flag of any alias models (for benchmarking)"};
42 float mod_md3_sin[320];
44 static size_t Mod_Skeletal_AnimateVertices_maxbonepose = 0;
45 static void *Mod_Skeletal_AnimateVertices_bonepose = NULL;
46 void Mod_Skeletal_FreeBuffers(void)
48 if(Mod_Skeletal_AnimateVertices_bonepose)
49 Mem_Free(Mod_Skeletal_AnimateVertices_bonepose);
50 Mod_Skeletal_AnimateVertices_maxbonepose = 0;
51 Mod_Skeletal_AnimateVertices_bonepose = NULL;
53 void *Mod_Skeletal_AnimateVertices_AllocBuffers(size_t nbytes)
55 if(Mod_Skeletal_AnimateVertices_maxbonepose < nbytes)
57 if(Mod_Skeletal_AnimateVertices_bonepose)
58 Mem_Free(Mod_Skeletal_AnimateVertices_bonepose);
59 Mod_Skeletal_AnimateVertices_bonepose = Z_Malloc(nbytes);
60 Mod_Skeletal_AnimateVertices_maxbonepose = nbytes;
62 return Mod_Skeletal_AnimateVertices_bonepose;
65 void Mod_Skeletal_BuildTransforms(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT bonepose, float * RESTRICT boneposerelative)
71 bonepose = (float * RESTRICT) Mod_Skeletal_AnimateVertices_AllocBuffers(sizeof(float[12]) * model->num_bones);
73 if (skeleton && !skeleton->relativetransforms)
76 // interpolate matrices
79 for (i = 0;i < model->num_bones;i++)
81 Matrix4x4_ToArray12FloatD3D(&skeleton->relativetransforms[i], m);
82 if (model->data_bones[i].parent >= 0)
83 R_ConcatTransforms(bonepose + model->data_bones[i].parent * 12, m, bonepose + i * 12);
85 memcpy(bonepose + i * 12, m, sizeof(m));
87 // create a relative deformation matrix to describe displacement
88 // from the base mesh, which is used by the actual weighting
89 R_ConcatTransforms(bonepose + i * 12, model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12);
94 for (i = 0;i < model->num_bones;i++)
96 // blend by transform each quaternion/translation into a dual-quaternion first, then blending
97 const short * RESTRICT firstpose7s = model->data_poses7s + 7 * (frameblend[0].subframe * model->num_bones + i);
98 float firstlerp = frameblend[0].lerp,
99 firsttx = firstpose7s[0], firstty = firstpose7s[1], firsttz = firstpose7s[2],
100 rx = firstpose7s[3] * firstlerp,
101 ry = firstpose7s[4] * firstlerp,
102 rz = firstpose7s[5] * firstlerp,
103 rw = firstpose7s[6] * firstlerp,
104 dx = firsttx*rw + firstty*rz - firsttz*ry,
105 dy = -firsttx*rz + firstty*rw + firsttz*rx,
106 dz = firsttx*ry - firstty*rx + firsttz*rw,
107 dw = -firsttx*rx - firstty*ry - firsttz*rz,
108 scale, sx, sy, sz, sw;
109 for (blends = 1;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
111 const short * RESTRICT blendpose7s = model->data_poses7s + 7 * (frameblend[blends].subframe * model->num_bones + i);
112 float blendlerp = frameblend[blends].lerp,
113 blendtx = blendpose7s[0], blendty = blendpose7s[1], blendtz = blendpose7s[2],
114 qx = blendpose7s[3], qy = blendpose7s[4], qz = blendpose7s[5], qw = blendpose7s[6];
115 if(rx*qx + ry*qy + rz*qz + rw*qw < 0) blendlerp = -blendlerp;
124 dx += blendtx*qw + blendty*qz - blendtz*qy;
125 dy += -blendtx*qz + blendty*qw + blendtz*qx;
126 dz += blendtx*qy - blendty*qx + blendtz*qw;
127 dw += -blendtx*qx - blendty*qy - blendtz*qz;
129 // generate a matrix from the dual-quaternion, implicitly normalizing it in the process
130 scale = 1.0f / (rx*rx + ry*ry + rz*rz + rw*rw);
135 m[0] = sw*rw + sx*rx - sy*ry - sz*rz;
136 m[1] = 2*(sx*ry - sw*rz);
137 m[2] = 2*(sx*rz + sw*ry);
138 m[3] = model->num_posescale*(dx*sw - dy*sz + dz*sy - dw*sx);
139 m[4] = 2*(sx*ry + sw*rz);
140 m[5] = sw*rw + sy*ry - sx*rx - sz*rz;
141 m[6] = 2*(sy*rz - sw*rx);
142 m[7] = model->num_posescale*(dx*sz + dy*sw - dz*sx - dw*sy);
143 m[8] = 2*(sx*rz - sw*ry);
144 m[9] = 2*(sy*rz + sw*rx);
145 m[10] = sw*rw + sz*rz - sx*rx - sy*ry;
146 m[11] = model->num_posescale*(dy*sx + dz*sw - dx*sy - dw*sz);
147 if (i == r_skeletal_debugbone.integer)
148 m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value;
149 m[3] *= r_skeletal_debugtranslatex.value;
150 m[7] *= r_skeletal_debugtranslatey.value;
151 m[11] *= r_skeletal_debugtranslatez.value;
152 if (model->data_bones[i].parent >= 0)
153 R_ConcatTransforms(bonepose + model->data_bones[i].parent * 12, m, bonepose + i * 12);
155 memcpy(bonepose + i * 12, m, sizeof(m));
156 // create a relative deformation matrix to describe displacement
157 // from the base mesh, which is used by the actual weighting
158 R_ConcatTransforms(bonepose + i * 12, model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12);
163 static void Mod_Skeletal_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
166 if (!model->surfmesh.num_vertices)
169 if (!model->num_bones)
171 if (vertex3f) memcpy(vertex3f, model->surfmesh.data_vertex3f, model->surfmesh.num_vertices*sizeof(float[3]));
172 if (normal3f) memcpy(normal3f, model->surfmesh.data_normal3f, model->surfmesh.num_vertices*sizeof(float[3]));
173 if (svector3f) memcpy(svector3f, model->surfmesh.data_svector3f, model->surfmesh.num_vertices*sizeof(float[3]));
174 if (tvector3f) memcpy(tvector3f, model->surfmesh.data_tvector3f, model->surfmesh.num_vertices*sizeof(float[3]));
179 if(r_skeletal_use_sse_defined)
180 if(r_skeletal_use_sse.integer)
182 Mod_Skeletal_AnimateVertices_SSE(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f);
186 Mod_Skeletal_AnimateVertices_Generic(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f);
189 void Mod_AliasInit (void)
192 Cvar_RegisterVariable(&r_skeletal_debugbone);
193 Cvar_RegisterVariable(&r_skeletal_debugbonecomponent);
194 Cvar_RegisterVariable(&r_skeletal_debugbonevalue);
195 Cvar_RegisterVariable(&r_skeletal_debugtranslatex);
196 Cvar_RegisterVariable(&r_skeletal_debugtranslatey);
197 Cvar_RegisterVariable(&r_skeletal_debugtranslatez);
198 Cvar_RegisterVariable(&mod_alias_supporttagscale);
199 Cvar_RegisterVariable(&mod_alias_force_animated);
200 for (i = 0;i < 320;i++)
201 mod_md3_sin[i] = sin(i * M_PI * 2.0f / 256.0);
205 Con_Printf("Skeletal animation uses SSE code path\n");
206 r_skeletal_use_sse_defined = true;
207 Cvar_RegisterVariable(&r_skeletal_use_sse);
210 Con_Printf("Skeletal animation uses generic code path (SSE disabled or not detected)\n");
212 Con_Printf("Skeletal animation uses generic code path (SSE not compiled in)\n");
216 static int Mod_Skeletal_AddBlend(dp_model_t *model, const blendweights_t *newweights)
219 blendweights_t *weights;
220 if(!newweights->influence[1])
221 return newweights->index[0];
222 weights = model->surfmesh.data_blendweights;
223 for (i = 0;i < model->surfmesh.num_blends;i++, weights++)
225 if (!memcmp(weights, newweights, sizeof(blendweights_t)))
226 return model->num_bones + i;
228 model->surfmesh.num_blends++;
229 memcpy(weights, newweights, sizeof(blendweights_t));
230 return model->num_bones + i;
233 static int Mod_Skeletal_CompressBlend(dp_model_t *model, const int *newindex, const float *newinfluence)
237 blendweights_t newweights;
241 for (i = 0;i < 4;i++)
242 scale += newinfluence[i];
243 scale = 255.0f / scale;
245 for (i = 0;i < 4;i++)
247 newweights.index[i] = newindex[i];
248 newweights.influence[i] = (unsigned char)(newinfluence[i] * scale);
249 total += newweights.influence[i];
253 for (i = 0;i < 4;i++)
255 if(newweights.influence[i] > 0 && total > 255)
257 newweights.influence[i]--;
264 for (i = 0; i < 4;i++)
266 if(newweights.influence[i] < 255 && total < 255)
268 newweights.influence[i]++;
273 return Mod_Skeletal_AddBlend(model, &newweights);
276 static void Mod_MD3_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
279 int i, numblends, blendnum;
280 int numverts = model->surfmesh.num_vertices;
282 for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
284 //VectorMA(translate, model->surfmesh.num_morphmdlframetranslate, frameblend[blendnum].lerp, translate);
285 if (frameblend[blendnum].lerp > 0)
286 numblends = blendnum + 1;
288 // special case for the first blend because it avoids some adds and the need to memset the arrays first
289 for (blendnum = 0;blendnum < numblends;blendnum++)
291 const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].subframe;
294 float scale = frameblend[blendnum].lerp * (1.0f / 64.0f);
297 for (i = 0;i < numverts;i++)
299 vertex3f[i * 3 + 0] = verts[i].origin[0] * scale;
300 vertex3f[i * 3 + 1] = verts[i].origin[1] * scale;
301 vertex3f[i * 3 + 2] = verts[i].origin[2] * scale;
306 for (i = 0;i < numverts;i++)
308 vertex3f[i * 3 + 0] += verts[i].origin[0] * scale;
309 vertex3f[i * 3 + 1] += verts[i].origin[1] * scale;
310 vertex3f[i * 3 + 2] += verts[i].origin[2] * scale;
314 // the yaw and pitch stored in md3 models are 8bit quantized angles
315 // (0-255), and as such a lookup table is very well suited to
316 // decoding them, and since cosine is equivalent to sine with an
317 // extra 45 degree rotation, this uses one lookup table for both
318 // sine and cosine with a +64 bias to get cosine.
321 float lerp = frameblend[blendnum].lerp;
324 for (i = 0;i < numverts;i++)
326 normal3f[i * 3 + 0] = mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch ] * lerp;
327 normal3f[i * 3 + 1] = mod_md3_sin[verts[i].yaw ] * mod_md3_sin[verts[i].pitch ] * lerp;
328 normal3f[i * 3 + 2] = mod_md3_sin[verts[i].pitch + 64] * lerp;
333 for (i = 0;i < numverts;i++)
335 normal3f[i * 3 + 0] += mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch ] * lerp;
336 normal3f[i * 3 + 1] += mod_md3_sin[verts[i].yaw ] * mod_md3_sin[verts[i].pitch ] * lerp;
337 normal3f[i * 3 + 2] += mod_md3_sin[verts[i].pitch + 64] * lerp;
343 const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
344 float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
347 for (i = 0;i < numverts;i++, texvecvert++)
349 VectorScale(texvecvert->svec, f, svector3f + i*3);
350 VectorScale(texvecvert->tvec, f, tvector3f + i*3);
355 for (i = 0;i < numverts;i++, texvecvert++)
357 VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
358 VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
364 static void Mod_MDL_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
367 int i, numblends, blendnum;
368 int numverts = model->surfmesh.num_vertices;
370 VectorClear(translate);
372 // blend the frame translates to avoid redundantly doing so on each vertex
373 // (a bit of a brain twister but it works)
374 for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
376 if (model->surfmesh.data_morphmd2framesize6f)
377 VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6 + 3, translate);
379 VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.num_morphmdlframetranslate, translate);
380 if (frameblend[blendnum].lerp > 0)
381 numblends = blendnum + 1;
383 // special case for the first blend because it avoids some adds and the need to memset the arrays first
384 for (blendnum = 0;blendnum < numblends;blendnum++)
386 const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].subframe;
390 if (model->surfmesh.data_morphmd2framesize6f)
391 VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6, frameblend[blendnum].lerp, scale);
393 VectorScale(model->surfmesh.num_morphmdlframescale, frameblend[blendnum].lerp, scale);
396 for (i = 0;i < numverts;i++)
398 vertex3f[i * 3 + 0] = translate[0] + verts[i].v[0] * scale[0];
399 vertex3f[i * 3 + 1] = translate[1] + verts[i].v[1] * scale[1];
400 vertex3f[i * 3 + 2] = translate[2] + verts[i].v[2] * scale[2];
405 for (i = 0;i < numverts;i++)
407 vertex3f[i * 3 + 0] += verts[i].v[0] * scale[0];
408 vertex3f[i * 3 + 1] += verts[i].v[1] * scale[1];
409 vertex3f[i * 3 + 2] += verts[i].v[2] * scale[2];
413 // the vertex normals in mdl models are an index into a table of
414 // 162 unique values, this very crude quantization reduces the
415 // vertex normal to only one byte, which saves a lot of space but
416 // also makes lighting pretty coarse
419 float lerp = frameblend[blendnum].lerp;
422 for (i = 0;i < numverts;i++)
424 const float *vn = m_bytenormals[verts[i].lightnormalindex];
425 VectorScale(vn, lerp, normal3f + i*3);
430 for (i = 0;i < numverts;i++)
432 const float *vn = m_bytenormals[verts[i].lightnormalindex];
433 VectorMA(normal3f + i*3, lerp, vn, normal3f + i*3);
439 const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
440 float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
443 for (i = 0;i < numverts;i++, texvecvert++)
445 VectorScale(texvecvert->svec, f, svector3f + i*3);
446 VectorScale(texvecvert->tvec, f, tvector3f + i*3);
451 for (i = 0;i < numverts;i++, texvecvert++)
453 VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
454 VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
461 int Mod_Alias_GetTagMatrix(const dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, matrix4x4_t *outmatrix)
464 matrix4x4_t parentbonematrix;
465 matrix4x4_t tempbonematrix;
466 matrix4x4_t bonematrix;
467 matrix4x4_t blendmatrix;
474 *outmatrix = identitymatrix;
475 if (skeleton && skeleton->relativetransforms)
477 if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
479 *outmatrix = skeleton->relativetransforms[tagindex];
480 while ((tagindex = model->data_bones[tagindex].parent) >= 0)
483 Matrix4x4_Concat(outmatrix, &skeleton->relativetransforms[tagindex], &temp);
486 else if (model->num_bones)
488 if (tagindex < 0 || tagindex >= model->num_bones)
490 Matrix4x4_Clear(&blendmatrix);
491 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
493 lerp = frameblend[blendindex].lerp;
494 Matrix4x4_FromBonePose7s(&bonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + tagindex));
495 parenttagindex = tagindex;
496 while ((parenttagindex = model->data_bones[parenttagindex].parent) >= 0)
498 Matrix4x4_FromBonePose7s(&parentbonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + parenttagindex));
499 tempbonematrix = bonematrix;
500 Matrix4x4_Concat(&bonematrix, &parentbonematrix, &tempbonematrix);
502 Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
504 *outmatrix = blendmatrix;
506 else if (model->num_tags)
508 if (tagindex < 0 || tagindex >= model->num_tags)
510 for (k = 0;k < 12;k++)
512 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
514 lerp = frameblend[blendindex].lerp;
515 input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
516 for (k = 0;k < 12;k++)
517 blendtag[k] += input[k] * lerp;
519 Matrix4x4_FromArray12FloatGL(outmatrix, blendtag);
522 if(!mod_alias_supporttagscale.integer)
523 Matrix4x4_Normalize3(outmatrix, outmatrix);
528 int Mod_Alias_GetExtendedTagInfoForIndex(const dp_model_t *model, unsigned int skin, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
533 matrix4x4_t bonematrix;
534 matrix4x4_t blendmatrix;
538 if (skeleton && skeleton->relativetransforms)
540 if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
542 *parentindex = skeleton->model->data_bones[tagindex].parent;
543 *tagname = skeleton->model->data_bones[tagindex].name;
544 *tag_localmatrix = skeleton->relativetransforms[tagindex];
547 else if (model->num_bones)
549 if (tagindex < 0 || tagindex >= model->num_bones)
551 *parentindex = model->data_bones[tagindex].parent;
552 *tagname = model->data_bones[tagindex].name;
553 Matrix4x4_Clear(&blendmatrix);
554 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
556 lerp = frameblend[blendindex].lerp;
557 Matrix4x4_FromBonePose7s(&bonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + tagindex));
558 Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
560 *tag_localmatrix = blendmatrix;
563 else if (model->num_tags)
565 if (tagindex < 0 || tagindex >= model->num_tags)
568 *tagname = model->data_tags[tagindex].name;
569 for (k = 0;k < 12;k++)
571 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
573 lerp = frameblend[blendindex].lerp;
574 input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
575 for (k = 0;k < 12;k++)
576 blendtag[k] += input[k] * lerp;
578 Matrix4x4_FromArray12FloatGL(tag_localmatrix, blendtag);
585 int Mod_Alias_GetTagIndexForName(const dp_model_t *model, unsigned int skin, const char *tagname)
588 if(skin >= (unsigned int)model->numskins)
590 if (model->num_bones)
591 for (i = 0;i < model->num_bones;i++)
592 if (!strcasecmp(tagname, model->data_bones[i].name))
595 for (i = 0;i < model->num_tags;i++)
596 if (!strcasecmp(tagname, model->data_tags[i].name))
601 static void Mod_BuildBaseBonePoses(void)
604 matrix4x4_t *basebonepose;
605 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
606 matrix4x4_t bonematrix;
607 matrix4x4_t tempbonematrix;
608 if (!loadmodel->num_bones)
610 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
611 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
613 Matrix4x4_FromBonePose7s(&bonematrix, loadmodel->num_posescale, loadmodel->data_poses7s + 7 * boneindex);
614 if (loadmodel->data_bones[boneindex].parent >= 0)
616 tempbonematrix = bonematrix;
617 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
619 basebonepose[boneindex] = bonematrix;
620 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
621 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
623 Mem_Free(basebonepose);
626 static qboolean Mod_Alias_CalculateBoundingBox(void)
629 qboolean firstvertex = true;
630 float dist, yawradius, radius;
632 qboolean isanimated = false;
633 VectorClear(loadmodel->normalmins);
634 VectorClear(loadmodel->normalmaxs);
637 if (loadmodel->AnimateVertices)
639 float *vertex3f, *refvertex3f;
640 frameblend_t frameblend[MAX_FRAMEBLENDS];
641 memset(frameblend, 0, sizeof(frameblend));
642 frameblend[0].lerp = 1;
643 vertex3f = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]) * 2);
645 for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++)
647 loadmodel->AnimateVertices(loadmodel, frameblend, NULL, vertex3f, NULL, NULL, NULL);
650 // make a copy of the first frame for comparing all others
651 refvertex3f = vertex3f + loadmodel->surfmesh.num_vertices * 3;
652 memcpy(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
656 if (!isanimated && memcmp(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3])))
659 for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
664 VectorCopy(v, loadmodel->normalmins);
665 VectorCopy(v, loadmodel->normalmaxs);
669 if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
670 if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
671 if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
672 if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
673 if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
674 if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
676 dist = v[0] * v[0] + v[1] * v[1];
677 if (yawradius < dist)
689 for (vnum = 0, v = loadmodel->surfmesh.data_vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
694 VectorCopy(v, loadmodel->normalmins);
695 VectorCopy(v, loadmodel->normalmaxs);
699 if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
700 if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
701 if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
702 if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
703 if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
704 if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
706 dist = v[0] * v[0] + v[1] * v[1];
707 if (yawradius < dist)
714 radius = sqrt(radius);
715 yawradius = sqrt(yawradius);
716 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius;
717 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = yawradius;
718 loadmodel->yawmins[2] = loadmodel->normalmins[2];
719 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
720 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
721 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
722 loadmodel->radius = radius;
723 loadmodel->radius2 = radius * radius;
727 static void Mod_Alias_MorphMesh_CompileFrames(void)
730 frameblend_t frameblend[MAX_FRAMEBLENDS];
731 unsigned char *datapointer;
732 memset(frameblend, 0, sizeof(frameblend));
733 frameblend[0].lerp = 1;
734 datapointer = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * (sizeof(float[3]) * 4 + loadmodel->surfmesh.num_morphframes * sizeof(texvecvertex_t)));
735 loadmodel->surfmesh.data_vertex3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
736 loadmodel->surfmesh.data_svector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
737 loadmodel->surfmesh.data_tvector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
738 loadmodel->surfmesh.data_normal3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
739 loadmodel->surfmesh.data_morphtexvecvertex = (texvecvertex_t *)datapointer;datapointer += loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices * sizeof(texvecvertex_t);
740 // this counts down from the last frame to the first so that the final data in surfmesh is for frame zero (which is what the renderer expects to be there)
741 for (i = loadmodel->surfmesh.num_morphframes-1;i >= 0;i--)
743 frameblend[0].subframe = i;
744 loadmodel->AnimateVertices(loadmodel, frameblend, NULL, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_normal3f, NULL, NULL);
745 Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
746 // encode the svector and tvector in 3 byte format for permanent storage
747 for (j = 0;j < loadmodel->surfmesh.num_vertices;j++)
749 VectorScaleCast(loadmodel->surfmesh.data_svector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].svec);
750 VectorScaleCast(loadmodel->surfmesh.data_tvector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].tvec);
755 static void Mod_MDLMD2MD3_TraceLine(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
758 float segmentmins[3], segmentmaxs[3];
760 float vertex3fbuf[1024 * 3];
761 float *vertex3f = vertex3fbuf;
762 float *freevertex3f = NULL;
763 // for static cases we can just call CollisionBIH which is much faster
764 if ((frameblend == NULL || (frameblend[0].subframe == 0 && frameblend[1].lerp == 0)) && (skeleton == NULL || skeleton->relativetransforms == NULL))
766 Mod_CollisionBIH_TraceLine(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
769 memset(trace, 0, sizeof(*trace));
771 trace->hitsupercontentsmask = hitsupercontentsmask;
772 trace->skipsupercontentsmask = skipsupercontentsmask;
773 trace->skipmaterialflagsmask = skipmaterialflagsmask;
774 segmentmins[0] = min(start[0], end[0]) - 1;
775 segmentmins[1] = min(start[1], end[1]) - 1;
776 segmentmins[2] = min(start[2], end[2]) - 1;
777 segmentmaxs[0] = max(start[0], end[0]) + 1;
778 segmentmaxs[1] = max(start[1], end[1]) + 1;
779 segmentmaxs[2] = max(start[2], end[2]) + 1;
780 if (frameblend == NULL || frameblend[0].subframe != 0 || frameblend[0].lerp != 0 || skeleton != NULL)
782 if (model->surfmesh.num_vertices > 1024)
783 vertex3f = freevertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
784 model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
787 vertex3f = model->surfmesh.data_vertex3f;
788 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
789 Collision_TraceLineTriangleMeshFloat(trace, start, end, 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);
791 Mem_Free(freevertex3f);
794 static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
797 vec3_t shiftstart, shiftend;
798 float segmentmins[3], segmentmaxs[3];
800 float vertex3fbuf[1024*3];
801 float *vertex3f = vertex3fbuf;
802 colboxbrushf_t thisbrush_start, thisbrush_end;
803 vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
805 if (VectorCompare(boxmins, boxmaxs))
807 VectorAdd(start, boxmins, shiftstart);
808 VectorAdd(end, boxmins, shiftend);
809 Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
810 VectorSubtract(trace->endpos, boxmins, trace->endpos);
814 // for static cases we can just call CollisionBIH which is much faster
815 if ((frameblend == NULL || (frameblend[0].subframe == 0 && frameblend[1].lerp == 0)) && (skeleton == NULL || skeleton->relativetransforms == NULL))
817 Mod_CollisionBIH_TraceBox(model, frameblend, skeleton, trace, start, boxmins, boxmaxs, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
821 // box trace, performed as brush trace
822 memset(trace, 0, sizeof(*trace));
824 trace->hitsupercontentsmask = hitsupercontentsmask;
825 trace->skipsupercontentsmask = skipsupercontentsmask;
826 trace->skipmaterialflagsmask = skipmaterialflagsmask;
827 if (model->surfmesh.num_vertices > 1024)
828 vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
829 segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1;
830 segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1;
831 segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1;
832 segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1;
833 segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1;
834 segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1;
835 VectorAdd(start, boxmins, boxstartmins);
836 VectorAdd(start, boxmaxs, boxstartmaxs);
837 VectorAdd(end, boxmins, boxendmins);
838 VectorAdd(end, boxmaxs, boxendmaxs);
839 Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL);
840 Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL);
841 model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
842 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
843 Collision_TraceBrushTriangleMeshFloat(trace, &thisbrush_start.brush, &thisbrush_end.brush, 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);
844 if (vertex3f != vertex3fbuf)
848 static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap)
851 for (i = 0;i < inverts;i++)
853 if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
855 j = vertremap[i]; // not onseam
858 j = vertremap[i+inverts]; // onseam
864 static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *vertremap)
866 int i, f, pose, groupframes;
868 daliasframetype_t *pframetype;
869 daliasframe_t *pinframe;
870 daliasgroup_t *group;
871 daliasinterval_t *intervals;
874 scene = loadmodel->animscenes;
875 for (f = 0;f < loadmodel->numframes;f++)
877 pframetype = (daliasframetype_t *)datapointer;
878 datapointer += sizeof(daliasframetype_t);
879 if (LittleLong (pframetype->type) == ALIAS_SINGLE)
881 // a single frame is still treated as a group
888 group = (daliasgroup_t *)datapointer;
889 datapointer += sizeof(daliasgroup_t);
890 groupframes = LittleLong (group->numframes);
892 // intervals (time per frame)
893 intervals = (daliasinterval_t *)datapointer;
894 datapointer += sizeof(daliasinterval_t) * groupframes;
896 interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
897 if (interval < 0.01f)
899 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
904 // get scene name from first frame
905 pinframe = (daliasframe_t *)datapointer;
907 strlcpy(scene->name, pinframe->name, sizeof(scene->name));
908 scene->firstframe = pose;
909 scene->framecount = groupframes;
910 scene->framerate = 1.0f / interval;
915 for (i = 0;i < groupframes;i++)
917 datapointer += sizeof(daliasframe_t);
918 Mod_ConvertAliasVerts(inverts, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphmdlvertex + pose * loadmodel->surfmesh.num_vertices, vertremap);
919 datapointer += sizeof(trivertx_t) * inverts;
925 void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
928 char stripbuf[MAX_QPATH];
929 skinfileitem_t *skinfileitem;
930 if(developer_extra.integer)
931 Con_DPrintf("Looking up texture for %s (default: %s)\n", meshname, shadername);
934 // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
935 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
937 memset(skin, 0, sizeof(*skin));
939 for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
941 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
942 if (!strcmp(skinfileitem->name, meshname))
944 Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf));
945 if(developer_extra.integer)
946 Con_DPrintf("--> got %s from skin file\n", stripbuf);
947 Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
953 // don't render unmentioned meshes
954 Mod_LoadCustomMaterial(loadmodel->mempool, skin, meshname, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing());
955 if(developer_extra.integer)
956 Con_DPrintf("--> skipping\n");
957 skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW;
963 if(developer_extra.integer)
964 Con_DPrintf("--> using default\n");
965 Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf));
966 Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
970 #define BOUNDI(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%d exceeds %d - %d)", loadmodel->name, VALUE, MIN, MAX);
971 #define BOUNDF(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%f exceeds %f - %f)", loadmodel->name, VALUE, MIN, MAX);
972 void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
974 int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
975 float scales, scalet, interval;
979 stvert_t *pinstverts;
980 dtriangle_t *pintriangles;
981 daliasskintype_t *pinskintype;
982 daliasskingroup_t *pinskingroup;
983 daliasskininterval_t *pinskinintervals;
984 daliasframetype_t *pinframetype;
985 daliasgroup_t *pinframegroup;
986 unsigned char *datapointer, *startframes, *startskins;
987 char name[MAX_QPATH];
988 skinframe_t *tempskinframe;
989 animscene_t *tempskinscenes;
990 texture_t *tempaliasskins;
992 int *vertonseam, *vertremap;
993 skinfile_t *skinfiles;
995 datapointer = (unsigned char *)buffer;
996 pinmodel = (mdl_t *)datapointer;
997 datapointer += sizeof(mdl_t);
999 version = LittleLong (pinmodel->version);
1000 if (version != ALIAS_VERSION)
1001 Host_Error ("%s has wrong version number (%i should be %i)",
1002 loadmodel->name, version, ALIAS_VERSION);
1004 loadmodel->modeldatatypestring = "MDL";
1006 loadmodel->type = mod_alias;
1007 loadmodel->DrawSky = NULL;
1008 loadmodel->DrawAddWaterPlanes = NULL;
1009 loadmodel->Draw = R_Q1BSP_Draw;
1010 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1011 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1012 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1013 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1014 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1015 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1016 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1017 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1018 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1019 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1020 // FIXME add TraceBrush!
1021 loadmodel->PointSuperContents = NULL;
1022 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1024 loadmodel->num_surfaces = 1;
1025 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1026 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
1027 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1028 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1029 loadmodel->sortedmodelsurfaces[0] = 0;
1031 loadmodel->numskins = LittleLong(pinmodel->numskins);
1032 BOUNDI(loadmodel->numskins,0,65536);
1033 skinwidth = LittleLong (pinmodel->skinwidth);
1034 BOUNDI(skinwidth,0,65536);
1035 skinheight = LittleLong (pinmodel->skinheight);
1036 BOUNDI(skinheight,0,65536);
1037 numverts = LittleLong(pinmodel->numverts);
1038 BOUNDI(numverts,0,65536);
1039 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
1040 BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
1041 loadmodel->numframes = LittleLong(pinmodel->numframes);
1042 BOUNDI(loadmodel->numframes,0,65536);
1043 loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
1044 BOUNDI((int)loadmodel->synctype,0,2);
1045 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1046 i = LittleLong (pinmodel->flags);
1047 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1049 for (i = 0;i < 3;i++)
1051 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
1052 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
1055 startskins = datapointer;
1057 for (i = 0;i < loadmodel->numskins;i++)
1059 pinskintype = (daliasskintype_t *)datapointer;
1060 datapointer += sizeof(daliasskintype_t);
1061 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
1065 pinskingroup = (daliasskingroup_t *)datapointer;
1066 datapointer += sizeof(daliasskingroup_t);
1067 groupskins = LittleLong(pinskingroup->numskins);
1068 datapointer += sizeof(daliasskininterval_t) * groupskins;
1071 for (j = 0;j < groupskins;j++)
1073 datapointer += skinwidth * skinheight;
1078 pinstverts = (stvert_t *)datapointer;
1079 datapointer += sizeof(stvert_t) * numverts;
1081 pintriangles = (dtriangle_t *)datapointer;
1082 datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
1084 startframes = datapointer;
1085 loadmodel->surfmesh.num_morphframes = 0;
1086 for (i = 0;i < loadmodel->numframes;i++)
1088 pinframetype = (daliasframetype_t *)datapointer;
1089 datapointer += sizeof(daliasframetype_t);
1090 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1094 pinframegroup = (daliasgroup_t *)datapointer;
1095 datapointer += sizeof(daliasgroup_t);
1096 groupframes = LittleLong(pinframegroup->numframes);
1097 datapointer += sizeof(daliasinterval_t) * groupframes;
1100 for (j = 0;j < groupframes;j++)
1102 datapointer += sizeof(daliasframe_t);
1103 datapointer += sizeof(trivertx_t) * numverts;
1104 loadmodel->surfmesh.num_morphframes++;
1107 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1109 // store texture coordinates into temporary array, they will be stored
1110 // after usage is determined (triangle data)
1111 vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1112 vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1113 vertonseam = vertremap + numverts * 2;
1115 scales = 1.0 / skinwidth;
1116 scalet = 1.0 / skinheight;
1117 for (i = 0;i < numverts;i++)
1119 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1120 vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales;
1121 vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet;
1122 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1123 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1126 // load triangle data
1127 loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1129 // read the triangle elements
1130 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1131 for (j = 0;j < 3;j++)
1132 loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1133 // validate (note numverts is used because this is the original data)
1134 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1135 // now butcher the elements according to vertonseam and tri->facesfront
1136 // and then compact the vertex set to remove duplicates
1137 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1138 if (!LittleLong(pintriangles[i].facesfront)) // backface
1139 for (j = 0;j < 3;j++)
1140 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1141 loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1143 // (this uses vertremap to count usage to save some memory)
1144 for (i = 0;i < numverts*2;i++)
1146 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1147 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1148 // build remapping table and compact array
1149 loadmodel->surfmesh.num_vertices = 0;
1150 for (i = 0;i < numverts*2;i++)
1154 vertremap[i] = loadmodel->surfmesh.num_vertices;
1155 vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1156 vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1157 loadmodel->surfmesh.num_vertices++;
1160 vertremap[i] = -1; // not used at all
1162 // remap the elements to the new vertex set
1163 for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1164 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1165 // store the texture coordinates
1166 loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1167 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1169 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1170 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1173 // generate ushort elements array if possible
1174 if (loadmodel->surfmesh.num_vertices <= 65536)
1175 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1176 if (loadmodel->surfmesh.data_element3s)
1177 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1178 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1181 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1182 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1183 if (r_enableshadowvolumes.integer)
1185 loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
1187 Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1188 if (loadmodel->surfmesh.data_neighbor3i)
1189 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1190 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1191 Mod_Alias_MorphMesh_CompileFrames();
1194 Mem_Free(vertremap);
1197 skinfiles = Mod_LoadSkinFiles();
1200 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1201 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1202 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1203 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1204 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1205 Mod_FreeSkinFiles(skinfiles);
1206 for (i = 0;i < loadmodel->numskins;i++)
1208 loadmodel->skinscenes[i].firstframe = i;
1209 loadmodel->skinscenes[i].framecount = 1;
1210 loadmodel->skinscenes[i].loop = true;
1211 loadmodel->skinscenes[i].framerate = 10;
1216 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1217 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1218 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1219 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1221 datapointer = startskins;
1222 for (i = 0;i < loadmodel->numskins;i++)
1224 pinskintype = (daliasskintype_t *)datapointer;
1225 datapointer += sizeof(daliasskintype_t);
1227 if (pinskintype->type == ALIAS_SKIN_SINGLE)
1234 pinskingroup = (daliasskingroup_t *)datapointer;
1235 datapointer += sizeof(daliasskingroup_t);
1237 groupskins = LittleLong (pinskingroup->numskins);
1239 pinskinintervals = (daliasskininterval_t *)datapointer;
1240 datapointer += sizeof(daliasskininterval_t) * groupskins;
1242 interval = LittleFloat(pinskinintervals[0].interval);
1243 if (interval < 0.01f)
1245 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1250 dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1251 loadmodel->skinscenes[i].firstframe = totalskins;
1252 loadmodel->skinscenes[i].framecount = groupskins;
1253 loadmodel->skinscenes[i].framerate = 1.0f / interval;
1254 loadmodel->skinscenes[i].loop = true;
1256 for (j = 0;j < groupskins;j++)
1259 dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1261 dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1262 if (!Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, false, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL))
1263 Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadInternalQuake(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight));
1264 datapointer += skinwidth * skinheight;
1268 // check for skins that don't exist in the model, but do exist as external images
1269 // (this was added because yummyluv kept pestering me about support for it)
1270 // TODO: support shaders here?
1273 dpsnprintf(name, sizeof(name), "%s_%i", loadmodel->name, loadmodel->numskins);
1274 tempskinframe = R_SkinFrame_LoadExternal(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false, false);
1277 // expand the arrays to make room
1278 tempskinscenes = loadmodel->skinscenes;
1279 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1280 memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1281 Mem_Free(tempskinscenes);
1283 tempaliasskins = loadmodel->data_textures;
1284 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1285 memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1286 Mem_Free(tempaliasskins);
1288 // store the info about the new skin
1289 Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, tempskinframe);
1290 strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1291 loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1292 loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1293 loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1294 loadmodel->skinscenes[loadmodel->numskins].loop = true;
1296 //increase skin counts
1297 loadmodel->num_textures++;
1298 loadmodel->numskins++;
1301 // fix up the pointers since they are pointing at the old textures array
1302 // FIXME: this is a hack!
1303 for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1304 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1308 surface = loadmodel->data_surfaces;
1309 surface->texture = loadmodel->data_textures;
1310 surface->num_firsttriangle = 0;
1311 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1312 surface->num_firstvertex = 0;
1313 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1315 if(mod_alias_force_animated.string[0])
1316 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1318 // Always make a BIH for the first frame, we can use it where possible.
1319 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1320 if (!loadmodel->surfmesh.isanimated)
1322 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1323 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1324 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1325 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1326 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1329 // because shaders can do somewhat unexpected things, check for unusual features now
1330 for (i = 0;i < loadmodel->num_textures;i++)
1332 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1333 mod->DrawSky = R_Q1BSP_DrawSky;
1334 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1335 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1339 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
1341 int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1342 float iskinwidth, iskinheight;
1343 unsigned char *data;
1344 msurface_t *surface;
1346 unsigned char *base, *datapointer;
1347 md2frame_t *pinframe;
1349 md2triangle_t *intri;
1350 unsigned short *inst;
1351 struct md2verthash_s
1353 struct md2verthash_s *next;
1357 *hash, **md2verthash, *md2verthashdata;
1358 skinfile_t *skinfiles;
1360 pinmodel = (md2_t *)buffer;
1361 base = (unsigned char *)buffer;
1363 version = LittleLong (pinmodel->version);
1364 if (version != MD2ALIAS_VERSION)
1365 Host_Error ("%s has wrong version number (%i should be %i)",
1366 loadmodel->name, version, MD2ALIAS_VERSION);
1368 loadmodel->modeldatatypestring = "MD2";
1370 loadmodel->type = mod_alias;
1371 loadmodel->DrawSky = NULL;
1372 loadmodel->DrawAddWaterPlanes = NULL;
1373 loadmodel->Draw = R_Q1BSP_Draw;
1374 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1375 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1376 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1377 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1378 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1379 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1380 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1381 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1382 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1383 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1384 loadmodel->PointSuperContents = NULL;
1385 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1387 if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1388 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1389 if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1390 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1391 if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1392 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1393 if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1394 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1396 end = LittleLong(pinmodel->ofs_end);
1397 if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1398 Host_Error ("%s is not a valid model", loadmodel->name);
1399 if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1400 Host_Error ("%s is not a valid model", loadmodel->name);
1401 if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1402 Host_Error ("%s is not a valid model", loadmodel->name);
1403 if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1404 Host_Error ("%s is not a valid model", loadmodel->name);
1405 if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1406 Host_Error ("%s is not a valid model", loadmodel->name);
1408 loadmodel->numskins = LittleLong(pinmodel->num_skins);
1409 numxyz = LittleLong(pinmodel->num_xyz);
1410 numst = LittleLong(pinmodel->num_st);
1411 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1412 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1413 loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1414 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1415 skinwidth = LittleLong(pinmodel->skinwidth);
1416 skinheight = LittleLong(pinmodel->skinheight);
1417 iskinwidth = 1.0f / skinwidth;
1418 iskinheight = 1.0f / skinheight;
1420 loadmodel->num_surfaces = 1;
1421 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1422 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));
1423 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1424 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1425 loadmodel->sortedmodelsurfaces[0] = 0;
1426 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1427 loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1428 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1429 if (r_enableshadowvolumes.integer)
1431 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1434 loadmodel->synctype = ST_RAND;
1437 inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1438 skinfiles = Mod_LoadSkinFiles();
1441 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1442 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1443 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1444 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1445 Mod_FreeSkinFiles(skinfiles);
1447 else if (loadmodel->numskins)
1449 // skins found (most likely not a player model)
1450 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1451 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1452 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1453 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1454 Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
1458 // no skins (most likely a player model)
1459 loadmodel->numskins = 1;
1460 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1461 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1462 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1463 Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures, loadmodel->name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing());
1466 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1467 for (i = 0;i < loadmodel->numskins;i++)
1469 loadmodel->skinscenes[i].firstframe = i;
1470 loadmodel->skinscenes[i].framecount = 1;
1471 loadmodel->skinscenes[i].loop = true;
1472 loadmodel->skinscenes[i].framerate = 10;
1475 // load the triangles and stvert data
1476 inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1477 intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1478 md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1479 md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1480 // swap the triangle list
1481 loadmodel->surfmesh.num_vertices = 0;
1482 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1484 for (j = 0;j < 3;j++)
1486 xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1487 st = (unsigned short) LittleShort (intri[i].index_st[j]);
1490 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1495 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1498 hashindex = (xyz * 256 + st) & 65535;
1499 for (hash = md2verthash[hashindex];hash;hash = hash->next)
1500 if (hash->xyz == xyz && hash->st == st)
1504 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1507 hash->next = md2verthash[hashindex];
1508 md2verthash[hashindex] = hash;
1510 loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1514 vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1515 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));
1516 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1517 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1518 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1521 hash = md2verthashdata + i;
1522 vertremap[i] = hash->xyz;
1523 sts = LittleShort(inst[hash->st*2+0]);
1524 stt = LittleShort(inst[hash->st*2+1]);
1525 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1527 Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1531 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1532 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1535 Mem_Free(md2verthash);
1536 Mem_Free(md2verthashdata);
1538 // generate ushort elements array if possible
1539 if (loadmodel->surfmesh.num_vertices <= 65536)
1540 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1541 if (loadmodel->surfmesh.data_element3s)
1542 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1543 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1546 datapointer = (base + LittleLong(pinmodel->ofs_frames));
1547 for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1552 pinframe = (md2frame_t *)datapointer;
1553 datapointer += sizeof(md2frame_t);
1554 // store the frame scale/translate into the appropriate array
1555 for (j = 0;j < 3;j++)
1557 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1558 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1560 // convert the vertices
1561 v = (trivertx_t *)datapointer;
1562 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1563 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1564 out[k] = v[vertremap[k]];
1565 datapointer += numxyz * sizeof(trivertx_t);
1567 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1568 loadmodel->animscenes[i].firstframe = i;
1569 loadmodel->animscenes[i].framecount = 1;
1570 loadmodel->animscenes[i].framerate = 10;
1571 loadmodel->animscenes[i].loop = true;
1574 Mem_Free(vertremap);
1576 if (loadmodel->surfmesh.data_neighbor3i)
1577 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1578 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1579 Mod_Alias_MorphMesh_CompileFrames();
1580 if(mod_alias_force_animated.string[0])
1581 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1583 surface = loadmodel->data_surfaces;
1584 surface->texture = loadmodel->data_textures;
1585 surface->num_firsttriangle = 0;
1586 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1587 surface->num_firstvertex = 0;
1588 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1590 // Always make a BIH for the first frame, we can use it where possible.
1591 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1592 if (!loadmodel->surfmesh.isanimated)
1594 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1595 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1596 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1597 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1598 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1601 // because shaders can do somewhat unexpected things, check for unusual features now
1602 for (i = 0;i < loadmodel->num_textures;i++)
1604 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1605 mod->DrawSky = R_Q1BSP_DrawSky;
1606 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1607 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1611 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
1613 int i, j, k, version, meshvertices, meshtriangles;
1614 unsigned char *data;
1615 msurface_t *surface;
1616 md3modelheader_t *pinmodel;
1617 md3frameinfo_t *pinframe;
1620 skinfile_t *skinfiles;
1622 pinmodel = (md3modelheader_t *)buffer;
1624 if (memcmp(pinmodel->identifier, "IDP3", 4))
1625 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1626 version = LittleLong (pinmodel->version);
1627 if (version != MD3VERSION)
1628 Host_Error ("%s has wrong version number (%i should be %i)",
1629 loadmodel->name, version, MD3VERSION);
1631 skinfiles = Mod_LoadSkinFiles();
1632 if (loadmodel->numskins < 1)
1633 loadmodel->numskins = 1;
1635 loadmodel->modeldatatypestring = "MD3";
1637 loadmodel->type = mod_alias;
1638 loadmodel->DrawSky = NULL;
1639 loadmodel->DrawAddWaterPlanes = NULL;
1640 loadmodel->Draw = R_Q1BSP_Draw;
1641 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1642 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1643 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1644 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1645 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1646 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1647 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1648 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1649 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1650 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1651 loadmodel->PointSuperContents = NULL;
1652 loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1653 loadmodel->synctype = ST_RAND;
1654 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1655 i = LittleLong (pinmodel->flags);
1656 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1658 // set up some global info about the model
1659 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1660 loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1662 // make skinscenes for the skins (no groups)
1663 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1664 for (i = 0;i < loadmodel->numskins;i++)
1666 loadmodel->skinscenes[i].firstframe = i;
1667 loadmodel->skinscenes[i].framecount = 1;
1668 loadmodel->skinscenes[i].loop = true;
1669 loadmodel->skinscenes[i].framerate = 10;
1673 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1674 for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1676 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1677 loadmodel->animscenes[i].firstframe = i;
1678 loadmodel->animscenes[i].framecount = 1;
1679 loadmodel->animscenes[i].framerate = 10;
1680 loadmodel->animscenes[i].loop = true;
1684 loadmodel->num_tagframes = loadmodel->numframes;
1685 loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1686 loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1687 for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1689 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1690 for (j = 0;j < 9;j++)
1691 loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1692 for (j = 0;j < 3;j++)
1693 loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1694 //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);
1700 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)))
1702 if (memcmp(pinmesh->identifier, "IDP3", 4))
1703 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1704 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1705 Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1706 meshvertices += LittleLong(pinmesh->num_vertices);
1707 meshtriangles += LittleLong(pinmesh->num_triangles);
1710 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1711 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1712 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1713 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));
1714 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1715 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1716 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1717 loadmodel->surfmesh.num_vertices = meshvertices;
1718 loadmodel->surfmesh.num_triangles = meshtriangles;
1719 loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1720 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1721 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1722 if (r_enableshadowvolumes.integer)
1724 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1726 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1727 loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1728 if (meshvertices <= 65536)
1730 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1735 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)))
1737 if (memcmp(pinmesh->identifier, "IDP3", 4))
1738 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1739 loadmodel->sortedmodelsurfaces[i] = i;
1740 surface = loadmodel->data_surfaces + i;
1741 surface->texture = loadmodel->data_textures + i;
1742 surface->num_firsttriangle = meshtriangles;
1743 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1744 surface->num_firstvertex = meshvertices;
1745 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1746 meshvertices += surface->num_vertices;
1747 meshtriangles += surface->num_triangles;
1749 for (j = 0;j < surface->num_triangles * 3;j++)
1750 loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1751 for (j = 0;j < surface->num_vertices;j++)
1753 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1754 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1756 for (j = 0;j < loadmodel->numframes;j++)
1758 const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1759 md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1760 for (k = 0;k < surface->num_vertices;k++, in++, out++)
1762 out->origin[0] = LittleShort(in->origin[0]);
1763 out->origin[1] = LittleShort(in->origin[1]);
1764 out->origin[2] = LittleShort(in->origin[2]);
1765 out->pitch = in->pitch;
1770 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1772 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1774 if (loadmodel->surfmesh.data_element3s)
1775 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1776 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1777 if (loadmodel->surfmesh.data_neighbor3i)
1778 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1779 Mod_Alias_MorphMesh_CompileFrames();
1780 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1781 Mod_FreeSkinFiles(skinfiles);
1782 Mod_MakeSortedSurfaces(loadmodel);
1783 if(mod_alias_force_animated.string[0])
1784 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1786 // Always make a BIH for the first frame, we can use it where possible.
1787 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1788 if (!loadmodel->surfmesh.isanimated)
1790 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1791 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1792 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1793 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1794 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1797 // because shaders can do somewhat unexpected things, check for unusual features now
1798 for (i = 0;i < loadmodel->num_textures;i++)
1800 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1801 mod->DrawSky = R_Q1BSP_DrawSky;
1802 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1803 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1807 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1809 zymtype1header_t *pinmodel, *pheader;
1810 unsigned char *pbase;
1811 int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1812 float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1813 zymvertex_t *verts, *vertdata;
1817 skinfile_t *skinfiles;
1818 unsigned char *data;
1819 msurface_t *surface;
1821 pinmodel = (zymtype1header_t *)buffer;
1822 pbase = (unsigned char *)buffer;
1823 if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1824 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1825 if (BigLong(pinmodel->type) != 1)
1826 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1828 loadmodel->modeldatatypestring = "ZYM";
1830 loadmodel->type = mod_alias;
1831 loadmodel->synctype = ST_RAND;
1835 pheader->type = BigLong(pinmodel->type);
1836 pheader->filesize = BigLong(pinmodel->filesize);
1837 pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1838 pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1839 pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1840 pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1841 pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1842 pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1843 pheader->radius = BigFloat(pinmodel->radius);
1844 pheader->numverts = BigLong(pinmodel->numverts);
1845 pheader->numtris = BigLong(pinmodel->numtris);
1846 pheader->numshaders = BigLong(pinmodel->numshaders);
1847 pheader->numbones = BigLong(pinmodel->numbones);
1848 pheader->numscenes = BigLong(pinmodel->numscenes);
1849 pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1850 pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1851 pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1852 pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1853 pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1854 pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1855 pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1856 pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1857 pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1858 pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1859 pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1860 pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1861 pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1862 pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1863 pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1864 pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1865 pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1866 pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1868 if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1870 Con_Printf("%s has no geometry\n", loadmodel->name);
1873 if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1875 Con_Printf("%s has no animations\n", loadmodel->name);
1879 loadmodel->DrawSky = NULL;
1880 loadmodel->DrawAddWaterPlanes = NULL;
1881 loadmodel->Draw = R_Q1BSP_Draw;
1882 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1883 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1884 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1885 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1886 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1887 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1888 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1889 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1890 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1891 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1892 loadmodel->PointSuperContents = NULL;
1893 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1895 loadmodel->numframes = pheader->numscenes;
1896 loadmodel->num_surfaces = pheader->numshaders;
1898 skinfiles = Mod_LoadSkinFiles();
1899 if (loadmodel->numskins < 1)
1900 loadmodel->numskins = 1;
1902 // make skinscenes for the skins (no groups)
1903 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1904 for (i = 0;i < loadmodel->numskins;i++)
1906 loadmodel->skinscenes[i].firstframe = i;
1907 loadmodel->skinscenes[i].framecount = 1;
1908 loadmodel->skinscenes[i].loop = true;
1909 loadmodel->skinscenes[i].framerate = 10;
1913 // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
1914 modelradius = pheader->radius;
1915 for (i = 0;i < 3;i++)
1917 loadmodel->normalmins[i] = pheader->mins[i];
1918 loadmodel->normalmaxs[i] = pheader->maxs[i];
1919 loadmodel->rotatedmins[i] = -modelradius;
1920 loadmodel->rotatedmaxs[i] = modelradius;
1922 corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1923 corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1924 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1925 if (loadmodel->yawmaxs[0] > modelradius)
1926 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1927 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1928 loadmodel->yawmins[2] = loadmodel->normalmins[2];
1929 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1930 loadmodel->radius = modelradius;
1931 loadmodel->radius2 = modelradius * modelradius;
1933 // go through the lumps, swapping things
1935 //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1936 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1937 scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1938 numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1939 for (i = 0;i < pheader->numscenes;i++)
1941 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1942 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1943 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1944 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1945 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1946 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1947 Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1948 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1949 Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1950 if (loadmodel->animscenes[i].framerate < 0)
1951 Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1955 //zymlump_t lump_bones; // zymbone_t bone[numbones];
1956 loadmodel->num_bones = pheader->numbones;
1957 loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1958 bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1959 for (i = 0;i < pheader->numbones;i++)
1961 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1962 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1963 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1964 if (loadmodel->data_bones[i].parent >= i)
1965 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1968 //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1969 vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1970 bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1971 for (i = 0;i < pheader->numverts;i++)
1973 vertbonecounts[i] = BigLong(bonecount[i]);
1974 if (vertbonecounts[i] != 1)
1975 Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1978 loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1980 meshvertices = pheader->numverts;
1981 meshtriangles = pheader->numtris;
1983 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1984 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1985 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1986 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]));
1987 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1988 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1989 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1990 loadmodel->surfmesh.num_vertices = meshvertices;
1991 loadmodel->surfmesh.num_triangles = meshtriangles;
1992 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1993 if (r_enableshadowvolumes.integer)
1995 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1997 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1998 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1999 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2000 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2001 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2002 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2003 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2004 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2005 loadmodel->surfmesh.num_blends = 0;
2006 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2007 if (loadmodel->surfmesh.num_vertices <= 65536)
2009 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2011 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2012 loadmodel->surfmesh.data_blendweights = NULL;
2014 //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
2015 poses = (float *) (pheader->lump_poses.start + pbase);
2016 // figure out scale of model from root bone, for compatibility with old zmodel versions
2017 tempvec[0] = BigFloat(poses[0]);
2018 tempvec[1] = BigFloat(poses[1]);
2019 tempvec[2] = BigFloat(poses[2]);
2020 modelscale = VectorLength(tempvec);
2022 for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
2024 f = fabs(BigFloat(poses[i]));
2025 biggestorigin = max(biggestorigin, f);
2027 loadmodel->num_posescale = biggestorigin / 32767.0f;
2028 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2029 for (i = 0;i < numposes;i++)
2031 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
2032 for (j = 0;j < loadmodel->num_bones;j++)
2035 matrix4x4_t posematrix;
2036 for (k = 0;k < 12;k++)
2037 pose[k] = BigFloat(frameposes[j*12+k]);
2038 //if (j < loadmodel->num_bones)
2039 // 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));
2040 // scale child bones to match the root scale
2041 if (loadmodel->data_bones[j].parent >= 0)
2043 pose[3] *= modelscale;
2044 pose[7] *= modelscale;
2045 pose[11] *= modelscale;
2047 // normalize rotation matrix
2048 VectorNormalize(pose + 0);
2049 VectorNormalize(pose + 4);
2050 VectorNormalize(pose + 8);
2051 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2052 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2056 //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2057 verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2058 vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2059 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2060 // (converting from weight-blending skeletal animation to
2061 // deformation-based skeletal animation)
2062 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2063 for (i = 0;i < loadmodel->num_bones;i++)
2066 for (k = 0;k < 12;k++)
2067 m[k] = BigFloat(poses[i*12+k]);
2068 if (loadmodel->data_bones[i].parent >= 0)
2069 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2071 for (k = 0;k < 12;k++)
2072 bonepose[12*i+k] = m[k];
2074 for (j = 0;j < pheader->numverts;j++)
2076 // this format really should have had a per vertexweight weight value...
2077 // but since it does not, the weighting is completely ignored and
2078 // only one weight is allowed per vertex
2079 int boneindex = BigLong(vertdata[j].bonenum);
2080 const float *m = bonepose + 12 * boneindex;
2081 float relativeorigin[3];
2082 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2083 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2084 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2085 // transform the vertex bone weight into the base mesh
2086 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2087 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2088 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2089 // store the weight as the primary weight on this vertex
2090 loadmodel->surfmesh.blends[j] = boneindex;
2091 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = boneindex;
2092 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2093 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2094 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2095 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = 255;
2096 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2097 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2098 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2101 // normals and tangents are calculated after elements are loaded
2103 //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2104 outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2105 intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2106 for (i = 0;i < pheader->numverts;i++)
2108 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2109 // flip T coordinate for OpenGL
2110 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2113 //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2114 //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2115 //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2117 //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2118 //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)
2119 // byteswap, validate, and swap winding order of tris
2120 count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2121 if (pheader->lump_render.length != count)
2122 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2123 renderlist = (int *) (pheader->lump_render.start + pbase);
2124 renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2126 for (i = 0;i < loadmodel->num_surfaces;i++)
2128 int firstvertex, lastvertex;
2129 if (renderlist >= renderlistend)
2130 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2131 count = BigLong(*renderlist);renderlist++;
2132 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2133 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2135 loadmodel->sortedmodelsurfaces[i] = i;
2136 surface = loadmodel->data_surfaces + i;
2137 surface->texture = loadmodel->data_textures + i;
2138 surface->num_firsttriangle = meshtriangles;
2139 surface->num_triangles = count;
2140 meshtriangles += surface->num_triangles;
2142 // load the elements
2143 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2144 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2146 outelements[j*3+2] = BigLong(renderlist[0]);
2147 outelements[j*3+1] = BigLong(renderlist[1]);
2148 outelements[j*3+0] = BigLong(renderlist[2]);
2150 // validate the elements and find the used vertex range
2151 firstvertex = meshvertices;
2153 for (j = 0;j < surface->num_triangles * 3;j++)
2155 if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2156 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2157 firstvertex = min(firstvertex, outelements[j]);
2158 lastvertex = max(lastvertex, outelements[j]);
2160 surface->num_firstvertex = firstvertex;
2161 surface->num_vertices = lastvertex + 1 - firstvertex;
2163 // since zym models do not have named sections, reuse their shader
2164 // name as the section name
2165 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2166 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2168 Mod_FreeSkinFiles(skinfiles);
2169 Mem_Free(vertbonecounts);
2171 Mod_MakeSortedSurfaces(loadmodel);
2173 // compute all the mesh information that was not loaded from the file
2174 if (loadmodel->surfmesh.data_element3s)
2175 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2176 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2177 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2178 Mod_BuildBaseBonePoses();
2179 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);
2180 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);
2181 if (loadmodel->surfmesh.data_neighbor3i)
2182 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2183 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2184 if(mod_alias_force_animated.string[0])
2185 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2187 // Always make a BIH for the first frame, we can use it where possible.
2188 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2189 if (!loadmodel->surfmesh.isanimated)
2191 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2192 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2193 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2194 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2195 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2198 // because shaders can do somewhat unexpected things, check for unusual features now
2199 for (i = 0;i < loadmodel->num_textures;i++)
2201 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2202 mod->DrawSky = R_Q1BSP_DrawSky;
2203 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2204 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2208 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2210 dpmheader_t *pheader;
2214 unsigned char *pbase;
2215 int i, j, k, meshvertices, meshtriangles;
2216 skinfile_t *skinfiles;
2217 unsigned char *data;
2219 float biggestorigin, tempvec[3], modelscale;
2223 pheader = (dpmheader_t *)buffer;
2224 pbase = (unsigned char *)buffer;
2225 if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2226 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2227 if (BigLong(pheader->type) != 2)
2228 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2230 loadmodel->modeldatatypestring = "DPM";
2232 loadmodel->type = mod_alias;
2233 loadmodel->synctype = ST_RAND;
2236 pheader->type = BigLong(pheader->type);
2237 pheader->filesize = BigLong(pheader->filesize);
2238 pheader->mins[0] = BigFloat(pheader->mins[0]);
2239 pheader->mins[1] = BigFloat(pheader->mins[1]);
2240 pheader->mins[2] = BigFloat(pheader->mins[2]);
2241 pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2242 pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2243 pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2244 pheader->yawradius = BigFloat(pheader->yawradius);
2245 pheader->allradius = BigFloat(pheader->allradius);
2246 pheader->num_bones = BigLong(pheader->num_bones);
2247 pheader->num_meshs = BigLong(pheader->num_meshs);
2248 pheader->num_frames = BigLong(pheader->num_frames);
2249 pheader->ofs_bones = BigLong(pheader->ofs_bones);
2250 pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2251 pheader->ofs_frames = BigLong(pheader->ofs_frames);
2253 if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2255 Con_Printf("%s has no geometry\n", loadmodel->name);
2258 if (pheader->num_frames < 1)
2260 Con_Printf("%s has no frames\n", loadmodel->name);
2264 loadmodel->DrawSky = NULL;
2265 loadmodel->DrawAddWaterPlanes = NULL;
2266 loadmodel->Draw = R_Q1BSP_Draw;
2267 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2268 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2269 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2270 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2271 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2272 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2273 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2274 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2275 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2276 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2277 loadmodel->PointSuperContents = NULL;
2278 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2281 // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2282 for (i = 0;i < 3;i++)
2284 loadmodel->normalmins[i] = pheader->mins[i];
2285 loadmodel->normalmaxs[i] = pheader->maxs[i];
2286 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2287 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2288 loadmodel->rotatedmins[i] = -pheader->allradius;
2289 loadmodel->rotatedmaxs[i] = pheader->allradius;
2291 loadmodel->radius = pheader->allradius;
2292 loadmodel->radius2 = pheader->allradius * pheader->allradius;
2294 // load external .skin files if present
2295 skinfiles = Mod_LoadSkinFiles();
2296 if (loadmodel->numskins < 1)
2297 loadmodel->numskins = 1;
2302 // gather combined statistics from the meshes
2303 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2304 for (i = 0;i < (int)pheader->num_meshs;i++)
2306 int numverts = BigLong(dpmmesh->num_verts);
2307 meshvertices += numverts;
2308 meshtriangles += BigLong(dpmmesh->num_tris);
2312 loadmodel->numframes = pheader->num_frames;
2313 loadmodel->num_bones = pheader->num_bones;
2314 loadmodel->num_poses = loadmodel->numframes;
2315 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
2316 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2317 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2318 // do most allocations as one merged chunk
2319 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));
2320 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2321 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2322 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2323 loadmodel->surfmesh.num_vertices = meshvertices;
2324 loadmodel->surfmesh.num_triangles = meshtriangles;
2325 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2326 if (r_enableshadowvolumes.integer)
2328 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2330 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2331 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2332 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2333 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2334 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2335 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2336 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2337 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2338 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2339 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2340 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2341 loadmodel->surfmesh.num_blends = 0;
2342 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2343 if (meshvertices <= 65536)
2345 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2347 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2348 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2350 for (i = 0;i < loadmodel->numskins;i++)
2352 loadmodel->skinscenes[i].firstframe = i;
2353 loadmodel->skinscenes[i].framecount = 1;
2354 loadmodel->skinscenes[i].loop = true;
2355 loadmodel->skinscenes[i].framerate = 10;
2358 // load the bone info
2359 bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2360 for (i = 0;i < loadmodel->num_bones;i++)
2362 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2363 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2364 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2365 if (loadmodel->data_bones[i].parent >= i)
2366 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2370 frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2371 // figure out scale of model from root bone, for compatibility with old dpmodel versions
2372 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2373 tempvec[0] = BigFloat(poses[0]);
2374 tempvec[1] = BigFloat(poses[1]);
2375 tempvec[2] = BigFloat(poses[2]);
2376 modelscale = VectorLength(tempvec);
2378 for (i = 0;i < loadmodel->numframes;i++)
2380 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2381 loadmodel->animscenes[i].firstframe = i;
2382 loadmodel->animscenes[i].framecount = 1;
2383 loadmodel->animscenes[i].loop = true;
2384 loadmodel->animscenes[i].framerate = 10;
2385 // load the bone poses for this frame
2386 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2387 for (j = 0;j < loadmodel->num_bones*12;j++)
2389 f = fabs(BigFloat(poses[j]));
2390 biggestorigin = max(biggestorigin, f);
2392 // stuff not processed here: mins, maxs, yawradius, allradius
2394 loadmodel->num_posescale = biggestorigin / 32767.0f;
2395 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2396 for (i = 0;i < loadmodel->numframes;i++)
2398 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2399 for (j = 0;j < loadmodel->num_bones;j++)
2402 matrix4x4_t posematrix;
2403 for (k = 0;k < 12;k++)
2404 pose[k] = BigFloat(frameposes[j*12+k]);
2405 // scale child bones to match the root scale
2406 if (loadmodel->data_bones[j].parent >= 0)
2408 pose[3] *= modelscale;
2409 pose[7] *= modelscale;
2410 pose[11] *= modelscale;
2412 // normalize rotation matrix
2413 VectorNormalize(pose + 0);
2414 VectorNormalize(pose + 4);
2415 VectorNormalize(pose + 8);
2416 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2417 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2421 // load the meshes now
2422 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2425 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2426 // (converting from weight-blending skeletal animation to
2427 // deformation-based skeletal animation)
2428 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2429 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2430 for (i = 0;i < loadmodel->num_bones;i++)
2433 for (k = 0;k < 12;k++)
2434 m[k] = BigFloat(poses[i*12+k]);
2435 if (loadmodel->data_bones[i].parent >= 0)
2436 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2438 for (k = 0;k < 12;k++)
2439 bonepose[12*i+k] = m[k];
2441 for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2443 const int *inelements;
2445 const float *intexcoord;
2446 msurface_t *surface;
2448 loadmodel->sortedmodelsurfaces[i] = i;
2449 surface = loadmodel->data_surfaces + i;
2450 surface->texture = loadmodel->data_textures + i;
2451 surface->num_firsttriangle = meshtriangles;
2452 surface->num_triangles = BigLong(dpmmesh->num_tris);
2453 surface->num_firstvertex = meshvertices;
2454 surface->num_vertices = BigLong(dpmmesh->num_verts);
2455 meshvertices += surface->num_vertices;
2456 meshtriangles += surface->num_triangles;
2458 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2459 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2460 for (j = 0;j < surface->num_triangles;j++)
2462 // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2463 outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
2464 outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
2465 outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
2470 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2471 for (j = 0;j < surface->num_vertices*2;j++)
2472 loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2474 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2475 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2477 int weightindex[4] = { 0, 0, 0, 0 };
2478 float weightinfluence[4] = { 0, 0, 0, 0 };
2480 int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2481 data += sizeof(dpmvertex_t);
2482 for (k = 0;k < numweights;k++)
2484 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2485 int boneindex = BigLong(vert->bonenum);
2486 const float *m = bonepose + 12 * boneindex;
2487 float influence = BigFloat(vert->influence);
2488 float relativeorigin[3], relativenormal[3];
2489 relativeorigin[0] = BigFloat(vert->origin[0]);
2490 relativeorigin[1] = BigFloat(vert->origin[1]);
2491 relativeorigin[2] = BigFloat(vert->origin[2]);
2492 relativenormal[0] = BigFloat(vert->normal[0]);
2493 relativenormal[1] = BigFloat(vert->normal[1]);
2494 relativenormal[2] = BigFloat(vert->normal[2]);
2495 // blend the vertex bone weights into the base mesh
2496 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2497 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2498 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2499 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2500 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2501 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2504 // store the first (and often only) weight
2505 weightinfluence[0] = influence;
2506 weightindex[0] = boneindex;
2510 // sort the new weight into this vertex's weight table
2511 // (which only accepts up to 4 bones per vertex)
2512 for (l = 0;l < 4;l++)
2514 if (weightinfluence[l] < influence)
2516 // move weaker influence weights out of the way first
2518 for (l2 = 3;l2 > l;l2--)
2520 weightinfluence[l2] = weightinfluence[l2-1];
2521 weightindex[l2] = weightindex[l2-1];
2523 // store the new weight
2524 weightinfluence[l] = influence;
2525 weightindex[l] = boneindex;
2530 data += sizeof(dpmbonevert_t);
2532 loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2533 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = weightindex[0];
2534 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2535 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2536 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2537 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
2538 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2539 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2540 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2543 // since dpm models do not have named sections, reuse their shader name as the section name
2544 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2546 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2548 if (loadmodel->surfmesh.num_blends < meshvertices)
2549 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2551 Mod_FreeSkinFiles(skinfiles);
2552 Mod_MakeSortedSurfaces(loadmodel);
2554 // compute all the mesh information that was not loaded from the file
2555 if (loadmodel->surfmesh.data_element3s)
2556 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2557 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2558 Mod_BuildBaseBonePoses();
2559 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);
2560 if (loadmodel->surfmesh.data_neighbor3i)
2561 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2562 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2563 if(mod_alias_force_animated.string[0])
2564 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2566 // Always make a BIH for the first frame, we can use it where possible.
2567 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2568 if (!loadmodel->surfmesh.isanimated)
2570 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2571 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2572 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2573 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2574 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2577 // because shaders can do somewhat unexpected things, check for unusual features now
2578 for (i = 0;i < loadmodel->num_textures;i++)
2580 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2581 mod->DrawSky = R_Q1BSP_DrawSky;
2582 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2583 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2587 // no idea why PSK/PSA files contain weird quaternions but they do...
2588 #define PSKQUATNEGATIONS
2589 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2591 int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2592 int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2593 fs_offset_t filesize;
2598 pskboneinfo_t *bones;
2599 pskrawweights_t *rawweights;
2600 //pskboneinfo_t *animbones;
2601 pskaniminfo_t *anims;
2602 pskanimkeys_t *animkeys;
2603 void *animfilebuffer, *animbuffer, *animbufferend;
2604 unsigned char *data;
2606 skinfile_t *skinfiles;
2607 char animname[MAX_QPATH];
2609 float biggestorigin;
2611 pchunk = (pskchunk_t *)buffer;
2612 if (strcmp(pchunk->id, "ACTRHEAD"))
2613 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2615 loadmodel->modeldatatypestring = "PSK";
2617 loadmodel->type = mod_alias;
2618 loadmodel->DrawSky = NULL;
2619 loadmodel->DrawAddWaterPlanes = NULL;
2620 loadmodel->Draw = R_Q1BSP_Draw;
2621 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2622 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2623 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2624 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2625 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2626 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2627 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2628 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2629 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2630 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2631 loadmodel->PointSuperContents = NULL;
2632 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2633 loadmodel->synctype = ST_RAND;
2635 FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2636 strlcat(animname, ".psa", sizeof(animname));
2637 animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2638 animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2640 animbufferend = animbuffer;
2659 while (buffer < bufferend)
2661 pchunk = (pskchunk_t *)buffer;
2662 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2663 version = LittleLong(pchunk->version);
2664 recordsize = LittleLong(pchunk->recordsize);
2665 numrecords = LittleLong(pchunk->numrecords);
2666 if (developer_extra.integer)
2667 Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2668 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2669 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);
2670 if (!strcmp(pchunk->id, "ACTRHEAD"))
2674 else if (!strcmp(pchunk->id, "PNTS0000"))
2677 if (recordsize != sizeof(*p))
2678 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2679 // byteswap in place and keep the pointer
2680 numpnts = numrecords;
2681 pnts = (pskpnts_t *)buffer;
2682 for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2684 p->origin[0] = LittleFloat(p->origin[0]);
2685 p->origin[1] = LittleFloat(p->origin[1]);
2686 p->origin[2] = LittleFloat(p->origin[2]);
2690 else if (!strcmp(pchunk->id, "VTXW0000"))
2693 if (recordsize != sizeof(*p))
2694 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2695 // byteswap in place and keep the pointer
2696 numvtxw = numrecords;
2697 vtxw = (pskvtxw_t *)buffer;
2698 for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2700 p->pntsindex = LittleShort(p->pntsindex);
2701 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2702 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2703 if (p->pntsindex >= numpnts)
2705 Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2711 else if (!strcmp(pchunk->id, "FACE0000"))
2714 if (recordsize != sizeof(*p))
2715 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2716 // byteswap in place and keep the pointer
2717 numfaces = numrecords;
2718 faces = (pskface_t *)buffer;
2719 for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2721 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2722 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2723 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2724 p->group = LittleLong(p->group);
2725 if (p->vtxwindex[0] >= numvtxw)
2727 Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2728 p->vtxwindex[0] = 0;
2730 if (p->vtxwindex[1] >= numvtxw)
2732 Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2733 p->vtxwindex[1] = 0;
2735 if (p->vtxwindex[2] >= numvtxw)
2737 Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2738 p->vtxwindex[2] = 0;
2743 else if (!strcmp(pchunk->id, "MATT0000"))
2746 if (recordsize != sizeof(*p))
2747 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2748 // byteswap in place and keep the pointer
2749 nummatts = numrecords;
2750 matts = (pskmatt_t *)buffer;
2751 for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2757 else if (!strcmp(pchunk->id, "REFSKELT"))
2760 if (recordsize != sizeof(*p))
2761 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2762 // byteswap in place and keep the pointer
2763 numbones = numrecords;
2764 bones = (pskboneinfo_t *)buffer;
2765 for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2767 p->numchildren = LittleLong(p->numchildren);
2768 p->parent = LittleLong(p->parent);
2769 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2770 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2771 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2772 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2773 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2774 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2775 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2776 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2777 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2778 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2779 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2780 #ifdef PSKQUATNEGATIONS
2783 p->basepose.quat[0] *= -1;
2784 p->basepose.quat[1] *= -1;
2785 p->basepose.quat[2] *= -1;
2789 p->basepose.quat[0] *= 1;
2790 p->basepose.quat[1] *= -1;
2791 p->basepose.quat[2] *= 1;
2794 if (p->parent < 0 || p->parent >= numbones)
2796 Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2802 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2805 if (recordsize != sizeof(*p))
2806 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2807 // byteswap in place and keep the pointer
2808 numrawweights = numrecords;
2809 rawweights = (pskrawweights_t *)buffer;
2810 for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2812 p->weight = LittleFloat(p->weight);
2813 p->pntsindex = LittleLong(p->pntsindex);
2814 p->boneindex = LittleLong(p->boneindex);
2815 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2817 Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2820 if (p->boneindex < 0 || p->boneindex >= numbones)
2822 Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2830 while (animbuffer < animbufferend)
2832 pchunk = (pskchunk_t *)animbuffer;
2833 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2834 version = LittleLong(pchunk->version);
2835 recordsize = LittleLong(pchunk->recordsize);
2836 numrecords = LittleLong(pchunk->numrecords);
2837 if (developer_extra.integer)
2838 Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2839 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2840 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);
2841 if (!strcmp(pchunk->id, "ANIMHEAD"))
2845 else if (!strcmp(pchunk->id, "BONENAMES"))
2848 if (recordsize != sizeof(*p))
2849 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2850 // byteswap in place and keep the pointer
2851 numanimbones = numrecords;
2852 //animbones = (pskboneinfo_t *)animbuffer;
2853 // NOTE: supposedly psa does not need to match the psk model, the
2854 // bones missing from the psa would simply use their base
2855 // positions from the psk, but this is hard for me to implement
2856 // and people can easily make animations that match.
2857 if (numanimbones != numbones)
2858 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2859 for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2861 p->numchildren = LittleLong(p->numchildren);
2862 p->parent = LittleLong(p->parent);
2863 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2864 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2865 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2866 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2867 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2868 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2869 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2870 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2871 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2872 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2873 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2874 #ifdef PSKQUATNEGATIONS
2877 p->basepose.quat[0] *= -1;
2878 p->basepose.quat[1] *= -1;
2879 p->basepose.quat[2] *= -1;
2883 p->basepose.quat[0] *= 1;
2884 p->basepose.quat[1] *= -1;
2885 p->basepose.quat[2] *= 1;
2888 if (p->parent < 0 || p->parent >= numanimbones)
2890 Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2893 // check that bones are the same as in the base
2894 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2895 Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2899 else if (!strcmp(pchunk->id, "ANIMINFO"))
2902 if (recordsize != sizeof(*p))
2903 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2904 // byteswap in place and keep the pointer
2905 numanims = numrecords;
2906 anims = (pskaniminfo_t *)animbuffer;
2907 for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2909 p->numbones = LittleLong(p->numbones);
2910 p->playtime = LittleFloat(p->playtime);
2911 p->fps = LittleFloat(p->fps);
2912 p->firstframe = LittleLong(p->firstframe);
2913 p->numframes = LittleLong(p->numframes);
2914 if (p->numbones != numbones)
2915 Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2919 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2922 if (recordsize != sizeof(*p))
2923 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2924 numanimkeys = numrecords;
2925 animkeys = (pskanimkeys_t *)animbuffer;
2926 for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2928 p->origin[0] = LittleFloat(p->origin[0]);
2929 p->origin[1] = LittleFloat(p->origin[1]);
2930 p->origin[2] = LittleFloat(p->origin[2]);
2931 p->quat[0] = LittleFloat(p->quat[0]);
2932 p->quat[1] = LittleFloat(p->quat[1]);
2933 p->quat[2] = LittleFloat(p->quat[2]);
2934 p->quat[3] = LittleFloat(p->quat[3]);
2935 p->frametime = LittleFloat(p->frametime);
2936 #ifdef PSKQUATNEGATIONS
2937 if (index % numbones)
2952 // TODO: allocate bonepose stuff
2955 Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2958 if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2959 Host_Error("%s: missing required chunks", loadmodel->name);
2963 loadmodel->numframes = 0;
2964 for (index = 0;index < numanims;index++)
2965 loadmodel->numframes += anims[index].numframes;
2966 if (numanimkeys != numbones * loadmodel->numframes)
2967 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2970 loadmodel->numframes = loadmodel->num_poses = 1;
2972 meshvertices = numvtxw;
2973 meshtriangles = numfaces;
2975 // load external .skin files if present
2976 skinfiles = Mod_LoadSkinFiles();
2977 if (loadmodel->numskins < 1)
2978 loadmodel->numskins = 1;
2979 loadmodel->num_bones = numbones;
2980 loadmodel->num_poses = loadmodel->numframes;
2981 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2982 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2983 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2984 loadmodel->surfmesh.num_vertices = meshvertices;
2985 loadmodel->surfmesh.num_triangles = meshtriangles;
2986 // do most allocations as one merged chunk
2987 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);
2988 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2989 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2990 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2991 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2992 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2993 if (r_enableshadowvolumes.integer)
2995 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2997 loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2998 loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2999 loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3000 loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3001 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3002 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3003 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3004 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3005 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3006 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3007 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3008 loadmodel->surfmesh.num_blends = 0;
3009 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3010 if (loadmodel->surfmesh.num_vertices <= 65536)
3012 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
3014 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3015 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
3017 for (i = 0;i < loadmodel->numskins;i++)
3019 loadmodel->skinscenes[i].firstframe = i;
3020 loadmodel->skinscenes[i].framecount = 1;
3021 loadmodel->skinscenes[i].loop = true;
3022 loadmodel->skinscenes[i].framerate = 10;
3026 for (index = 0, i = 0;index < nummatts;index++)
3028 // since psk models do not have named sections, reuse their shader name as the section name
3029 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
3030 loadmodel->sortedmodelsurfaces[index] = index;
3031 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
3032 loadmodel->data_surfaces[index].num_firstvertex = 0;
3033 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
3036 // copy over the vertex locations and texcoords
3037 for (index = 0;index < numvtxw;index++)
3039 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
3040 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
3041 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
3042 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
3043 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
3046 // loading the faces is complicated because we need to sort them into surfaces by mattindex
3047 for (index = 0;index < numfaces;index++)
3048 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
3049 for (index = 0, i = 0;index < nummatts;index++)
3051 loadmodel->data_surfaces[index].num_firsttriangle = i;
3052 i += loadmodel->data_surfaces[index].num_triangles;
3053 loadmodel->data_surfaces[index].num_triangles = 0;
3055 for (index = 0;index < numfaces;index++)
3057 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
3058 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
3059 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
3060 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
3063 // copy over the bones
3064 for (index = 0;index < numbones;index++)
3066 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
3067 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
3068 if (loadmodel->data_bones[index].parent >= index)
3069 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
3072 // convert the basepose data
3073 if (loadmodel->num_bones)
3076 matrix4x4_t *basebonepose;
3077 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
3078 matrix4x4_t bonematrix;
3079 matrix4x4_t tempbonematrix;
3080 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
3081 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
3083 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]);
3084 if (loadmodel->data_bones[boneindex].parent >= 0)
3086 tempbonematrix = bonematrix;
3087 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3089 basebonepose[boneindex] = bonematrix;
3090 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3091 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3093 Mem_Free(basebonepose);
3096 // sort the psk point weights into the vertex weight tables
3097 // (which only accept up to 4 bones per vertex)
3098 for (index = 0;index < numvtxw;index++)
3100 int weightindex[4] = { 0, 0, 0, 0 };
3101 float weightinfluence[4] = { 0, 0, 0, 0 };
3103 for (j = 0;j < numrawweights;j++)
3105 if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3107 int boneindex = rawweights[j].boneindex;
3108 float influence = rawweights[j].weight;
3109 for (l = 0;l < 4;l++)
3111 if (weightinfluence[l] < influence)
3113 // move lower influence weights out of the way first
3115 for (l2 = 3;l2 > l;l2--)
3117 weightinfluence[l2] = weightinfluence[l2-1];
3118 weightindex[l2] = weightindex[l2-1];
3120 // store the new weight
3121 weightinfluence[l] = influence;
3122 weightindex[l] = boneindex;
3128 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3129 loadmodel->surfmesh.data_skeletalindex4ub[index*4 ] = weightindex[0];
3130 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3131 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3132 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3133 loadmodel->surfmesh.data_skeletalweight4ub[index*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
3134 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3135 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3136 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3138 if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3139 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3141 // set up the animscenes based on the anims
3144 for (index = 0, i = 0;index < numanims;index++)
3146 for (j = 0;j < anims[index].numframes;j++, i++)
3148 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3149 loadmodel->animscenes[i].firstframe = i;
3150 loadmodel->animscenes[i].framecount = 1;
3151 loadmodel->animscenes[i].loop = true;
3152 loadmodel->animscenes[i].framerate = anims[index].fps;
3155 // calculate the scaling value for bone origins so they can be compressed to short
3157 for (index = 0;index < numanimkeys;index++)
3159 pskanimkeys_t *k = animkeys + index;
3160 biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3161 biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3162 biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3164 loadmodel->num_posescale = biggestorigin / 32767.0f;
3165 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3167 // load the poses from the animkeys
3168 for (index = 0;index < numanimkeys;index++)
3170 pskanimkeys_t *k = animkeys + index;
3172 Vector4Copy(k->quat, quat);
3174 Vector4Negate(quat, quat);
3175 Vector4Normalize2(quat, quat);
3176 // compress poses to the short[7] format for longterm storage
3177 loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3178 loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3179 loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3180 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3181 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3182 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3183 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3188 strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3189 loadmodel->animscenes[0].firstframe = 0;
3190 loadmodel->animscenes[0].framecount = 1;
3191 loadmodel->animscenes[0].loop = true;
3192 loadmodel->animscenes[0].framerate = 10;
3194 // calculate the scaling value for bone origins so they can be compressed to short
3196 for (index = 0;index < numbones;index++)
3198 pskboneinfo_t *p = bones + index;
3199 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3200 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3201 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3203 loadmodel->num_posescale = biggestorigin / 32767.0f;
3204 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3206 // load the basepose as a frame
3207 for (index = 0;index < numbones;index++)
3209 pskboneinfo_t *p = bones + index;
3211 Vector4Copy(p->basepose.quat, quat);
3213 Vector4Negate(quat, quat);
3214 Vector4Normalize2(quat, quat);
3215 // compress poses to the short[7] format for longterm storage
3216 loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3217 loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3218 loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3219 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3220 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3221 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3222 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3226 Mod_FreeSkinFiles(skinfiles);
3228 Mem_Free(animfilebuffer);
3229 Mod_MakeSortedSurfaces(loadmodel);
3231 // compute all the mesh information that was not loaded from the file
3232 // TODO: honor smoothing groups somehow?
3233 if (loadmodel->surfmesh.data_element3s)
3234 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3235 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3236 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3237 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);
3238 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);
3239 if (loadmodel->surfmesh.data_neighbor3i)
3240 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
3241 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3242 if(mod_alias_force_animated.string[0])
3243 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3245 // Always make a BIH for the first frame, we can use it where possible.
3246 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3247 if (!loadmodel->surfmesh.isanimated)
3249 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3250 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3251 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3252 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3253 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3256 // because shaders can do somewhat unexpected things, check for unusual features now
3257 for (i = 0;i < loadmodel->num_textures;i++)
3259 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3260 mod->DrawSky = R_Q1BSP_DrawSky;
3261 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3262 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
3266 void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
3268 unsigned char *data;
3270 const unsigned char *pbase, *pend;
3272 skinfile_t *skinfiles;
3273 int i, j, k, meshvertices, meshtriangles;
3274 float biggestorigin;
3275 const unsigned int *inelements;
3277 const int *inneighbors;
3279 float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3280 // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3281 const float *vnormal = NULL;
3282 const float *vposition = NULL;
3283 const float *vtangent = NULL;
3284 const float *vtexcoord = NULL;
3285 const float *vcolor4f = NULL;
3286 const unsigned char *vblendindexes = NULL;
3287 const unsigned char *vblendweights = NULL;
3288 const unsigned char *vcolor4ub = NULL;
3289 const unsigned short *framedata = NULL;
3290 // temporary memory allocations (because the data in the file may be misaligned)
3291 iqmanim_t *anims = NULL;
3292 iqmbounds_t *bounds = NULL;
3293 iqmjoint1_t *joint1 = NULL;
3294 iqmjoint_t *joint = NULL;
3295 iqmmesh_t *meshes = NULL;
3296 iqmpose1_t *pose1 = NULL;
3297 iqmpose_t *pose = NULL;
3298 iqmvertexarray_t *vas = NULL;
3300 pbase = (unsigned char *)buffer;
3301 pend = (unsigned char *)bufferend;
3303 if (pbase + sizeof(iqmheader_t) > pend)
3304 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3306 // copy struct (otherwise it may be misaligned)
3307 // LordHavoc: okay it's definitely not misaligned here, but for consistency...
3308 memcpy(&header, pbase, sizeof(iqmheader_t));
3310 if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3311 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3312 if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3313 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3315 loadmodel->modeldatatypestring = "IQM";
3317 loadmodel->type = mod_alias;
3318 loadmodel->synctype = ST_RAND;
3321 header.version = LittleLong(header.version);
3322 header.filesize = LittleLong(header.filesize);
3323 header.flags = LittleLong(header.flags);
3324 header.num_text = LittleLong(header.num_text);
3325 header.ofs_text = LittleLong(header.ofs_text);
3326 header.num_meshes = LittleLong(header.num_meshes);
3327 header.ofs_meshes = LittleLong(header.ofs_meshes);
3328 header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3329 header.num_vertexes = LittleLong(header.num_vertexes);
3330 header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3331 header.num_triangles = LittleLong(header.num_triangles);
3332 header.ofs_triangles = LittleLong(header.ofs_triangles);
3333 header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3334 header.num_joints = LittleLong(header.num_joints);
3335 header.ofs_joints = LittleLong(header.ofs_joints);
3336 header.num_poses = LittleLong(header.num_poses);
3337 header.ofs_poses = LittleLong(header.ofs_poses);
3338 header.num_anims = LittleLong(header.num_anims);
3339 header.ofs_anims = LittleLong(header.ofs_anims);
3340 header.num_frames = LittleLong(header.num_frames);
3341 header.num_framechannels = LittleLong(header.num_framechannels);
3342 header.ofs_frames = LittleLong(header.ofs_frames);
3343 header.ofs_bounds = LittleLong(header.ofs_bounds);
3344 header.num_comment = LittleLong(header.num_comment);
3345 header.ofs_comment = LittleLong(header.ofs_comment);
3346 header.num_extensions = LittleLong(header.num_extensions);
3347 header.ofs_extensions = LittleLong(header.ofs_extensions);
3349 if (header.version == 1)
3351 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3352 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3354 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3360 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3361 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3363 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3367 if (pbase + header.ofs_text + header.num_text > pend ||
3368 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3369 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3370 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3371 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3372 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3373 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3374 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3375 pbase + header.ofs_comment + header.num_comment > pend)
3377 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3381 // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3382 if (header.num_vertexarrays)
3383 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3384 if (header.num_anims)
3385 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3386 if (header.ofs_bounds)
3387 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3388 if (header.num_meshes)
3389 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3391 for (i = 0;i < (int)header.num_vertexarrays;i++)
3393 iqmvertexarray_t va;
3395 va.type = LittleLong(vas[i].type);
3396 va.flags = LittleLong(vas[i].flags);
3397 va.format = LittleLong(vas[i].format);
3398 va.size = LittleLong(vas[i].size);
3399 va.offset = LittleLong(vas[i].offset);
3400 vsize = header.num_vertexes*va.size;
3403 case IQM_FLOAT: vsize *= sizeof(float); break;
3404 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3407 if (pbase + va.offset + vsize > pend)
3409 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3413 if (va.format == IQM_FLOAT && va.size == 3)
3414 vposition = (const float *)(pbase + va.offset);
3417 if (va.format == IQM_FLOAT && va.size == 2)
3418 vtexcoord = (const float *)(pbase + va.offset);
3421 if (va.format == IQM_FLOAT && va.size == 3)
3422 vnormal = (const float *)(pbase + va.offset);
3425 if (va.format == IQM_FLOAT && va.size == 4)
3426 vtangent = (const float *)(pbase + va.offset);
3428 case IQM_BLENDINDEXES:
3429 if (va.format == IQM_UBYTE && va.size == 4)
3430 vblendindexes = (const unsigned char *)(pbase + va.offset);
3432 case IQM_BLENDWEIGHTS:
3433 if (va.format == IQM_UBYTE && va.size == 4)
3434 vblendweights = (const unsigned char *)(pbase + va.offset);
3437 if (va.format == IQM_FLOAT && va.size == 4)
3438 vcolor4f = (const float *)(pbase + va.offset);
3439 if (va.format == IQM_UBYTE && va.size == 4)
3440 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3444 if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3446 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3450 text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3452 loadmodel->DrawSky = NULL;
3453 loadmodel->DrawAddWaterPlanes = NULL;
3454 loadmodel->Draw = R_Q1BSP_Draw;
3455 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
3456 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
3457 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
3458 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
3459 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
3460 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
3461 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
3462 loadmodel->DrawLight = R_Q1BSP_DrawLight;
3463 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3464 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3465 loadmodel->PointSuperContents = NULL;
3466 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3468 // load external .skin files if present
3469 skinfiles = Mod_LoadSkinFiles();
3470 if (loadmodel->numskins < 1)
3471 loadmodel->numskins = 1;
3473 loadmodel->numframes = max(header.num_anims, 1);
3474 loadmodel->num_bones = header.num_joints;
3475 loadmodel->num_poses = max(header.num_frames, 1);
3476 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header.num_meshes;
3477 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3478 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3480 meshvertices = header.num_vertexes;
3481 meshtriangles = header.num_triangles;
3483 // do most allocations as one merged chunk
3484 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));
3485 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3486 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3487 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3488 loadmodel->surfmesh.num_vertices = meshvertices;
3489 loadmodel->surfmesh.num_triangles = meshtriangles;
3490 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3491 if (r_enableshadowvolumes.integer)
3493 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3495 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3496 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3497 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3498 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3499 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3500 if (vcolor4f || vcolor4ub)
3502 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]);
3504 if (vblendindexes && vblendweights)
3506 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3507 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3509 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3510 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3511 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3512 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3513 if (vblendindexes && vblendweights)
3515 loadmodel->surfmesh.num_blends = 0;
3516 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3518 if (meshvertices <= 65536)
3520 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3522 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3523 if (vblendindexes && vblendweights)
3524 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3526 for (i = 0;i < loadmodel->numskins;i++)
3528 loadmodel->skinscenes[i].firstframe = i;
3529 loadmodel->skinscenes[i].framecount = 1;
3530 loadmodel->skinscenes[i].loop = true;
3531 loadmodel->skinscenes[i].framerate = 10;
3534 // load the bone info
3535 if (header.version == 1)
3537 iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3538 if (loadmodel->num_bones)
3539 joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3540 for (i = 0;i < loadmodel->num_bones;i++)
3542 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3543 joint1[i].name = LittleLong(injoint1[i].name);
3544 joint1[i].parent = LittleLong(injoint1[i].parent);
3545 for (j = 0;j < 3;j++)
3547 joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
3548 joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
3549 joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
3551 strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3552 loadmodel->data_bones[i].parent = joint1[i].parent;
3553 if (loadmodel->data_bones[i].parent >= i)
3554 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3555 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]);
3556 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3557 if (loadmodel->data_bones[i].parent >= 0)
3559 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3560 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3561 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3563 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3568 iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
3569 if (header.num_joints)
3570 joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3571 for (i = 0;i < loadmodel->num_bones;i++)
3573 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3574 joint[i].name = LittleLong(injoint[i].name);
3575 joint[i].parent = LittleLong(injoint[i].parent);
3576 for (j = 0;j < 3;j++)
3578 joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
3579 joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
3580 joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
3582 joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
3583 strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3584 loadmodel->data_bones[i].parent = joint[i].parent;
3585 if (loadmodel->data_bones[i].parent >= i)
3586 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3587 if (joint[i].rotation[3] > 0)
3588 Vector4Negate(joint[i].rotation, joint[i].rotation);
3589 Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3590 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]);
3591 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3592 if (loadmodel->data_bones[i].parent >= 0)
3594 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3595 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3596 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3598 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3602 // set up the animscenes based on the anims
3603 for (i = 0;i < (int)header.num_anims;i++)
3606 anim.name = LittleLong(anims[i].name);
3607 anim.first_frame = LittleLong(anims[i].first_frame);
3608 anim.num_frames = LittleLong(anims[i].num_frames);
3609 anim.framerate = LittleFloat(anims[i].framerate);
3610 anim.flags = LittleLong(anims[i].flags);
3611 strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3612 loadmodel->animscenes[i].firstframe = anim.first_frame;
3613 loadmodel->animscenes[i].framecount = anim.num_frames;
3614 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3615 loadmodel->animscenes[i].framerate = anim.framerate;
3617 if (header.num_anims <= 0)
3619 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3620 loadmodel->animscenes[0].firstframe = 0;
3621 loadmodel->animscenes[0].framecount = 1;
3622 loadmodel->animscenes[0].loop = true;
3623 loadmodel->animscenes[0].framerate = 10;
3626 loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3627 if(mod_alias_force_animated.string[0])
3628 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3631 if (header.version == 1)
3633 iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3634 if (header.num_poses)
3635 pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3636 for (i = 0;i < (int)header.num_poses;i++)
3639 pose1[i].parent = LittleLong(inpose1[i].parent);
3640 pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
3641 for (j = 0;j < 9;j++)
3643 pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
3644 pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
3646 f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3647 f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3648 f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3649 f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3650 f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3651 f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3653 if (header.num_frames <= 0)
3655 for (i = 0;i < loadmodel->num_bones;i++)
3658 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3659 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3660 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3666 iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
3667 if (header.num_poses)
3668 pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3669 for (i = 0;i < (int)header.num_poses;i++)
3672 pose[i].parent = LittleLong(inpose[i].parent);
3673 pose[i].channelmask = LittleLong(inpose[i].channelmask);
3674 for (j = 0;j < 10;j++)
3676 pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
3677 pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
3679 f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3680 f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3681 f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3682 f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3683 f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3684 f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3686 if (header.num_frames <= 0)
3688 for (i = 0;i < loadmodel->num_bones;i++)
3691 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3692 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3693 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3697 loadmodel->num_posescale = biggestorigin / 32767.0f;
3698 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3700 // load the pose data
3701 // this unaligned memory access is safe (LittleShort reads as bytes)
3702 framedata = (const unsigned short *)(pbase + header.ofs_frames);
3703 if (header.version == 1)
3705 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3707 for (j = 0;j < (int)header.num_poses;j++, k++)
3709 float qx, qy, qz, qw;
3710 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));
3711 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));
3712 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));
3713 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3714 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3715 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3716 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3717 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3718 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3719 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3720 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3721 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3722 // skip scale data for now
3723 if(pose1[j].channelmask&64) framedata++;
3724 if(pose1[j].channelmask&128) framedata++;
3725 if(pose1[j].channelmask&256) framedata++;
3728 if (header.num_frames <= 0)
3730 for (i = 0;i < loadmodel->num_bones;i++)
3732 float qx, qy, qz, qw;
3733 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3734 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3735 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3736 qx = joint1[i].rotation[0];
3737 qy = joint1[i].rotation[1];
3738 qz = joint1[i].rotation[2];
3739 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3740 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3741 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3742 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3743 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3744 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3750 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3752 for (j = 0;j < (int)header.num_poses;j++, k++)
3755 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));
3756 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));
3757 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));
3758 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3759 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3760 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3761 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3763 Vector4Negate(rot, rot);
3764 Vector4Normalize2(rot, rot);
3765 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3766 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3767 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3768 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3769 // skip scale data for now
3770 if(pose[j].channelmask&128) framedata++;
3771 if(pose[j].channelmask&256) framedata++;
3772 if(pose[j].channelmask&512) framedata++;
3775 if (header.num_frames <= 0)
3777 for (i = 0;i < loadmodel->num_bones;i++)
3779 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3780 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3781 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3782 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3783 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3784 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3785 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3790 // load bounding box data
3791 if (header.ofs_bounds)
3793 float xyradius = 0, radius = 0;
3794 VectorClear(loadmodel->normalmins);
3795 VectorClear(loadmodel->normalmaxs);
3796 for (i = 0; i < (int)header.num_frames;i++)
3799 bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3800 bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3801 bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3802 bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);
3803 bound.maxs[1] = LittleFloat(bounds[i].maxs[1]);
3804 bound.maxs[2] = LittleFloat(bounds[i].maxs[2]);
3805 bound.xyradius = LittleFloat(bounds[i].xyradius);
3806 bound.radius = LittleFloat(bounds[i].radius);
3809 VectorCopy(bound.mins, loadmodel->normalmins);
3810 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3814 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3815 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3816 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3817 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3818 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3819 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3821 if (bound.xyradius > xyradius)
3822 xyradius = bound.xyradius;
3823 if (bound.radius > radius)
3824 radius = bound.radius;
3826 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3827 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3828 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3829 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3830 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3831 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3832 loadmodel->radius = radius;
3833 loadmodel->radius2 = radius * radius;
3836 // load triangle data
3837 // this unaligned memory access is safe (LittleLong reads as bytes)
3838 inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3839 outelements = loadmodel->surfmesh.data_element3i;
3840 for (i = 0;i < (int)header.num_triangles;i++)
3842 outelements[0] = LittleLong(inelements[0]);
3843 outelements[1] = LittleLong(inelements[1]);
3844 outelements[2] = LittleLong(inelements[2]);
3848 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3850 if (header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
3852 // this unaligned memory access is safe (LittleLong reads as bytes)
3853 inneighbors = (const int *)(pbase + header.ofs_neighbors);
3854 outneighbors = loadmodel->surfmesh.data_neighbor3i;
3855 for (i = 0;i < (int)header.num_triangles;i++)
3857 outneighbors[0] = LittleLong(inneighbors[0]);
3858 outneighbors[1] = LittleLong(inneighbors[1]);
3859 outneighbors[2] = LittleLong(inneighbors[2]);
3866 // this unaligned memory access is safe (LittleFloat reads as bytes)
3867 outvertex = loadmodel->surfmesh.data_vertex3f;
3868 for (i = 0;i < (int)header.num_vertexes;i++)
3870 outvertex[0] = LittleFloat(vposition[0]);
3871 outvertex[1] = LittleFloat(vposition[1]);
3872 outvertex[2] = LittleFloat(vposition[2]);
3877 outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3878 // this unaligned memory access is safe (LittleFloat reads as bytes)
3879 for (i = 0;i < (int)header.num_vertexes;i++)
3881 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3882 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3887 // this unaligned memory access is safe (LittleFloat reads as bytes)
3890 outnormal = loadmodel->surfmesh.data_normal3f;
3891 for (i = 0;i < (int)header.num_vertexes;i++)
3893 outnormal[0] = LittleFloat(vnormal[0]);
3894 outnormal[1] = LittleFloat(vnormal[1]);
3895 outnormal[2] = LittleFloat(vnormal[2]);
3901 // this unaligned memory access is safe (LittleFloat reads as bytes)
3902 if(vnormal && vtangent)
3904 outnormal = loadmodel->surfmesh.data_normal3f;
3905 outsvector = loadmodel->surfmesh.data_svector3f;
3906 outtvector = loadmodel->surfmesh.data_tvector3f;
3907 for (i = 0;i < (int)header.num_vertexes;i++)
3909 outsvector[0] = LittleFloat(vtangent[0]);
3910 outsvector[1] = LittleFloat(vtangent[1]);
3911 outsvector[2] = LittleFloat(vtangent[2]);
3912 if(LittleFloat(vtangent[3]) < 0)
3913 CrossProduct(outsvector, outnormal, outtvector);
3915 CrossProduct(outnormal, outsvector, outtvector);
3923 // this unaligned memory access is safe (all bytes)
3924 if (vblendindexes && vblendweights)
3926 for (i = 0; i < (int)header.num_vertexes;i++)
3928 blendweights_t weights;
3929 memcpy(weights.index, vblendindexes + i*4, 4);
3930 memcpy(weights.influence, vblendweights + i*4, 4);
3931 loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3932 loadmodel->surfmesh.data_skeletalindex4ub[i*4 ] = weights.index[0];
3933 loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3934 loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3935 loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3936 loadmodel->surfmesh.data_skeletalweight4ub[i*4 ] = weights.influence[0];
3937 loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3938 loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3939 loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3945 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3946 // this unaligned memory access is safe (LittleFloat reads as bytes)
3947 for (i = 0;i < (int)header.num_vertexes;i++)
3949 outcolor[0] = LittleFloat(vcolor4f[0]);
3950 outcolor[1] = LittleFloat(vcolor4f[1]);
3951 outcolor[2] = LittleFloat(vcolor4f[2]);
3952 outcolor[3] = LittleFloat(vcolor4f[3]);
3959 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3960 // this unaligned memory access is safe (all bytes)
3961 for (i = 0;i < (int)header.num_vertexes;i++)
3963 outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3964 outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3965 outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3966 outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3973 for (i = 0;i < (int)header.num_meshes;i++)
3976 msurface_t *surface;
3978 mesh.name = LittleLong(meshes[i].name);
3979 mesh.material = LittleLong(meshes[i].material);
3980 mesh.first_vertex = LittleLong(meshes[i].first_vertex);
3981 mesh.num_vertexes = LittleLong(meshes[i].num_vertexes);
3982 mesh.first_triangle = LittleLong(meshes[i].first_triangle);
3983 mesh.num_triangles = LittleLong(meshes[i].num_triangles);
3985 loadmodel->sortedmodelsurfaces[i] = i;
3986 surface = loadmodel->data_surfaces + i;
3987 surface->texture = loadmodel->data_textures + i;
3988 surface->num_firsttriangle = mesh.first_triangle;
3989 surface->num_triangles = mesh.num_triangles;
3990 surface->num_firstvertex = mesh.first_vertex;
3991 surface->num_vertices = mesh.num_vertexes;
3993 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
3996 Mod_FreeSkinFiles(skinfiles);
3997 Mod_MakeSortedSurfaces(loadmodel);
3999 // compute all the mesh information that was not loaded from the file
4000 if (loadmodel->surfmesh.data_element3s)
4001 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
4002 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
4004 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);
4005 if (!vnormal || !vtangent)
4006 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);
4007 if (!header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
4008 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
4009 if (!header.ofs_bounds)
4010 Mod_Alias_CalculateBoundingBox();
4012 // Always make a BIH for the first frame, we can use it where possible.
4013 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
4014 if (!loadmodel->surfmesh.isanimated)
4016 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
4017 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
4018 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
4019 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
4020 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
4023 if (joint ) Mem_Free(joint );joint = NULL;
4024 if (joint1 ) Mem_Free(joint1 );joint1 = NULL;
4025 if (pose ) Mem_Free(pose );pose = NULL;
4026 if (pose1 ) Mem_Free(pose1 );pose1 = NULL;
4028 // because shaders can do somewhat unexpected things, check for unusual features now
4029 for (i = 0;i < loadmodel->num_textures;i++)
4031 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
4032 mod->DrawSky = R_Q1BSP_DrawSky;
4033 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
4034 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;