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 pose7s = model->data_poses7s + 7 * (frameblend[0].subframe * model->num_bones + i);
98 float lerp = frameblend[0].lerp,
99 tx = pose7s[0], ty = pose7s[1], tz = pose7s[2],
100 rx = pose7s[3] * lerp,
101 ry = pose7s[4] * lerp,
102 rz = pose7s[5] * lerp,
103 rw = pose7s[6] * lerp,
104 dx = tx*rw + ty*rz - tz*ry,
105 dy = -tx*rz + ty*rw + tz*rx,
106 dz = tx*ry - ty*rx + tz*rw,
107 dw = -tx*rx - ty*ry - tz*rz,
108 scale, sx, sy, sz, sw;
109 for (blends = 1;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
111 const short * RESTRICT pose7s = model->data_poses7s + 7 * (frameblend[blends].subframe * model->num_bones + i);
112 float lerp = frameblend[blends].lerp,
113 tx = pose7s[0], ty = pose7s[1], tz = pose7s[2],
114 qx = pose7s[3], qy = pose7s[4], qz = pose7s[5], qw = pose7s[6];
115 if(rx*qx + ry*qy + rz*qz + rw*qw < 0) lerp = -lerp;
124 dx += tx*qw + ty*qz - tz*qy;
125 dy += -tx*qz + ty*qw + tz*qx;
126 dz += tx*qy - ty*qx + tz*qw;
127 dw += -tx*qx - ty*qy - tz*qz;
129 // generate a matrix from the dual-quaternion, implicitly normalizing it in the process
130 scale = 1.0f / (rx*rx + ry*ry + rz*rz + rw*rw);
135 m[0] = sw*rw + sx*rx - sy*ry - sz*rz;
136 m[1] = 2*(sx*ry - sw*rz);
137 m[2] = 2*(sx*rz + sw*ry);
138 m[3] = model->num_posescale*(dx*sw - dy*sz + dz*sy - dw*sx);
139 m[4] = 2*(sx*ry + sw*rz);
140 m[5] = sw*rw + sy*ry - sx*rx - sz*rz;
141 m[6] = 2*(sy*rz - sw*rx);
142 m[7] = model->num_posescale*(dx*sz + dy*sw - dz*sx - dw*sy);
143 m[8] = 2*(sx*rz - sw*ry);
144 m[9] = 2*(sy*rz + sw*rx);
145 m[10] = sw*rw + sz*rz - sx*rx - sy*ry;
146 m[11] = model->num_posescale*(dy*sx + dz*sw - dx*sy - dw*sz);
147 if (i == r_skeletal_debugbone.integer)
148 m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value;
149 m[3] *= r_skeletal_debugtranslatex.value;
150 m[7] *= r_skeletal_debugtranslatey.value;
151 m[11] *= r_skeletal_debugtranslatez.value;
152 if (model->data_bones[i].parent >= 0)
153 R_ConcatTransforms(bonepose + model->data_bones[i].parent * 12, m, bonepose + i * 12);
155 memcpy(bonepose + i * 12, m, sizeof(m));
156 // create a relative deformation matrix to describe displacement
157 // from the base mesh, which is used by the actual weighting
158 R_ConcatTransforms(bonepose + i * 12, model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12);
163 static void Mod_Skeletal_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
166 if (!model->surfmesh.num_vertices)
169 if (!model->num_bones)
171 if (vertex3f) memcpy(vertex3f, model->surfmesh.data_vertex3f, model->surfmesh.num_vertices*sizeof(float[3]));
172 if (normal3f) memcpy(normal3f, model->surfmesh.data_normal3f, model->surfmesh.num_vertices*sizeof(float[3]));
173 if (svector3f) memcpy(svector3f, model->surfmesh.data_svector3f, model->surfmesh.num_vertices*sizeof(float[3]));
174 if (tvector3f) memcpy(tvector3f, model->surfmesh.data_tvector3f, model->surfmesh.num_vertices*sizeof(float[3]));
179 if(r_skeletal_use_sse_defined)
180 if(r_skeletal_use_sse.integer)
182 Mod_Skeletal_AnimateVertices_SSE(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f);
186 Mod_Skeletal_AnimateVertices_Generic(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f);
189 void Mod_AliasInit (void)
192 Cvar_RegisterVariable(&r_skeletal_debugbone);
193 Cvar_RegisterVariable(&r_skeletal_debugbonecomponent);
194 Cvar_RegisterVariable(&r_skeletal_debugbonevalue);
195 Cvar_RegisterVariable(&r_skeletal_debugtranslatex);
196 Cvar_RegisterVariable(&r_skeletal_debugtranslatey);
197 Cvar_RegisterVariable(&r_skeletal_debugtranslatez);
198 Cvar_RegisterVariable(&mod_alias_supporttagscale);
199 Cvar_RegisterVariable(&mod_alias_force_animated);
200 for (i = 0;i < 320;i++)
201 mod_md3_sin[i] = sin(i * M_PI * 2.0f / 256.0);
205 Con_Printf("Skeletal animation uses SSE code path\n");
206 r_skeletal_use_sse_defined = true;
207 Cvar_RegisterVariable(&r_skeletal_use_sse);
210 Con_Printf("Skeletal animation uses generic code path (SSE disabled or not detected)\n");
212 Con_Printf("Skeletal animation uses generic code path (SSE not compiled in)\n");
216 static int Mod_Skeletal_AddBlend(dp_model_t *model, const blendweights_t *newweights)
219 blendweights_t *weights;
220 if(!newweights->influence[1])
221 return newweights->index[0];
222 weights = model->surfmesh.data_blendweights;
223 for (i = 0;i < model->surfmesh.num_blends;i++, weights++)
225 if (!memcmp(weights, newweights, sizeof(blendweights_t)))
226 return model->num_bones + i;
228 model->surfmesh.num_blends++;
229 memcpy(weights, newweights, sizeof(blendweights_t));
230 return model->num_bones + i;
233 static int Mod_Skeletal_CompressBlend(dp_model_t *model, const int *newindex, const float *newinfluence)
237 blendweights_t newweights;
241 for (i = 0;i < 4;i++)
242 scale += newinfluence[i];
243 scale = 255.0f / scale;
245 for (i = 0;i < 4;i++)
247 newweights.index[i] = newindex[i];
248 newweights.influence[i] = (unsigned char)(newinfluence[i] * scale);
249 total += newweights.influence[i];
253 for (i = 0;i < 4;i++)
255 if(newweights.influence[i] > 0 && total > 255)
257 newweights.influence[i]--;
264 for (i = 0; i < 4;i++)
266 if(newweights.influence[i] < 255 && total < 255)
268 newweights.influence[i]++;
273 return Mod_Skeletal_AddBlend(model, &newweights);
276 static void Mod_MD3_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
279 int i, numblends, blendnum;
280 int numverts = model->surfmesh.num_vertices;
282 for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
284 //VectorMA(translate, model->surfmesh.num_morphmdlframetranslate, frameblend[blendnum].lerp, translate);
285 if (frameblend[blendnum].lerp > 0)
286 numblends = blendnum + 1;
288 // special case for the first blend because it avoids some adds and the need to memset the arrays first
289 for (blendnum = 0;blendnum < numblends;blendnum++)
291 const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].subframe;
294 float scale = frameblend[blendnum].lerp * (1.0f / 64.0f);
297 for (i = 0;i < numverts;i++)
299 vertex3f[i * 3 + 0] = verts[i].origin[0] * scale;
300 vertex3f[i * 3 + 1] = verts[i].origin[1] * scale;
301 vertex3f[i * 3 + 2] = verts[i].origin[2] * scale;
306 for (i = 0;i < numverts;i++)
308 vertex3f[i * 3 + 0] += verts[i].origin[0] * scale;
309 vertex3f[i * 3 + 1] += verts[i].origin[1] * scale;
310 vertex3f[i * 3 + 2] += verts[i].origin[2] * scale;
314 // the yaw and pitch stored in md3 models are 8bit quantized angles
315 // (0-255), and as such a lookup table is very well suited to
316 // decoding them, and since cosine is equivalent to sine with an
317 // extra 45 degree rotation, this uses one lookup table for both
318 // sine and cosine with a +64 bias to get cosine.
321 float lerp = frameblend[blendnum].lerp;
324 for (i = 0;i < numverts;i++)
326 normal3f[i * 3 + 0] = mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch ] * lerp;
327 normal3f[i * 3 + 1] = mod_md3_sin[verts[i].yaw ] * mod_md3_sin[verts[i].pitch ] * lerp;
328 normal3f[i * 3 + 2] = mod_md3_sin[verts[i].pitch + 64] * lerp;
333 for (i = 0;i < numverts;i++)
335 normal3f[i * 3 + 0] += mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch ] * lerp;
336 normal3f[i * 3 + 1] += mod_md3_sin[verts[i].yaw ] * mod_md3_sin[verts[i].pitch ] * lerp;
337 normal3f[i * 3 + 2] += mod_md3_sin[verts[i].pitch + 64] * lerp;
343 const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
344 float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
347 for (i = 0;i < numverts;i++, texvecvert++)
349 VectorScale(texvecvert->svec, f, svector3f + i*3);
350 VectorScale(texvecvert->tvec, f, tvector3f + i*3);
355 for (i = 0;i < numverts;i++, texvecvert++)
357 VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
358 VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
364 static void Mod_MDL_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
367 int i, numblends, blendnum;
368 int numverts = model->surfmesh.num_vertices;
370 VectorClear(translate);
372 // blend the frame translates to avoid redundantly doing so on each vertex
373 // (a bit of a brain twister but it works)
374 for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
376 if (model->surfmesh.data_morphmd2framesize6f)
377 VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6 + 3, translate);
379 VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.num_morphmdlframetranslate, translate);
380 if (frameblend[blendnum].lerp > 0)
381 numblends = blendnum + 1;
383 // special case for the first blend because it avoids some adds and the need to memset the arrays first
384 for (blendnum = 0;blendnum < numblends;blendnum++)
386 const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].subframe;
390 if (model->surfmesh.data_morphmd2framesize6f)
391 VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6, frameblend[blendnum].lerp, scale);
393 VectorScale(model->surfmesh.num_morphmdlframescale, frameblend[blendnum].lerp, scale);
396 for (i = 0;i < numverts;i++)
398 vertex3f[i * 3 + 0] = translate[0] + verts[i].v[0] * scale[0];
399 vertex3f[i * 3 + 1] = translate[1] + verts[i].v[1] * scale[1];
400 vertex3f[i * 3 + 2] = translate[2] + verts[i].v[2] * scale[2];
405 for (i = 0;i < numverts;i++)
407 vertex3f[i * 3 + 0] += verts[i].v[0] * scale[0];
408 vertex3f[i * 3 + 1] += verts[i].v[1] * scale[1];
409 vertex3f[i * 3 + 2] += verts[i].v[2] * scale[2];
413 // the vertex normals in mdl models are an index into a table of
414 // 162 unique values, this very crude quantization reduces the
415 // vertex normal to only one byte, which saves a lot of space but
416 // also makes lighting pretty coarse
419 float lerp = frameblend[blendnum].lerp;
422 for (i = 0;i < numverts;i++)
424 const float *vn = m_bytenormals[verts[i].lightnormalindex];
425 VectorScale(vn, lerp, normal3f + i*3);
430 for (i = 0;i < numverts;i++)
432 const float *vn = m_bytenormals[verts[i].lightnormalindex];
433 VectorMA(normal3f + i*3, lerp, vn, normal3f + i*3);
439 const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
440 float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
443 for (i = 0;i < numverts;i++, texvecvert++)
445 VectorScale(texvecvert->svec, f, svector3f + i*3);
446 VectorScale(texvecvert->tvec, f, tvector3f + i*3);
451 for (i = 0;i < numverts;i++, texvecvert++)
453 VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
454 VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
461 int Mod_Alias_GetTagMatrix(const dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, matrix4x4_t *outmatrix)
464 matrix4x4_t parentbonematrix;
465 matrix4x4_t tempbonematrix;
466 matrix4x4_t bonematrix;
467 matrix4x4_t blendmatrix;
474 *outmatrix = identitymatrix;
475 if (skeleton && skeleton->relativetransforms)
477 if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
479 *outmatrix = skeleton->relativetransforms[tagindex];
480 while ((tagindex = model->data_bones[tagindex].parent) >= 0)
483 Matrix4x4_Concat(outmatrix, &skeleton->relativetransforms[tagindex], &temp);
486 else if (model->num_bones)
488 if (tagindex < 0 || tagindex >= model->num_bones)
490 Matrix4x4_Clear(&blendmatrix);
491 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
493 lerp = frameblend[blendindex].lerp;
494 Matrix4x4_FromBonePose7s(&bonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + tagindex));
495 parenttagindex = tagindex;
496 while ((parenttagindex = model->data_bones[parenttagindex].parent) >= 0)
498 Matrix4x4_FromBonePose7s(&parentbonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + parenttagindex));
499 tempbonematrix = bonematrix;
500 Matrix4x4_Concat(&bonematrix, &parentbonematrix, &tempbonematrix);
502 Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
504 *outmatrix = blendmatrix;
506 else if (model->num_tags)
508 if (tagindex < 0 || tagindex >= model->num_tags)
510 for (k = 0;k < 12;k++)
512 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
514 lerp = frameblend[blendindex].lerp;
515 input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
516 for (k = 0;k < 12;k++)
517 blendtag[k] += input[k] * lerp;
519 Matrix4x4_FromArray12FloatGL(outmatrix, blendtag);
522 if(!mod_alias_supporttagscale.integer)
523 Matrix4x4_Normalize3(outmatrix, outmatrix);
528 int Mod_Alias_GetExtendedTagInfoForIndex(const dp_model_t *model, unsigned int skin, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
533 matrix4x4_t bonematrix;
534 matrix4x4_t blendmatrix;
538 if (skeleton && skeleton->relativetransforms)
540 if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
542 *parentindex = skeleton->model->data_bones[tagindex].parent;
543 *tagname = skeleton->model->data_bones[tagindex].name;
544 *tag_localmatrix = skeleton->relativetransforms[tagindex];
547 else if (model->num_bones)
549 if (tagindex < 0 || tagindex >= model->num_bones)
551 *parentindex = model->data_bones[tagindex].parent;
552 *tagname = model->data_bones[tagindex].name;
553 Matrix4x4_Clear(&blendmatrix);
554 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
556 lerp = frameblend[blendindex].lerp;
557 Matrix4x4_FromBonePose7s(&bonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + tagindex));
558 Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
560 *tag_localmatrix = blendmatrix;
563 else if (model->num_tags)
565 if (tagindex < 0 || tagindex >= model->num_tags)
568 *tagname = model->data_tags[tagindex].name;
569 for (k = 0;k < 12;k++)
571 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
573 lerp = frameblend[blendindex].lerp;
574 input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
575 for (k = 0;k < 12;k++)
576 blendtag[k] += input[k] * lerp;
578 Matrix4x4_FromArray12FloatGL(tag_localmatrix, blendtag);
585 int Mod_Alias_GetTagIndexForName(const dp_model_t *model, unsigned int skin, const char *tagname)
588 if(skin >= (unsigned int)model->numskins)
590 if (model->num_bones)
591 for (i = 0;i < model->num_bones;i++)
592 if (!strcasecmp(tagname, model->data_bones[i].name))
595 for (i = 0;i < model->num_tags;i++)
596 if (!strcasecmp(tagname, model->data_tags[i].name))
601 static void Mod_BuildBaseBonePoses(void)
604 matrix4x4_t *basebonepose;
605 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
606 matrix4x4_t bonematrix;
607 matrix4x4_t tempbonematrix;
608 if (!loadmodel->num_bones)
610 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
611 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
613 Matrix4x4_FromBonePose7s(&bonematrix, loadmodel->num_posescale, loadmodel->data_poses7s + 7 * boneindex);
614 if (loadmodel->data_bones[boneindex].parent >= 0)
616 tempbonematrix = bonematrix;
617 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
619 basebonepose[boneindex] = bonematrix;
620 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
621 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
623 Mem_Free(basebonepose);
626 static qboolean Mod_Alias_CalculateBoundingBox(void)
629 qboolean firstvertex = true;
630 float dist, yawradius, radius;
632 qboolean isanimated = false;
633 VectorClear(loadmodel->normalmins);
634 VectorClear(loadmodel->normalmaxs);
637 if (loadmodel->AnimateVertices)
639 float *vertex3f, *refvertex3f;
640 frameblend_t frameblend[MAX_FRAMEBLENDS];
641 memset(frameblend, 0, sizeof(frameblend));
642 frameblend[0].lerp = 1;
643 vertex3f = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]) * 2);
645 for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++)
647 loadmodel->AnimateVertices(loadmodel, frameblend, NULL, vertex3f, NULL, NULL, NULL);
650 // make a copy of the first frame for comparing all others
651 refvertex3f = vertex3f + loadmodel->surfmesh.num_vertices * 3;
652 memcpy(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
656 if (!isanimated && memcmp(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3])))
659 for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
664 VectorCopy(v, loadmodel->normalmins);
665 VectorCopy(v, loadmodel->normalmaxs);
669 if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
670 if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
671 if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
672 if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
673 if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
674 if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
676 dist = v[0] * v[0] + v[1] * v[1];
677 if (yawradius < dist)
689 for (vnum = 0, v = loadmodel->surfmesh.data_vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
694 VectorCopy(v, loadmodel->normalmins);
695 VectorCopy(v, loadmodel->normalmaxs);
699 if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
700 if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
701 if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
702 if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
703 if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
704 if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
706 dist = v[0] * v[0] + v[1] * v[1];
707 if (yawradius < dist)
714 radius = sqrt(radius);
715 yawradius = sqrt(yawradius);
716 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius;
717 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = yawradius;
718 loadmodel->yawmins[2] = loadmodel->normalmins[2];
719 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
720 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
721 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
722 loadmodel->radius = radius;
723 loadmodel->radius2 = radius * radius;
727 static void Mod_Alias_MorphMesh_CompileFrames(void)
730 frameblend_t frameblend[MAX_FRAMEBLENDS];
731 unsigned char *datapointer;
732 memset(frameblend, 0, sizeof(frameblend));
733 frameblend[0].lerp = 1;
734 datapointer = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * (sizeof(float[3]) * 4 + loadmodel->surfmesh.num_morphframes * sizeof(texvecvertex_t)));
735 loadmodel->surfmesh.data_vertex3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
736 loadmodel->surfmesh.data_svector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
737 loadmodel->surfmesh.data_tvector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
738 loadmodel->surfmesh.data_normal3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
739 loadmodel->surfmesh.data_morphtexvecvertex = (texvecvertex_t *)datapointer;datapointer += loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices * sizeof(texvecvertex_t);
740 // this counts down from the last frame to the first so that the final data in surfmesh is for frame zero (which is what the renderer expects to be there)
741 for (i = loadmodel->surfmesh.num_morphframes-1;i >= 0;i--)
743 frameblend[0].subframe = i;
744 loadmodel->AnimateVertices(loadmodel, frameblend, NULL, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_normal3f, NULL, NULL);
745 Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
746 // encode the svector and tvector in 3 byte format for permanent storage
747 for (j = 0;j < loadmodel->surfmesh.num_vertices;j++)
749 VectorScaleCast(loadmodel->surfmesh.data_svector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].svec);
750 VectorScaleCast(loadmodel->surfmesh.data_tvector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].tvec);
755 static void Mod_MDLMD2MD3_TraceLine(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask)
758 float segmentmins[3], segmentmaxs[3];
760 float vertex3fbuf[1024*3];
761 float *vertex3f = vertex3fbuf;
762 memset(trace, 0, sizeof(*trace));
764 trace->realfraction = 1;
765 trace->hitsupercontentsmask = hitsupercontentsmask;
766 if (model->surfmesh.num_vertices > 1024)
767 vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
768 segmentmins[0] = min(start[0], end[0]) - 1;
769 segmentmins[1] = min(start[1], end[1]) - 1;
770 segmentmins[2] = min(start[2], end[2]) - 1;
771 segmentmaxs[0] = max(start[0], end[0]) + 1;
772 segmentmaxs[1] = max(start[1], end[1]) + 1;
773 segmentmaxs[2] = max(start[2], end[2]) + 1;
774 model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
775 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
776 Collision_TraceLineTriangleMeshFloat(trace, start, end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
777 if (vertex3f != vertex3fbuf)
781 static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask)
784 vec3_t shiftstart, shiftend;
785 float segmentmins[3], segmentmaxs[3];
787 float vertex3fbuf[1024*3];
788 float *vertex3f = vertex3fbuf;
789 colboxbrushf_t thisbrush_start, thisbrush_end;
790 vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
792 if (VectorCompare(boxmins, boxmaxs))
794 VectorAdd(start, boxmins, shiftstart);
795 VectorAdd(end, boxmins, shiftend);
796 Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask);
797 VectorSubtract(trace->endpos, boxmins, trace->endpos);
801 // box trace, performed as brush trace
802 memset(trace, 0, sizeof(*trace));
804 trace->realfraction = 1;
805 trace->hitsupercontentsmask = hitsupercontentsmask;
806 if (model->surfmesh.num_vertices > 1024)
807 vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
808 segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1;
809 segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1;
810 segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1;
811 segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1;
812 segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1;
813 segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1;
814 VectorAdd(start, boxmins, boxstartmins);
815 VectorAdd(start, boxmaxs, boxstartmaxs);
816 VectorAdd(end, boxmins, boxendmins);
817 VectorAdd(end, boxmaxs, boxendmaxs);
818 Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL);
819 Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL);
820 model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
821 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
822 Collision_TraceBrushTriangleMeshFloat(trace, &thisbrush_start.brush, &thisbrush_end.brush, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
823 if (vertex3f != vertex3fbuf)
827 static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap)
830 for (i = 0;i < inverts;i++)
832 if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
834 j = vertremap[i]; // not onseam
837 j = vertremap[i+inverts]; // onseam
843 static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *vertremap)
845 int i, f, pose, groupframes;
847 daliasframetype_t *pframetype;
848 daliasframe_t *pinframe;
849 daliasgroup_t *group;
850 daliasinterval_t *intervals;
853 scene = loadmodel->animscenes;
854 for (f = 0;f < loadmodel->numframes;f++)
856 pframetype = (daliasframetype_t *)datapointer;
857 datapointer += sizeof(daliasframetype_t);
858 if (LittleLong (pframetype->type) == ALIAS_SINGLE)
860 // a single frame is still treated as a group
867 group = (daliasgroup_t *)datapointer;
868 datapointer += sizeof(daliasgroup_t);
869 groupframes = LittleLong (group->numframes);
871 // intervals (time per frame)
872 intervals = (daliasinterval_t *)datapointer;
873 datapointer += sizeof(daliasinterval_t) * groupframes;
875 interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
876 if (interval < 0.01f)
878 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
883 // get scene name from first frame
884 pinframe = (daliasframe_t *)datapointer;
886 strlcpy(scene->name, pinframe->name, sizeof(scene->name));
887 scene->firstframe = pose;
888 scene->framecount = groupframes;
889 scene->framerate = 1.0f / interval;
894 for (i = 0;i < groupframes;i++)
896 datapointer += sizeof(daliasframe_t);
897 Mod_ConvertAliasVerts(inverts, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphmdlvertex + pose * loadmodel->surfmesh.num_vertices, vertremap);
898 datapointer += sizeof(trivertx_t) * inverts;
904 static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *skinframe)
906 if (cls.state == ca_dedicated)
910 skinframe = R_SkinFrame_LoadMissing();
911 memset(texture, 0, sizeof(*texture));
912 texture->currentframe = texture;
913 //texture->animated = false;
914 texture->numskinframes = 1;
915 texture->skinframerate = 1;
916 texture->skinframes[0] = skinframe;
917 texture->currentskinframe = skinframe;
918 //texture->backgroundnumskinframes = 0;
919 //texture->customblendfunc[0] = 0;
920 //texture->customblendfunc[1] = 0;
921 //texture->surfaceflags = 0;
922 //texture->supercontents = 0;
923 //texture->surfaceparms = 0;
924 //texture->textureflags = 0;
926 texture->basematerialflags = MATERIALFLAG_WALL;
927 if (texture->currentskinframe->hasalpha)
928 texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
929 texture->currentmaterialflags = texture->basematerialflags;
930 texture->offsetmapping = OFFSETMAPPING_DEFAULT;
931 texture->offsetscale = 1;
932 texture->offsetbias = 0;
933 texture->specularscalemod = 1;
934 texture->specularpowermod = 1;
935 texture->surfaceflags = 0;
936 texture->supercontents = SUPERCONTENTS_SOLID;
937 if (!(texture->basematerialflags & MATERIALFLAG_BLENDED))
938 texture->supercontents |= SUPERCONTENTS_OPAQUE;
939 texture->transparentsort = TRANSPARENTSORT_DISTANCE;
940 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
941 // JUST GREP FOR "specularscalemod = 1".
944 void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
947 char stripbuf[MAX_QPATH];
948 skinfileitem_t *skinfileitem;
949 if(developer_extra.integer)
950 Con_DPrintf("Looking up texture for %s (default: %s)\n", meshname, shadername);
953 // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
954 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
956 memset(skin, 0, sizeof(*skin));
958 for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
960 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
961 if (!strcmp(skinfileitem->name, meshname))
963 Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf));
964 if(developer_extra.integer)
965 Con_DPrintf("--> got %s from skin file\n", stripbuf);
966 Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
972 // don't render unmentioned meshes
973 Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
974 if(developer_extra.integer)
975 Con_DPrintf("--> skipping\n");
976 skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW;
982 if(developer_extra.integer)
983 Con_DPrintf("--> using default\n");
984 Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf));
985 Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
989 #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);
990 #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);
991 void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
993 int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
994 float scales, scalet, interval;
998 stvert_t *pinstverts;
999 dtriangle_t *pintriangles;
1000 daliasskintype_t *pinskintype;
1001 daliasskingroup_t *pinskingroup;
1002 daliasskininterval_t *pinskinintervals;
1003 daliasframetype_t *pinframetype;
1004 daliasgroup_t *pinframegroup;
1005 unsigned char *datapointer, *startframes, *startskins;
1006 char name[MAX_QPATH];
1007 skinframe_t *tempskinframe;
1008 animscene_t *tempskinscenes;
1009 texture_t *tempaliasskins;
1011 int *vertonseam, *vertremap;
1012 skinfile_t *skinfiles;
1015 datapointer = (unsigned char *)buffer;
1016 pinmodel = (mdl_t *)datapointer;
1017 datapointer += sizeof(mdl_t);
1019 version = LittleLong (pinmodel->version);
1020 if (version != ALIAS_VERSION)
1021 Host_Error ("%s has wrong version number (%i should be %i)",
1022 loadmodel->name, version, ALIAS_VERSION);
1024 loadmodel->modeldatatypestring = "MDL";
1026 loadmodel->type = mod_alias;
1027 loadmodel->DrawSky = NULL;
1028 loadmodel->DrawAddWaterPlanes = NULL;
1029 loadmodel->Draw = R_Q1BSP_Draw;
1030 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1031 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1032 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1033 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1034 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1035 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1036 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1037 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1038 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1039 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1040 // FIXME add TraceBrush!
1041 loadmodel->PointSuperContents = NULL;
1042 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1044 loadmodel->num_surfaces = 1;
1045 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1046 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
1047 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1048 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1049 loadmodel->sortedmodelsurfaces[0] = 0;
1051 loadmodel->numskins = LittleLong(pinmodel->numskins);
1052 BOUNDI(loadmodel->numskins,0,65536);
1053 skinwidth = LittleLong (pinmodel->skinwidth);
1054 BOUNDI(skinwidth,0,65536);
1055 skinheight = LittleLong (pinmodel->skinheight);
1056 BOUNDI(skinheight,0,65536);
1057 numverts = LittleLong(pinmodel->numverts);
1058 BOUNDI(numverts,0,65536);
1059 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
1060 BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
1061 loadmodel->numframes = LittleLong(pinmodel->numframes);
1062 BOUNDI(loadmodel->numframes,0,65536);
1063 loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
1064 BOUNDI((int)loadmodel->synctype,0,2);
1065 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1066 i = LittleLong (pinmodel->flags);
1067 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1069 for (i = 0;i < 3;i++)
1071 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
1072 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
1075 startskins = datapointer;
1077 for (i = 0;i < loadmodel->numskins;i++)
1079 pinskintype = (daliasskintype_t *)datapointer;
1080 datapointer += sizeof(daliasskintype_t);
1081 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
1085 pinskingroup = (daliasskingroup_t *)datapointer;
1086 datapointer += sizeof(daliasskingroup_t);
1087 groupskins = LittleLong(pinskingroup->numskins);
1088 datapointer += sizeof(daliasskininterval_t) * groupskins;
1091 for (j = 0;j < groupskins;j++)
1093 datapointer += skinwidth * skinheight;
1098 pinstverts = (stvert_t *)datapointer;
1099 datapointer += sizeof(stvert_t) * numverts;
1101 pintriangles = (dtriangle_t *)datapointer;
1102 datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
1104 startframes = datapointer;
1105 loadmodel->surfmesh.num_morphframes = 0;
1106 for (i = 0;i < loadmodel->numframes;i++)
1108 pinframetype = (daliasframetype_t *)datapointer;
1109 datapointer += sizeof(daliasframetype_t);
1110 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1114 pinframegroup = (daliasgroup_t *)datapointer;
1115 datapointer += sizeof(daliasgroup_t);
1116 groupframes = LittleLong(pinframegroup->numframes);
1117 datapointer += sizeof(daliasinterval_t) * groupframes;
1120 for (j = 0;j < groupframes;j++)
1122 datapointer += sizeof(daliasframe_t);
1123 datapointer += sizeof(trivertx_t) * numverts;
1124 loadmodel->surfmesh.num_morphframes++;
1127 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1129 // store texture coordinates into temporary array, they will be stored
1130 // after usage is determined (triangle data)
1131 vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1132 vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1133 vertonseam = vertremap + numverts * 2;
1135 scales = 1.0 / skinwidth;
1136 scalet = 1.0 / skinheight;
1137 for (i = 0;i < numverts;i++)
1139 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1140 vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales;
1141 vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet;
1142 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1143 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1146 // load triangle data
1147 loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1149 // read the triangle elements
1150 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1151 for (j = 0;j < 3;j++)
1152 loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1153 // validate (note numverts is used because this is the original data)
1154 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1155 // now butcher the elements according to vertonseam and tri->facesfront
1156 // and then compact the vertex set to remove duplicates
1157 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1158 if (!LittleLong(pintriangles[i].facesfront)) // backface
1159 for (j = 0;j < 3;j++)
1160 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1161 loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1163 // (this uses vertremap to count usage to save some memory)
1164 for (i = 0;i < numverts*2;i++)
1166 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1167 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1168 // build remapping table and compact array
1169 loadmodel->surfmesh.num_vertices = 0;
1170 for (i = 0;i < numverts*2;i++)
1174 vertremap[i] = loadmodel->surfmesh.num_vertices;
1175 vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1176 vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1177 loadmodel->surfmesh.num_vertices++;
1180 vertremap[i] = -1; // not used at all
1182 // remap the elements to the new vertex set
1183 for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1184 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1185 // store the texture coordinates
1186 loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1187 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1189 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1190 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1193 // generate ushort elements array if possible
1194 if (loadmodel->surfmesh.num_vertices <= 65536)
1195 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1196 if (loadmodel->surfmesh.data_element3s)
1197 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1198 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1201 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1202 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1203 if (r_enableshadowvolumes.integer)
1205 loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
1207 Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1208 if (loadmodel->surfmesh.data_neighbor3i)
1209 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1210 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1211 Mod_Alias_MorphMesh_CompileFrames();
1214 Mem_Free(vertremap);
1217 skinfiles = Mod_LoadSkinFiles();
1220 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1221 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1222 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1223 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1224 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1225 Mod_FreeSkinFiles(skinfiles);
1226 for (i = 0;i < loadmodel->numskins;i++)
1228 loadmodel->skinscenes[i].firstframe = i;
1229 loadmodel->skinscenes[i].framecount = 1;
1230 loadmodel->skinscenes[i].loop = true;
1231 loadmodel->skinscenes[i].framerate = 10;
1236 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1237 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1238 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1239 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1241 datapointer = startskins;
1242 for (i = 0;i < loadmodel->numskins;i++)
1244 pinskintype = (daliasskintype_t *)datapointer;
1245 datapointer += sizeof(daliasskintype_t);
1247 if (pinskintype->type == ALIAS_SKIN_SINGLE)
1254 pinskingroup = (daliasskingroup_t *)datapointer;
1255 datapointer += sizeof(daliasskingroup_t);
1257 groupskins = LittleLong (pinskingroup->numskins);
1259 pinskinintervals = (daliasskininterval_t *)datapointer;
1260 datapointer += sizeof(daliasskininterval_t) * groupskins;
1262 interval = LittleFloat(pinskinintervals[0].interval);
1263 if (interval < 0.01f)
1265 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1270 dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1271 loadmodel->skinscenes[i].firstframe = totalskins;
1272 loadmodel->skinscenes[i].framecount = groupskins;
1273 loadmodel->skinscenes[i].framerate = 1.0f / interval;
1274 loadmodel->skinscenes[i].loop = true;
1276 for (j = 0;j < groupskins;j++)
1279 dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1281 dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1282 if (!Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS))
1283 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, R_SkinFrame_LoadInternalQuake(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight));
1284 datapointer += skinwidth * skinheight;
1288 // check for skins that don't exist in the model, but do exist as external images
1289 // (this was added because yummyluv kept pestering me about support for it)
1290 // TODO: support shaders here?
1291 while ((tempskinframe = R_SkinFrame_LoadExternal(va(vabuf, sizeof(vabuf), "%s_%i", loadmodel->name, loadmodel->numskins), (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false)))
1293 // expand the arrays to make room
1294 tempskinscenes = loadmodel->skinscenes;
1295 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1296 memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1297 Mem_Free(tempskinscenes);
1299 tempaliasskins = loadmodel->data_textures;
1300 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1301 memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1302 Mem_Free(tempaliasskins);
1304 // store the info about the new skin
1305 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, tempskinframe);
1306 strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1307 loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1308 loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1309 loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1310 loadmodel->skinscenes[loadmodel->numskins].loop = true;
1312 //increase skin counts
1313 loadmodel->numskins++;
1316 // fix up the pointers since they are pointing at the old textures array
1317 // FIXME: this is a hack!
1318 for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1319 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1323 surface = loadmodel->data_surfaces;
1324 surface->texture = loadmodel->data_textures;
1325 surface->num_firsttriangle = 0;
1326 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1327 surface->num_firstvertex = 0;
1328 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1330 if(mod_alias_force_animated.string[0])
1331 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1333 if (!loadmodel->surfmesh.isanimated)
1335 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1336 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1337 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1338 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1339 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1340 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1343 // because shaders can do somewhat unexpected things, check for unusual features now
1344 for (i = 0;i < loadmodel->num_textures;i++)
1346 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1347 mod->DrawSky = R_Q1BSP_DrawSky;
1348 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1349 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1353 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
1355 int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1356 float iskinwidth, iskinheight;
1357 unsigned char *data;
1358 msurface_t *surface;
1360 unsigned char *base, *datapointer;
1361 md2frame_t *pinframe;
1363 md2triangle_t *intri;
1364 unsigned short *inst;
1365 struct md2verthash_s
1367 struct md2verthash_s *next;
1371 *hash, **md2verthash, *md2verthashdata;
1372 skinfile_t *skinfiles;
1374 pinmodel = (md2_t *)buffer;
1375 base = (unsigned char *)buffer;
1377 version = LittleLong (pinmodel->version);
1378 if (version != MD2ALIAS_VERSION)
1379 Host_Error ("%s has wrong version number (%i should be %i)",
1380 loadmodel->name, version, MD2ALIAS_VERSION);
1382 loadmodel->modeldatatypestring = "MD2";
1384 loadmodel->type = mod_alias;
1385 loadmodel->DrawSky = NULL;
1386 loadmodel->DrawAddWaterPlanes = NULL;
1387 loadmodel->Draw = R_Q1BSP_Draw;
1388 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1389 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1390 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1391 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1392 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1393 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1394 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1395 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1396 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1397 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1398 loadmodel->PointSuperContents = NULL;
1399 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1401 if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1402 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1403 if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1404 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1405 if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1406 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1407 if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1408 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1410 end = LittleLong(pinmodel->ofs_end);
1411 if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1412 Host_Error ("%s is not a valid model", loadmodel->name);
1413 if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1414 Host_Error ("%s is not a valid model", loadmodel->name);
1415 if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1416 Host_Error ("%s is not a valid model", loadmodel->name);
1417 if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1418 Host_Error ("%s is not a valid model", loadmodel->name);
1419 if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1420 Host_Error ("%s is not a valid model", loadmodel->name);
1422 loadmodel->numskins = LittleLong(pinmodel->num_skins);
1423 numxyz = LittleLong(pinmodel->num_xyz);
1424 numst = LittleLong(pinmodel->num_st);
1425 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1426 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1427 loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1428 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1429 skinwidth = LittleLong(pinmodel->skinwidth);
1430 skinheight = LittleLong(pinmodel->skinheight);
1431 iskinwidth = 1.0f / skinwidth;
1432 iskinheight = 1.0f / skinheight;
1434 loadmodel->num_surfaces = 1;
1435 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1436 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));
1437 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1438 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1439 loadmodel->sortedmodelsurfaces[0] = 0;
1440 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1441 loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1442 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1443 if (r_enableshadowvolumes.integer)
1445 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1448 loadmodel->synctype = ST_RAND;
1451 inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1452 skinfiles = Mod_LoadSkinFiles();
1455 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1456 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1457 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1458 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1459 Mod_FreeSkinFiles(skinfiles);
1461 else if (loadmodel->numskins)
1463 // skins found (most likely not a player model)
1464 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1465 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1466 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1467 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1468 Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
1472 // no skins (most likely a player model)
1473 loadmodel->numskins = 1;
1474 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1475 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1476 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1477 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL);
1480 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1481 for (i = 0;i < loadmodel->numskins;i++)
1483 loadmodel->skinscenes[i].firstframe = i;
1484 loadmodel->skinscenes[i].framecount = 1;
1485 loadmodel->skinscenes[i].loop = true;
1486 loadmodel->skinscenes[i].framerate = 10;
1489 // load the triangles and stvert data
1490 inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1491 intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1492 md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1493 md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1494 // swap the triangle list
1495 loadmodel->surfmesh.num_vertices = 0;
1496 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1498 for (j = 0;j < 3;j++)
1500 xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1501 st = (unsigned short) LittleShort (intri[i].index_st[j]);
1504 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1509 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1512 hashindex = (xyz * 256 + st) & 65535;
1513 for (hash = md2verthash[hashindex];hash;hash = hash->next)
1514 if (hash->xyz == xyz && hash->st == st)
1518 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1521 hash->next = md2verthash[hashindex];
1522 md2verthash[hashindex] = hash;
1524 loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1528 vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1529 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));
1530 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1531 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1532 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1535 hash = md2verthashdata + i;
1536 vertremap[i] = hash->xyz;
1537 sts = LittleShort(inst[hash->st*2+0]);
1538 stt = LittleShort(inst[hash->st*2+1]);
1539 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1541 Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1545 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1546 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1549 Mem_Free(md2verthash);
1550 Mem_Free(md2verthashdata);
1552 // generate ushort elements array if possible
1553 if (loadmodel->surfmesh.num_vertices <= 65536)
1554 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1555 if (loadmodel->surfmesh.data_element3s)
1556 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1557 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1560 datapointer = (base + LittleLong(pinmodel->ofs_frames));
1561 for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1566 pinframe = (md2frame_t *)datapointer;
1567 datapointer += sizeof(md2frame_t);
1568 // store the frame scale/translate into the appropriate array
1569 for (j = 0;j < 3;j++)
1571 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1572 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1574 // convert the vertices
1575 v = (trivertx_t *)datapointer;
1576 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1577 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1578 out[k] = v[vertremap[k]];
1579 datapointer += numxyz * sizeof(trivertx_t);
1581 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1582 loadmodel->animscenes[i].firstframe = i;
1583 loadmodel->animscenes[i].framecount = 1;
1584 loadmodel->animscenes[i].framerate = 10;
1585 loadmodel->animscenes[i].loop = true;
1588 Mem_Free(vertremap);
1590 if (loadmodel->surfmesh.data_neighbor3i)
1591 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1592 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1593 Mod_Alias_MorphMesh_CompileFrames();
1594 if(mod_alias_force_animated.string[0])
1595 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1597 surface = loadmodel->data_surfaces;
1598 surface->texture = loadmodel->data_textures;
1599 surface->num_firsttriangle = 0;
1600 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1601 surface->num_firstvertex = 0;
1602 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1604 if (!loadmodel->surfmesh.isanimated)
1606 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1607 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1608 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1609 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1610 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1611 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1614 // because shaders can do somewhat unexpected things, check for unusual features now
1615 for (i = 0;i < loadmodel->num_textures;i++)
1617 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1618 mod->DrawSky = R_Q1BSP_DrawSky;
1619 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1620 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1624 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
1626 int i, j, k, version, meshvertices, meshtriangles;
1627 unsigned char *data;
1628 msurface_t *surface;
1629 md3modelheader_t *pinmodel;
1630 md3frameinfo_t *pinframe;
1633 skinfile_t *skinfiles;
1635 pinmodel = (md3modelheader_t *)buffer;
1637 if (memcmp(pinmodel->identifier, "IDP3", 4))
1638 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1639 version = LittleLong (pinmodel->version);
1640 if (version != MD3VERSION)
1641 Host_Error ("%s has wrong version number (%i should be %i)",
1642 loadmodel->name, version, MD3VERSION);
1644 skinfiles = Mod_LoadSkinFiles();
1645 if (loadmodel->numskins < 1)
1646 loadmodel->numskins = 1;
1648 loadmodel->modeldatatypestring = "MD3";
1650 loadmodel->type = mod_alias;
1651 loadmodel->DrawSky = NULL;
1652 loadmodel->DrawAddWaterPlanes = NULL;
1653 loadmodel->Draw = R_Q1BSP_Draw;
1654 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1655 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1656 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1657 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1658 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1659 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1660 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1661 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1662 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1663 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1664 loadmodel->PointSuperContents = NULL;
1665 loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1666 loadmodel->synctype = ST_RAND;
1667 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1668 i = LittleLong (pinmodel->flags);
1669 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1671 // set up some global info about the model
1672 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1673 loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1675 // make skinscenes for the skins (no groups)
1676 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1677 for (i = 0;i < loadmodel->numskins;i++)
1679 loadmodel->skinscenes[i].firstframe = i;
1680 loadmodel->skinscenes[i].framecount = 1;
1681 loadmodel->skinscenes[i].loop = true;
1682 loadmodel->skinscenes[i].framerate = 10;
1686 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1687 for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1689 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1690 loadmodel->animscenes[i].firstframe = i;
1691 loadmodel->animscenes[i].framecount = 1;
1692 loadmodel->animscenes[i].framerate = 10;
1693 loadmodel->animscenes[i].loop = true;
1697 loadmodel->num_tagframes = loadmodel->numframes;
1698 loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1699 loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1700 for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1702 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1703 for (j = 0;j < 9;j++)
1704 loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1705 for (j = 0;j < 3;j++)
1706 loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1707 //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);
1713 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)))
1715 if (memcmp(pinmesh->identifier, "IDP3", 4))
1716 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1717 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1718 Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1719 meshvertices += LittleLong(pinmesh->num_vertices);
1720 meshtriangles += LittleLong(pinmesh->num_triangles);
1723 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1724 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1725 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1726 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));
1727 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1728 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1729 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1730 loadmodel->surfmesh.num_vertices = meshvertices;
1731 loadmodel->surfmesh.num_triangles = meshtriangles;
1732 loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1733 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1734 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1735 if (r_enableshadowvolumes.integer)
1737 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1739 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1740 loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1741 if (meshvertices <= 65536)
1743 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1748 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)))
1750 if (memcmp(pinmesh->identifier, "IDP3", 4))
1751 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1752 loadmodel->sortedmodelsurfaces[i] = i;
1753 surface = loadmodel->data_surfaces + i;
1754 surface->texture = loadmodel->data_textures + i;
1755 surface->num_firsttriangle = meshtriangles;
1756 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1757 surface->num_firstvertex = meshvertices;
1758 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1759 meshvertices += surface->num_vertices;
1760 meshtriangles += surface->num_triangles;
1762 for (j = 0;j < surface->num_triangles * 3;j++)
1763 loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1764 for (j = 0;j < surface->num_vertices;j++)
1766 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1767 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1769 for (j = 0;j < loadmodel->numframes;j++)
1771 const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1772 md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1773 for (k = 0;k < surface->num_vertices;k++, in++, out++)
1775 out->origin[0] = LittleShort(in->origin[0]);
1776 out->origin[1] = LittleShort(in->origin[1]);
1777 out->origin[2] = LittleShort(in->origin[2]);
1778 out->pitch = in->pitch;
1783 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1785 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1787 if (loadmodel->surfmesh.data_element3s)
1788 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1789 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1790 if (loadmodel->surfmesh.data_neighbor3i)
1791 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1792 Mod_Alias_MorphMesh_CompileFrames();
1793 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1794 Mod_FreeSkinFiles(skinfiles);
1795 Mod_MakeSortedSurfaces(loadmodel);
1796 if(mod_alias_force_animated.string[0])
1797 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1799 if (!loadmodel->surfmesh.isanimated)
1801 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1802 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1803 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1804 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1805 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1806 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1809 // because shaders can do somewhat unexpected things, check for unusual features now
1810 for (i = 0;i < loadmodel->num_textures;i++)
1812 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1813 mod->DrawSky = R_Q1BSP_DrawSky;
1814 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1815 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1819 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1821 zymtype1header_t *pinmodel, *pheader;
1822 unsigned char *pbase;
1823 int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1824 float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1825 zymvertex_t *verts, *vertdata;
1829 skinfile_t *skinfiles;
1830 unsigned char *data;
1831 msurface_t *surface;
1833 pinmodel = (zymtype1header_t *)buffer;
1834 pbase = (unsigned char *)buffer;
1835 if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1836 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1837 if (BigLong(pinmodel->type) != 1)
1838 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1840 loadmodel->modeldatatypestring = "ZYM";
1842 loadmodel->type = mod_alias;
1843 loadmodel->synctype = ST_RAND;
1847 pheader->type = BigLong(pinmodel->type);
1848 pheader->filesize = BigLong(pinmodel->filesize);
1849 pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1850 pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1851 pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1852 pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1853 pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1854 pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1855 pheader->radius = BigFloat(pinmodel->radius);
1856 pheader->numverts = BigLong(pinmodel->numverts);
1857 pheader->numtris = BigLong(pinmodel->numtris);
1858 pheader->numshaders = BigLong(pinmodel->numshaders);
1859 pheader->numbones = BigLong(pinmodel->numbones);
1860 pheader->numscenes = BigLong(pinmodel->numscenes);
1861 pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1862 pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1863 pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1864 pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1865 pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1866 pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1867 pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1868 pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1869 pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1870 pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1871 pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1872 pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1873 pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1874 pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1875 pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1876 pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1877 pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1878 pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1880 if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1882 Con_Printf("%s has no geometry\n", loadmodel->name);
1885 if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1887 Con_Printf("%s has no animations\n", loadmodel->name);
1891 loadmodel->DrawSky = NULL;
1892 loadmodel->DrawAddWaterPlanes = NULL;
1893 loadmodel->Draw = R_Q1BSP_Draw;
1894 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1895 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1896 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1897 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1898 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1899 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1900 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1901 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1902 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1903 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1904 loadmodel->PointSuperContents = NULL;
1905 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1907 loadmodel->numframes = pheader->numscenes;
1908 loadmodel->num_surfaces = pheader->numshaders;
1910 skinfiles = Mod_LoadSkinFiles();
1911 if (loadmodel->numskins < 1)
1912 loadmodel->numskins = 1;
1914 // make skinscenes for the skins (no groups)
1915 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1916 for (i = 0;i < loadmodel->numskins;i++)
1918 loadmodel->skinscenes[i].firstframe = i;
1919 loadmodel->skinscenes[i].framecount = 1;
1920 loadmodel->skinscenes[i].loop = true;
1921 loadmodel->skinscenes[i].framerate = 10;
1925 // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
1926 modelradius = pheader->radius;
1927 for (i = 0;i < 3;i++)
1929 loadmodel->normalmins[i] = pheader->mins[i];
1930 loadmodel->normalmaxs[i] = pheader->maxs[i];
1931 loadmodel->rotatedmins[i] = -modelradius;
1932 loadmodel->rotatedmaxs[i] = modelradius;
1934 corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1935 corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1936 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1937 if (loadmodel->yawmaxs[0] > modelradius)
1938 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1939 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1940 loadmodel->yawmins[2] = loadmodel->normalmins[2];
1941 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1942 loadmodel->radius = modelradius;
1943 loadmodel->radius2 = modelradius * modelradius;
1945 // go through the lumps, swapping things
1947 //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1948 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1949 scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1950 numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1951 for (i = 0;i < pheader->numscenes;i++)
1953 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1954 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1955 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1956 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1957 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1958 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1959 Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1960 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1961 Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1962 if (loadmodel->animscenes[i].framerate < 0)
1963 Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1967 //zymlump_t lump_bones; // zymbone_t bone[numbones];
1968 loadmodel->num_bones = pheader->numbones;
1969 loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1970 bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1971 for (i = 0;i < pheader->numbones;i++)
1973 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1974 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1975 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1976 if (loadmodel->data_bones[i].parent >= i)
1977 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1980 //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1981 vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1982 bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1983 for (i = 0;i < pheader->numverts;i++)
1985 vertbonecounts[i] = BigLong(bonecount[i]);
1986 if (vertbonecounts[i] != 1)
1987 Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1990 loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1992 meshvertices = pheader->numverts;
1993 meshtriangles = pheader->numtris;
1995 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1996 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1997 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1998 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]));
1999 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2000 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2001 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2002 loadmodel->surfmesh.num_vertices = meshvertices;
2003 loadmodel->surfmesh.num_triangles = meshtriangles;
2004 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2005 if (r_enableshadowvolumes.integer)
2007 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2009 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2010 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2011 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2012 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2013 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2014 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2015 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2016 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2017 loadmodel->surfmesh.num_blends = 0;
2018 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2019 if (loadmodel->surfmesh.num_vertices <= 65536)
2021 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2023 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2024 loadmodel->surfmesh.data_blendweights = NULL;
2026 //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
2027 poses = (float *) (pheader->lump_poses.start + pbase);
2028 // figure out scale of model from root bone, for compatibility with old zmodel versions
2029 tempvec[0] = BigFloat(poses[0]);
2030 tempvec[1] = BigFloat(poses[1]);
2031 tempvec[2] = BigFloat(poses[2]);
2032 modelscale = VectorLength(tempvec);
2034 for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
2036 f = fabs(BigFloat(poses[i]));
2037 biggestorigin = max(biggestorigin, f);
2039 loadmodel->num_posescale = biggestorigin / 32767.0f;
2040 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2041 for (i = 0;i < numposes;i++)
2043 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
2044 for (j = 0;j < loadmodel->num_bones;j++)
2047 matrix4x4_t posematrix;
2048 for (k = 0;k < 12;k++)
2049 pose[k] = BigFloat(frameposes[j*12+k]);
2050 //if (j < loadmodel->num_bones)
2051 // 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));
2052 // scale child bones to match the root scale
2053 if (loadmodel->data_bones[j].parent >= 0)
2055 pose[3] *= modelscale;
2056 pose[7] *= modelscale;
2057 pose[11] *= modelscale;
2059 // normalize rotation matrix
2060 VectorNormalize(pose + 0);
2061 VectorNormalize(pose + 4);
2062 VectorNormalize(pose + 8);
2063 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2064 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2068 //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2069 verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2070 vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2071 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2072 // (converting from weight-blending skeletal animation to
2073 // deformation-based skeletal animation)
2074 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2075 for (i = 0;i < loadmodel->num_bones;i++)
2078 for (k = 0;k < 12;k++)
2079 m[k] = BigFloat(poses[i*12+k]);
2080 if (loadmodel->data_bones[i].parent >= 0)
2081 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2083 for (k = 0;k < 12;k++)
2084 bonepose[12*i+k] = m[k];
2086 for (j = 0;j < pheader->numverts;j++)
2088 // this format really should have had a per vertexweight weight value...
2089 // but since it does not, the weighting is completely ignored and
2090 // only one weight is allowed per vertex
2091 int boneindex = BigLong(vertdata[j].bonenum);
2092 const float *m = bonepose + 12 * boneindex;
2093 float relativeorigin[3];
2094 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2095 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2096 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2097 // transform the vertex bone weight into the base mesh
2098 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2099 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2100 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2101 // store the weight as the primary weight on this vertex
2102 loadmodel->surfmesh.blends[j] = boneindex;
2103 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = boneindex;
2104 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2105 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2106 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2107 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = 255;
2108 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2109 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2110 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2113 // normals and tangents are calculated after elements are loaded
2115 //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2116 outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2117 intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2118 for (i = 0;i < pheader->numverts;i++)
2120 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2121 // flip T coordinate for OpenGL
2122 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2125 //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2126 //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2127 //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2129 //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2130 //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)
2131 // byteswap, validate, and swap winding order of tris
2132 count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2133 if (pheader->lump_render.length != count)
2134 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2135 renderlist = (int *) (pheader->lump_render.start + pbase);
2136 renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2138 for (i = 0;i < loadmodel->num_surfaces;i++)
2140 int firstvertex, lastvertex;
2141 if (renderlist >= renderlistend)
2142 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2143 count = BigLong(*renderlist);renderlist++;
2144 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2145 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2147 loadmodel->sortedmodelsurfaces[i] = i;
2148 surface = loadmodel->data_surfaces + i;
2149 surface->texture = loadmodel->data_textures + i;
2150 surface->num_firsttriangle = meshtriangles;
2151 surface->num_triangles = count;
2152 meshtriangles += surface->num_triangles;
2154 // load the elements
2155 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2156 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2158 outelements[j*3+2] = BigLong(renderlist[0]);
2159 outelements[j*3+1] = BigLong(renderlist[1]);
2160 outelements[j*3+0] = BigLong(renderlist[2]);
2162 // validate the elements and find the used vertex range
2163 firstvertex = meshvertices;
2165 for (j = 0;j < surface->num_triangles * 3;j++)
2167 if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2168 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2169 firstvertex = min(firstvertex, outelements[j]);
2170 lastvertex = max(lastvertex, outelements[j]);
2172 surface->num_firstvertex = firstvertex;
2173 surface->num_vertices = lastvertex + 1 - firstvertex;
2175 // since zym models do not have named sections, reuse their shader
2176 // name as the section name
2177 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2178 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2180 Mod_FreeSkinFiles(skinfiles);
2181 Mem_Free(vertbonecounts);
2183 Mod_MakeSortedSurfaces(loadmodel);
2185 // compute all the mesh information that was not loaded from the file
2186 if (loadmodel->surfmesh.data_element3s)
2187 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2188 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2189 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2190 Mod_BuildBaseBonePoses();
2191 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);
2192 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);
2193 if (loadmodel->surfmesh.data_neighbor3i)
2194 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2195 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2196 if(mod_alias_force_animated.string[0])
2197 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2199 if (!loadmodel->surfmesh.isanimated)
2201 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2202 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2203 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2204 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2205 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2206 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2209 // because shaders can do somewhat unexpected things, check for unusual features now
2210 for (i = 0;i < loadmodel->num_textures;i++)
2212 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2213 mod->DrawSky = R_Q1BSP_DrawSky;
2214 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2215 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2219 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2221 dpmheader_t *pheader;
2225 unsigned char *pbase;
2226 int i, j, k, meshvertices, meshtriangles;
2227 skinfile_t *skinfiles;
2228 unsigned char *data;
2230 float biggestorigin, tempvec[3], modelscale;
2234 pheader = (dpmheader_t *)buffer;
2235 pbase = (unsigned char *)buffer;
2236 if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2237 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2238 if (BigLong(pheader->type) != 2)
2239 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2241 loadmodel->modeldatatypestring = "DPM";
2243 loadmodel->type = mod_alias;
2244 loadmodel->synctype = ST_RAND;
2247 pheader->type = BigLong(pheader->type);
2248 pheader->filesize = BigLong(pheader->filesize);
2249 pheader->mins[0] = BigFloat(pheader->mins[0]);
2250 pheader->mins[1] = BigFloat(pheader->mins[1]);
2251 pheader->mins[2] = BigFloat(pheader->mins[2]);
2252 pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2253 pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2254 pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2255 pheader->yawradius = BigFloat(pheader->yawradius);
2256 pheader->allradius = BigFloat(pheader->allradius);
2257 pheader->num_bones = BigLong(pheader->num_bones);
2258 pheader->num_meshs = BigLong(pheader->num_meshs);
2259 pheader->num_frames = BigLong(pheader->num_frames);
2260 pheader->ofs_bones = BigLong(pheader->ofs_bones);
2261 pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2262 pheader->ofs_frames = BigLong(pheader->ofs_frames);
2264 if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2266 Con_Printf("%s has no geometry\n", loadmodel->name);
2269 if (pheader->num_frames < 1)
2271 Con_Printf("%s has no frames\n", loadmodel->name);
2275 loadmodel->DrawSky = NULL;
2276 loadmodel->DrawAddWaterPlanes = NULL;
2277 loadmodel->Draw = R_Q1BSP_Draw;
2278 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2279 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2280 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2281 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2282 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2283 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2284 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2285 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2286 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2287 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2288 loadmodel->PointSuperContents = NULL;
2289 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2292 // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2293 for (i = 0;i < 3;i++)
2295 loadmodel->normalmins[i] = pheader->mins[i];
2296 loadmodel->normalmaxs[i] = pheader->maxs[i];
2297 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2298 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2299 loadmodel->rotatedmins[i] = -pheader->allradius;
2300 loadmodel->rotatedmaxs[i] = pheader->allradius;
2302 loadmodel->radius = pheader->allradius;
2303 loadmodel->radius2 = pheader->allradius * pheader->allradius;
2305 // load external .skin files if present
2306 skinfiles = Mod_LoadSkinFiles();
2307 if (loadmodel->numskins < 1)
2308 loadmodel->numskins = 1;
2313 // gather combined statistics from the meshes
2314 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2315 for (i = 0;i < (int)pheader->num_meshs;i++)
2317 int numverts = BigLong(dpmmesh->num_verts);
2318 meshvertices += numverts;
2319 meshtriangles += BigLong(dpmmesh->num_tris);
2323 loadmodel->numframes = pheader->num_frames;
2324 loadmodel->num_bones = pheader->num_bones;
2325 loadmodel->num_poses = loadmodel->numframes;
2326 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
2327 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2328 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2329 // do most allocations as one merged chunk
2330 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));
2331 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2332 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2333 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2334 loadmodel->surfmesh.num_vertices = meshvertices;
2335 loadmodel->surfmesh.num_triangles = meshtriangles;
2336 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2337 if (r_enableshadowvolumes.integer)
2339 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2341 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2342 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2343 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2344 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2345 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2346 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2347 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2348 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2349 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2350 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2351 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2352 loadmodel->surfmesh.num_blends = 0;
2353 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2354 if (meshvertices <= 65536)
2356 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2358 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2359 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2361 for (i = 0;i < loadmodel->numskins;i++)
2363 loadmodel->skinscenes[i].firstframe = i;
2364 loadmodel->skinscenes[i].framecount = 1;
2365 loadmodel->skinscenes[i].loop = true;
2366 loadmodel->skinscenes[i].framerate = 10;
2369 // load the bone info
2370 bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2371 for (i = 0;i < loadmodel->num_bones;i++)
2373 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2374 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2375 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2376 if (loadmodel->data_bones[i].parent >= i)
2377 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2381 frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2382 // figure out scale of model from root bone, for compatibility with old dpmodel versions
2383 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2384 tempvec[0] = BigFloat(poses[0]);
2385 tempvec[1] = BigFloat(poses[1]);
2386 tempvec[2] = BigFloat(poses[2]);
2387 modelscale = VectorLength(tempvec);
2389 for (i = 0;i < loadmodel->numframes;i++)
2391 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2392 loadmodel->animscenes[i].firstframe = i;
2393 loadmodel->animscenes[i].framecount = 1;
2394 loadmodel->animscenes[i].loop = true;
2395 loadmodel->animscenes[i].framerate = 10;
2396 // load the bone poses for this frame
2397 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2398 for (j = 0;j < loadmodel->num_bones*12;j++)
2400 f = fabs(BigFloat(poses[j]));
2401 biggestorigin = max(biggestorigin, f);
2403 // stuff not processed here: mins, maxs, yawradius, allradius
2405 loadmodel->num_posescale = biggestorigin / 32767.0f;
2406 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2407 for (i = 0;i < loadmodel->numframes;i++)
2409 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2410 for (j = 0;j < loadmodel->num_bones;j++)
2413 matrix4x4_t posematrix;
2414 for (k = 0;k < 12;k++)
2415 pose[k] = BigFloat(frameposes[j*12+k]);
2416 // scale child bones to match the root scale
2417 if (loadmodel->data_bones[j].parent >= 0)
2419 pose[3] *= modelscale;
2420 pose[7] *= modelscale;
2421 pose[11] *= modelscale;
2423 // normalize rotation matrix
2424 VectorNormalize(pose + 0);
2425 VectorNormalize(pose + 4);
2426 VectorNormalize(pose + 8);
2427 Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2428 Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2432 // load the meshes now
2433 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2436 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2437 // (converting from weight-blending skeletal animation to
2438 // deformation-based skeletal animation)
2439 poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2440 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2441 for (i = 0;i < loadmodel->num_bones;i++)
2444 for (k = 0;k < 12;k++)
2445 m[k] = BigFloat(poses[i*12+k]);
2446 if (loadmodel->data_bones[i].parent >= 0)
2447 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2449 for (k = 0;k < 12;k++)
2450 bonepose[12*i+k] = m[k];
2452 for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2454 const int *inelements;
2456 const float *intexcoord;
2457 msurface_t *surface;
2459 loadmodel->sortedmodelsurfaces[i] = i;
2460 surface = loadmodel->data_surfaces + i;
2461 surface->texture = loadmodel->data_textures + i;
2462 surface->num_firsttriangle = meshtriangles;
2463 surface->num_triangles = BigLong(dpmmesh->num_tris);
2464 surface->num_firstvertex = meshvertices;
2465 surface->num_vertices = BigLong(dpmmesh->num_verts);
2466 meshvertices += surface->num_vertices;
2467 meshtriangles += surface->num_triangles;
2469 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2470 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2471 for (j = 0;j < surface->num_triangles;j++)
2473 // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2474 outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
2475 outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
2476 outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
2481 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2482 for (j = 0;j < surface->num_vertices*2;j++)
2483 loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2485 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2486 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2488 int weightindex[4] = { 0, 0, 0, 0 };
2489 float weightinfluence[4] = { 0, 0, 0, 0 };
2491 int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2492 data += sizeof(dpmvertex_t);
2493 for (k = 0;k < numweights;k++)
2495 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2496 int boneindex = BigLong(vert->bonenum);
2497 const float *m = bonepose + 12 * boneindex;
2498 float influence = BigFloat(vert->influence);
2499 float relativeorigin[3], relativenormal[3];
2500 relativeorigin[0] = BigFloat(vert->origin[0]);
2501 relativeorigin[1] = BigFloat(vert->origin[1]);
2502 relativeorigin[2] = BigFloat(vert->origin[2]);
2503 relativenormal[0] = BigFloat(vert->normal[0]);
2504 relativenormal[1] = BigFloat(vert->normal[1]);
2505 relativenormal[2] = BigFloat(vert->normal[2]);
2506 // blend the vertex bone weights into the base mesh
2507 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2508 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2509 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2510 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2511 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2512 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2515 // store the first (and often only) weight
2516 weightinfluence[0] = influence;
2517 weightindex[0] = boneindex;
2521 // sort the new weight into this vertex's weight table
2522 // (which only accepts up to 4 bones per vertex)
2523 for (l = 0;l < 4;l++)
2525 if (weightinfluence[l] < influence)
2527 // move weaker influence weights out of the way first
2529 for (l2 = 3;l2 > l;l2--)
2531 weightinfluence[l2] = weightinfluence[l2-1];
2532 weightindex[l2] = weightindex[l2-1];
2534 // store the new weight
2535 weightinfluence[l] = influence;
2536 weightindex[l] = boneindex;
2541 data += sizeof(dpmbonevert_t);
2543 loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2544 loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = weightindex[0];
2545 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2546 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2547 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2548 loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
2549 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2550 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2551 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2554 // since dpm models do not have named sections, reuse their shader name as the section name
2555 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2557 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2559 if (loadmodel->surfmesh.num_blends < meshvertices)
2560 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2562 Mod_FreeSkinFiles(skinfiles);
2563 Mod_MakeSortedSurfaces(loadmodel);
2565 // compute all the mesh information that was not loaded from the file
2566 if (loadmodel->surfmesh.data_element3s)
2567 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2568 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2569 Mod_BuildBaseBonePoses();
2570 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);
2571 if (loadmodel->surfmesh.data_neighbor3i)
2572 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2573 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2574 if(mod_alias_force_animated.string[0])
2575 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2577 if (!loadmodel->surfmesh.isanimated)
2579 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2580 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2581 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2582 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2583 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2584 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2587 // because shaders can do somewhat unexpected things, check for unusual features now
2588 for (i = 0;i < loadmodel->num_textures;i++)
2590 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2591 mod->DrawSky = R_Q1BSP_DrawSky;
2592 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2593 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2597 // no idea why PSK/PSA files contain weird quaternions but they do...
2598 #define PSKQUATNEGATIONS
2599 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2601 int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2602 int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2603 fs_offset_t filesize;
2608 pskboneinfo_t *bones;
2609 pskrawweights_t *rawweights;
2610 //pskboneinfo_t *animbones;
2611 pskaniminfo_t *anims;
2612 pskanimkeys_t *animkeys;
2613 void *animfilebuffer, *animbuffer, *animbufferend;
2614 unsigned char *data;
2616 skinfile_t *skinfiles;
2617 char animname[MAX_QPATH];
2619 float biggestorigin;
2621 pchunk = (pskchunk_t *)buffer;
2622 if (strcmp(pchunk->id, "ACTRHEAD"))
2623 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2625 loadmodel->modeldatatypestring = "PSK";
2627 loadmodel->type = mod_alias;
2628 loadmodel->DrawSky = NULL;
2629 loadmodel->DrawAddWaterPlanes = NULL;
2630 loadmodel->Draw = R_Q1BSP_Draw;
2631 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2632 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2633 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2634 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2635 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2636 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2637 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2638 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2639 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2640 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2641 loadmodel->PointSuperContents = NULL;
2642 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2643 loadmodel->synctype = ST_RAND;
2645 FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2646 strlcat(animname, ".psa", sizeof(animname));
2647 animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2648 animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2650 animbufferend = animbuffer;
2669 while (buffer < bufferend)
2671 pchunk = (pskchunk_t *)buffer;
2672 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2673 version = LittleLong(pchunk->version);
2674 recordsize = LittleLong(pchunk->recordsize);
2675 numrecords = LittleLong(pchunk->numrecords);
2676 if (developer_extra.integer)
2677 Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2678 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2679 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);
2680 if (!strcmp(pchunk->id, "ACTRHEAD"))
2684 else if (!strcmp(pchunk->id, "PNTS0000"))
2687 if (recordsize != sizeof(*p))
2688 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2689 // byteswap in place and keep the pointer
2690 numpnts = numrecords;
2691 pnts = (pskpnts_t *)buffer;
2692 for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2694 p->origin[0] = LittleFloat(p->origin[0]);
2695 p->origin[1] = LittleFloat(p->origin[1]);
2696 p->origin[2] = LittleFloat(p->origin[2]);
2700 else if (!strcmp(pchunk->id, "VTXW0000"))
2703 if (recordsize != sizeof(*p))
2704 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2705 // byteswap in place and keep the pointer
2706 numvtxw = numrecords;
2707 vtxw = (pskvtxw_t *)buffer;
2708 for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2710 p->pntsindex = LittleShort(p->pntsindex);
2711 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2712 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2713 if (p->pntsindex >= numpnts)
2715 Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2721 else if (!strcmp(pchunk->id, "FACE0000"))
2724 if (recordsize != sizeof(*p))
2725 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2726 // byteswap in place and keep the pointer
2727 numfaces = numrecords;
2728 faces = (pskface_t *)buffer;
2729 for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2731 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2732 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2733 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2734 p->group = LittleLong(p->group);
2735 if (p->vtxwindex[0] >= numvtxw)
2737 Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2738 p->vtxwindex[0] = 0;
2740 if (p->vtxwindex[1] >= numvtxw)
2742 Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2743 p->vtxwindex[1] = 0;
2745 if (p->vtxwindex[2] >= numvtxw)
2747 Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2748 p->vtxwindex[2] = 0;
2753 else if (!strcmp(pchunk->id, "MATT0000"))
2756 if (recordsize != sizeof(*p))
2757 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2758 // byteswap in place and keep the pointer
2759 nummatts = numrecords;
2760 matts = (pskmatt_t *)buffer;
2761 for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2767 else if (!strcmp(pchunk->id, "REFSKELT"))
2770 if (recordsize != sizeof(*p))
2771 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2772 // byteswap in place and keep the pointer
2773 numbones = numrecords;
2774 bones = (pskboneinfo_t *)buffer;
2775 for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2777 p->numchildren = LittleLong(p->numchildren);
2778 p->parent = LittleLong(p->parent);
2779 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2780 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2781 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2782 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2783 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2784 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2785 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2786 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2787 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2788 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2789 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2790 #ifdef PSKQUATNEGATIONS
2793 p->basepose.quat[0] *= -1;
2794 p->basepose.quat[1] *= -1;
2795 p->basepose.quat[2] *= -1;
2799 p->basepose.quat[0] *= 1;
2800 p->basepose.quat[1] *= -1;
2801 p->basepose.quat[2] *= 1;
2804 if (p->parent < 0 || p->parent >= numbones)
2806 Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2812 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2815 if (recordsize != sizeof(*p))
2816 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2817 // byteswap in place and keep the pointer
2818 numrawweights = numrecords;
2819 rawweights = (pskrawweights_t *)buffer;
2820 for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2822 p->weight = LittleFloat(p->weight);
2823 p->pntsindex = LittleLong(p->pntsindex);
2824 p->boneindex = LittleLong(p->boneindex);
2825 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2827 Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2830 if (p->boneindex < 0 || p->boneindex >= numbones)
2832 Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2840 while (animbuffer < animbufferend)
2842 pchunk = (pskchunk_t *)animbuffer;
2843 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2844 version = LittleLong(pchunk->version);
2845 recordsize = LittleLong(pchunk->recordsize);
2846 numrecords = LittleLong(pchunk->numrecords);
2847 if (developer_extra.integer)
2848 Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2849 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2850 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);
2851 if (!strcmp(pchunk->id, "ANIMHEAD"))
2855 else if (!strcmp(pchunk->id, "BONENAMES"))
2858 if (recordsize != sizeof(*p))
2859 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2860 // byteswap in place and keep the pointer
2861 numanimbones = numrecords;
2862 //animbones = (pskboneinfo_t *)animbuffer;
2863 // NOTE: supposedly psa does not need to match the psk model, the
2864 // bones missing from the psa would simply use their base
2865 // positions from the psk, but this is hard for me to implement
2866 // and people can easily make animations that match.
2867 if (numanimbones != numbones)
2868 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2869 for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2871 p->numchildren = LittleLong(p->numchildren);
2872 p->parent = LittleLong(p->parent);
2873 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2874 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2875 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2876 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2877 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2878 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2879 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2880 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2881 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2882 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2883 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2884 #ifdef PSKQUATNEGATIONS
2887 p->basepose.quat[0] *= -1;
2888 p->basepose.quat[1] *= -1;
2889 p->basepose.quat[2] *= -1;
2893 p->basepose.quat[0] *= 1;
2894 p->basepose.quat[1] *= -1;
2895 p->basepose.quat[2] *= 1;
2898 if (p->parent < 0 || p->parent >= numanimbones)
2900 Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2903 // check that bones are the same as in the base
2904 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2905 Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2909 else if (!strcmp(pchunk->id, "ANIMINFO"))
2912 if (recordsize != sizeof(*p))
2913 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2914 // byteswap in place and keep the pointer
2915 numanims = numrecords;
2916 anims = (pskaniminfo_t *)animbuffer;
2917 for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2919 p->numbones = LittleLong(p->numbones);
2920 p->playtime = LittleFloat(p->playtime);
2921 p->fps = LittleFloat(p->fps);
2922 p->firstframe = LittleLong(p->firstframe);
2923 p->numframes = LittleLong(p->numframes);
2924 if (p->numbones != numbones)
2925 Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2929 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2932 if (recordsize != sizeof(*p))
2933 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2934 numanimkeys = numrecords;
2935 animkeys = (pskanimkeys_t *)animbuffer;
2936 for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2938 p->origin[0] = LittleFloat(p->origin[0]);
2939 p->origin[1] = LittleFloat(p->origin[1]);
2940 p->origin[2] = LittleFloat(p->origin[2]);
2941 p->quat[0] = LittleFloat(p->quat[0]);
2942 p->quat[1] = LittleFloat(p->quat[1]);
2943 p->quat[2] = LittleFloat(p->quat[2]);
2944 p->quat[3] = LittleFloat(p->quat[3]);
2945 p->frametime = LittleFloat(p->frametime);
2946 #ifdef PSKQUATNEGATIONS
2947 if (index % numbones)
2962 // TODO: allocate bonepose stuff
2965 Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2968 if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2969 Host_Error("%s: missing required chunks", loadmodel->name);
2973 loadmodel->numframes = 0;
2974 for (index = 0;index < numanims;index++)
2975 loadmodel->numframes += anims[index].numframes;
2976 if (numanimkeys != numbones * loadmodel->numframes)
2977 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2980 loadmodel->numframes = loadmodel->num_poses = 1;
2982 meshvertices = numvtxw;
2983 meshtriangles = numfaces;
2985 // load external .skin files if present
2986 skinfiles = Mod_LoadSkinFiles();
2987 if (loadmodel->numskins < 1)
2988 loadmodel->numskins = 1;
2989 loadmodel->num_bones = numbones;
2990 loadmodel->num_poses = loadmodel->numframes;
2991 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2992 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2993 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2994 loadmodel->surfmesh.num_vertices = meshvertices;
2995 loadmodel->surfmesh.num_triangles = meshtriangles;
2996 // do most allocations as one merged chunk
2997 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);
2998 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2999 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3000 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3001 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3002 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
3003 if (r_enableshadowvolumes.integer)
3005 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
3007 loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3008 loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3009 loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3010 loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3011 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3012 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3013 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3014 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3015 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3016 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3017 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3018 loadmodel->surfmesh.num_blends = 0;
3019 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3020 if (loadmodel->surfmesh.num_vertices <= 65536)
3022 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
3024 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3025 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
3027 for (i = 0;i < loadmodel->numskins;i++)
3029 loadmodel->skinscenes[i].firstframe = i;
3030 loadmodel->skinscenes[i].framecount = 1;
3031 loadmodel->skinscenes[i].loop = true;
3032 loadmodel->skinscenes[i].framerate = 10;
3036 for (index = 0, i = 0;index < nummatts;index++)
3038 // since psk models do not have named sections, reuse their shader name as the section name
3039 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
3040 loadmodel->sortedmodelsurfaces[index] = index;
3041 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
3042 loadmodel->data_surfaces[index].num_firstvertex = 0;
3043 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
3046 // copy over the vertex locations and texcoords
3047 for (index = 0;index < numvtxw;index++)
3049 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
3050 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
3051 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
3052 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
3053 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
3056 // loading the faces is complicated because we need to sort them into surfaces by mattindex
3057 for (index = 0;index < numfaces;index++)
3058 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
3059 for (index = 0, i = 0;index < nummatts;index++)
3061 loadmodel->data_surfaces[index].num_firsttriangle = i;
3062 i += loadmodel->data_surfaces[index].num_triangles;
3063 loadmodel->data_surfaces[index].num_triangles = 0;
3065 for (index = 0;index < numfaces;index++)
3067 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
3068 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
3069 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
3070 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
3073 // copy over the bones
3074 for (index = 0;index < numbones;index++)
3076 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
3077 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
3078 if (loadmodel->data_bones[index].parent >= index)
3079 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
3082 // convert the basepose data
3083 if (loadmodel->num_bones)
3086 matrix4x4_t *basebonepose;
3087 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
3088 matrix4x4_t bonematrix;
3089 matrix4x4_t tempbonematrix;
3090 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
3091 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
3093 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]);
3094 if (loadmodel->data_bones[boneindex].parent >= 0)
3096 tempbonematrix = bonematrix;
3097 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3099 basebonepose[boneindex] = bonematrix;
3100 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3101 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3103 Mem_Free(basebonepose);
3106 // sort the psk point weights into the vertex weight tables
3107 // (which only accept up to 4 bones per vertex)
3108 for (index = 0;index < numvtxw;index++)
3110 int weightindex[4] = { 0, 0, 0, 0 };
3111 float weightinfluence[4] = { 0, 0, 0, 0 };
3113 for (j = 0;j < numrawweights;j++)
3115 if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3117 int boneindex = rawweights[j].boneindex;
3118 float influence = rawweights[j].weight;
3119 for (l = 0;l < 4;l++)
3121 if (weightinfluence[l] < influence)
3123 // move lower influence weights out of the way first
3125 for (l2 = 3;l2 > l;l2--)
3127 weightinfluence[l2] = weightinfluence[l2-1];
3128 weightindex[l2] = weightindex[l2-1];
3130 // store the new weight
3131 weightinfluence[l] = influence;
3132 weightindex[l] = boneindex;
3138 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3139 loadmodel->surfmesh.data_skeletalindex4ub[index*4 ] = weightindex[0];
3140 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3141 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3142 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3143 loadmodel->surfmesh.data_skeletalweight4ub[index*4 ] = (unsigned char)(weightinfluence[0]*255.0f);
3144 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3145 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3146 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3148 if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3149 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3151 // set up the animscenes based on the anims
3154 for (index = 0, i = 0;index < numanims;index++)
3156 for (j = 0;j < anims[index].numframes;j++, i++)
3158 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3159 loadmodel->animscenes[i].firstframe = i;
3160 loadmodel->animscenes[i].framecount = 1;
3161 loadmodel->animscenes[i].loop = true;
3162 loadmodel->animscenes[i].framerate = anims[index].fps;
3165 // calculate the scaling value for bone origins so they can be compressed to short
3167 for (index = 0;index < numanimkeys;index++)
3169 pskanimkeys_t *k = animkeys + index;
3170 biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3171 biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3172 biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3174 loadmodel->num_posescale = biggestorigin / 32767.0f;
3175 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3177 // load the poses from the animkeys
3178 for (index = 0;index < numanimkeys;index++)
3180 pskanimkeys_t *k = animkeys + index;
3182 Vector4Copy(k->quat, quat);
3184 Vector4Negate(quat, quat);
3185 Vector4Normalize2(quat, quat);
3186 // compress poses to the short[7] format for longterm storage
3187 loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3188 loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3189 loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3190 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3191 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3192 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3193 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3198 strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3199 loadmodel->animscenes[0].firstframe = 0;
3200 loadmodel->animscenes[0].framecount = 1;
3201 loadmodel->animscenes[0].loop = true;
3202 loadmodel->animscenes[0].framerate = 10;
3204 // calculate the scaling value for bone origins so they can be compressed to short
3206 for (index = 0;index < numbones;index++)
3208 pskboneinfo_t *p = bones + index;
3209 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3210 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3211 biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3213 loadmodel->num_posescale = biggestorigin / 32767.0f;
3214 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3216 // load the basepose as a frame
3217 for (index = 0;index < numbones;index++)
3219 pskboneinfo_t *p = bones + index;
3221 Vector4Copy(p->basepose.quat, quat);
3223 Vector4Negate(quat, quat);
3224 Vector4Normalize2(quat, quat);
3225 // compress poses to the short[7] format for longterm storage
3226 loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3227 loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3228 loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3229 loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3230 loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3231 loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3232 loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3236 Mod_FreeSkinFiles(skinfiles);
3238 Mem_Free(animfilebuffer);
3239 Mod_MakeSortedSurfaces(loadmodel);
3241 // compute all the mesh information that was not loaded from the file
3242 // TODO: honor smoothing groups somehow?
3243 if (loadmodel->surfmesh.data_element3s)
3244 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3245 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3246 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3247 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);
3248 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);
3249 if (loadmodel->surfmesh.data_neighbor3i)
3250 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
3251 loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3252 if(mod_alias_force_animated.string[0])
3253 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3255 if (!loadmodel->surfmesh.isanimated)
3257 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3258 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3259 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3260 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3261 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3262 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3265 // because shaders can do somewhat unexpected things, check for unusual features now
3266 for (i = 0;i < loadmodel->num_textures;i++)
3268 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3269 mod->DrawSky = R_Q1BSP_DrawSky;
3270 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3271 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
3275 void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
3277 unsigned char *data;
3279 const unsigned char *pbase, *pend;
3281 skinfile_t *skinfiles;
3282 int i, j, k, meshvertices, meshtriangles;
3283 float biggestorigin;
3284 const unsigned int *inelements;
3286 const int *inneighbors;
3288 float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3289 // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3290 const float *vnormal = NULL;
3291 const float *vposition = NULL;
3292 const float *vtangent = NULL;
3293 const float *vtexcoord = NULL;
3294 const float *vcolor4f = NULL;
3295 const unsigned char *vblendindexes = NULL;
3296 const unsigned char *vblendweights = NULL;
3297 const unsigned char *vcolor4ub = NULL;
3298 const unsigned short *framedata = NULL;
3299 // temporary memory allocations (because the data in the file may be misaligned)
3300 iqmanim_t *anims = NULL;
3301 iqmbounds_t *bounds = NULL;
3302 iqmjoint1_t *joint1 = NULL;
3303 iqmjoint_t *joint = NULL;
3304 iqmmesh_t *meshes = NULL;
3305 iqmpose1_t *pose1 = NULL;
3306 iqmpose_t *pose = NULL;
3307 iqmvertexarray_t *vas = NULL;
3309 pbase = (unsigned char *)buffer;
3310 pend = (unsigned char *)bufferend;
3312 if (pbase + sizeof(iqmheader_t) > pend)
3313 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3315 // copy struct (otherwise it may be misaligned)
3316 // LordHavoc: okay it's definitely not misaligned here, but for consistency...
3317 memcpy(&header, pbase, sizeof(iqmheader_t));
3319 if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3320 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3321 if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3322 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3324 loadmodel->modeldatatypestring = "IQM";
3326 loadmodel->type = mod_alias;
3327 loadmodel->synctype = ST_RAND;
3330 header.version = LittleLong(header.version);
3331 header.filesize = LittleLong(header.filesize);
3332 header.flags = LittleLong(header.flags);
3333 header.num_text = LittleLong(header.num_text);
3334 header.ofs_text = LittleLong(header.ofs_text);
3335 header.num_meshes = LittleLong(header.num_meshes);
3336 header.ofs_meshes = LittleLong(header.ofs_meshes);
3337 header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3338 header.num_vertexes = LittleLong(header.num_vertexes);
3339 header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3340 header.num_triangles = LittleLong(header.num_triangles);
3341 header.ofs_triangles = LittleLong(header.ofs_triangles);
3342 header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3343 header.num_joints = LittleLong(header.num_joints);
3344 header.ofs_joints = LittleLong(header.ofs_joints);
3345 header.num_poses = LittleLong(header.num_poses);
3346 header.ofs_poses = LittleLong(header.ofs_poses);
3347 header.num_anims = LittleLong(header.num_anims);
3348 header.ofs_anims = LittleLong(header.ofs_anims);
3349 header.num_frames = LittleLong(header.num_frames);
3350 header.num_framechannels = LittleLong(header.num_framechannels);
3351 header.ofs_frames = LittleLong(header.ofs_frames);
3352 header.ofs_bounds = LittleLong(header.ofs_bounds);
3353 header.num_comment = LittleLong(header.num_comment);
3354 header.ofs_comment = LittleLong(header.ofs_comment);
3355 header.num_extensions = LittleLong(header.num_extensions);
3356 header.ofs_extensions = LittleLong(header.ofs_extensions);
3358 if (header.version == 1)
3360 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3361 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3363 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3369 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3370 pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3372 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3376 if (pbase + header.ofs_text + header.num_text > pend ||
3377 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3378 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3379 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3380 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3381 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3382 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3383 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3384 pbase + header.ofs_comment + header.num_comment > pend)
3386 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3390 // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3391 if (header.num_vertexarrays)
3392 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3393 if (header.num_anims)
3394 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3395 if (header.ofs_bounds)
3396 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3397 if (header.num_meshes)
3398 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3400 for (i = 0;i < (int)header.num_vertexarrays;i++)
3402 iqmvertexarray_t va;
3404 va.type = LittleLong(vas[i].type);
3405 va.flags = LittleLong(vas[i].flags);
3406 va.format = LittleLong(vas[i].format);
3407 va.size = LittleLong(vas[i].size);
3408 va.offset = LittleLong(vas[i].offset);
3409 vsize = header.num_vertexes*va.size;
3412 case IQM_FLOAT: vsize *= sizeof(float); break;
3413 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3416 if (pbase + va.offset + vsize > pend)
3418 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3422 if (va.format == IQM_FLOAT && va.size == 3)
3423 vposition = (const float *)(pbase + va.offset);
3426 if (va.format == IQM_FLOAT && va.size == 2)
3427 vtexcoord = (const float *)(pbase + va.offset);
3430 if (va.format == IQM_FLOAT && va.size == 3)
3431 vnormal = (const float *)(pbase + va.offset);
3434 if (va.format == IQM_FLOAT && va.size == 4)
3435 vtangent = (const float *)(pbase + va.offset);
3437 case IQM_BLENDINDEXES:
3438 if (va.format == IQM_UBYTE && va.size == 4)
3439 vblendindexes = (const unsigned char *)(pbase + va.offset);
3441 case IQM_BLENDWEIGHTS:
3442 if (va.format == IQM_UBYTE && va.size == 4)
3443 vblendweights = (const unsigned char *)(pbase + va.offset);
3446 if (va.format == IQM_FLOAT && va.size == 4)
3447 vcolor4f = (const float *)(pbase + va.offset);
3448 if (va.format == IQM_UBYTE && va.size == 4)
3449 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3453 if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3455 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3459 text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3461 loadmodel->DrawSky = NULL;
3462 loadmodel->DrawAddWaterPlanes = NULL;
3463 loadmodel->Draw = R_Q1BSP_Draw;
3464 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
3465 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
3466 loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
3467 loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
3468 loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
3469 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
3470 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
3471 loadmodel->DrawLight = R_Q1BSP_DrawLight;
3472 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3473 loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3474 loadmodel->PointSuperContents = NULL;
3475 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3477 // load external .skin files if present
3478 skinfiles = Mod_LoadSkinFiles();
3479 if (loadmodel->numskins < 1)
3480 loadmodel->numskins = 1;
3482 loadmodel->numframes = max(header.num_anims, 1);
3483 loadmodel->num_bones = header.num_joints;
3484 loadmodel->num_poses = max(header.num_frames, 1);
3485 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header.num_meshes;
3486 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3487 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3489 meshvertices = header.num_vertexes;
3490 meshtriangles = header.num_triangles;
3492 // do most allocations as one merged chunk
3493 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));
3494 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3495 loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3496 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3497 loadmodel->surfmesh.num_vertices = meshvertices;
3498 loadmodel->surfmesh.num_triangles = meshtriangles;
3499 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3500 if (r_enableshadowvolumes.integer)
3502 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3504 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3505 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3506 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3507 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3508 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3509 if (vcolor4f || vcolor4ub)
3511 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]);
3513 if (vblendindexes && vblendweights)
3515 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3516 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3518 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3519 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3520 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3521 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3522 if (vblendindexes && vblendweights)
3524 loadmodel->surfmesh.num_blends = 0;
3525 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3527 if (meshvertices <= 65536)
3529 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3531 loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3532 if (vblendindexes && vblendweights)
3533 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3535 for (i = 0;i < loadmodel->numskins;i++)
3537 loadmodel->skinscenes[i].firstframe = i;
3538 loadmodel->skinscenes[i].framecount = 1;
3539 loadmodel->skinscenes[i].loop = true;
3540 loadmodel->skinscenes[i].framerate = 10;
3543 // load the bone info
3544 if (header.version == 1)
3546 iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3547 if (loadmodel->num_bones)
3548 joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3549 for (i = 0;i < loadmodel->num_bones;i++)
3551 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3552 joint1[i].name = LittleLong(injoint1[i].name);
3553 joint1[i].parent = LittleLong(injoint1[i].parent);
3554 for (j = 0;j < 3;j++)
3556 joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
3557 joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
3558 joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
3560 strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3561 loadmodel->data_bones[i].parent = joint1[i].parent;
3562 if (loadmodel->data_bones[i].parent >= i)
3563 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3564 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]);
3565 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3566 if (loadmodel->data_bones[i].parent >= 0)
3568 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3569 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3570 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3572 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3577 iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
3578 if (header.num_joints)
3579 joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3580 for (i = 0;i < loadmodel->num_bones;i++)
3582 matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3583 joint[i].name = LittleLong(injoint[i].name);
3584 joint[i].parent = LittleLong(injoint[i].parent);
3585 for (j = 0;j < 3;j++)
3587 joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
3588 joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
3589 joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
3591 joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
3592 strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3593 loadmodel->data_bones[i].parent = joint[i].parent;
3594 if (loadmodel->data_bones[i].parent >= i)
3595 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3596 if (joint[i].rotation[3] > 0)
3597 Vector4Negate(joint[i].rotation, joint[i].rotation);
3598 Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3599 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]);
3600 Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3601 if (loadmodel->data_bones[i].parent >= 0)
3603 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3604 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3605 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3607 else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3611 // set up the animscenes based on the anims
3612 for (i = 0;i < (int)header.num_anims;i++)
3615 anim.name = LittleLong(anims[i].name);
3616 anim.first_frame = LittleLong(anims[i].first_frame);
3617 anim.num_frames = LittleLong(anims[i].num_frames);
3618 anim.framerate = LittleFloat(anims[i].framerate);
3619 anim.flags = LittleLong(anims[i].flags);
3620 strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3621 loadmodel->animscenes[i].firstframe = anim.first_frame;
3622 loadmodel->animscenes[i].framecount = anim.num_frames;
3623 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3624 loadmodel->animscenes[i].framerate = anim.framerate;
3626 if (header.num_anims <= 0)
3628 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3629 loadmodel->animscenes[0].firstframe = 0;
3630 loadmodel->animscenes[0].framecount = 1;
3631 loadmodel->animscenes[0].loop = true;
3632 loadmodel->animscenes[0].framerate = 10;
3635 loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3636 if(mod_alias_force_animated.string[0])
3637 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3640 if (header.version == 1)
3642 iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3643 if (header.num_poses)
3644 pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3645 for (i = 0;i < (int)header.num_poses;i++)
3648 pose1[i].parent = LittleLong(inpose1[i].parent);
3649 pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
3650 for (j = 0;j < 9;j++)
3652 pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
3653 pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
3655 f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3656 f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3657 f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3658 f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3659 f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3660 f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3662 if (header.num_frames <= 0)
3664 for (i = 0;i < loadmodel->num_bones;i++)
3667 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3668 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3669 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3675 iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
3676 if (header.num_poses)
3677 pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3678 for (i = 0;i < (int)header.num_poses;i++)
3681 pose[i].parent = LittleLong(inpose[i].parent);
3682 pose[i].channelmask = LittleLong(inpose[i].channelmask);
3683 for (j = 0;j < 10;j++)
3685 pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
3686 pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
3688 f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3689 f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3690 f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3691 f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3692 f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3693 f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3695 if (header.num_frames <= 0)
3697 for (i = 0;i < loadmodel->num_bones;i++)
3700 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3701 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3702 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3706 loadmodel->num_posescale = biggestorigin / 32767.0f;
3707 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3709 // load the pose data
3710 // this unaligned memory access is safe (LittleShort reads as bytes)
3711 framedata = (const unsigned short *)(pbase + header.ofs_frames);
3712 if (header.version == 1)
3714 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3716 for (j = 0;j < (int)header.num_poses;j++, k++)
3718 float qx, qy, qz, qw;
3719 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));
3720 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));
3721 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));
3722 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3723 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3724 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3725 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3726 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3727 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3728 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3729 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3730 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3731 // skip scale data for now
3732 if(pose1[j].channelmask&64) framedata++;
3733 if(pose1[j].channelmask&128) framedata++;
3734 if(pose1[j].channelmask&256) framedata++;
3737 if (header.num_frames <= 0)
3739 for (i = 0;i < loadmodel->num_bones;i++)
3741 float qx, qy, qz, qw;
3742 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3743 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3744 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3745 qx = joint1[i].rotation[0];
3746 qy = joint1[i].rotation[1];
3747 qz = joint1[i].rotation[2];
3748 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3749 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3750 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3751 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3752 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3753 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3759 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3761 for (j = 0;j < (int)header.num_poses;j++, k++)
3764 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));
3765 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));
3766 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));
3767 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3768 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3769 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3770 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3772 Vector4Negate(rot, rot);
3773 Vector4Normalize2(rot, rot);
3774 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3775 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3776 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3777 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3778 // skip scale data for now
3779 if(pose[j].channelmask&128) framedata++;
3780 if(pose[j].channelmask&256) framedata++;
3781 if(pose[j].channelmask&512) framedata++;
3784 if (header.num_frames <= 0)
3786 for (i = 0;i < loadmodel->num_bones;i++)
3788 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3789 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3790 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3791 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3792 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3793 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3794 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3799 // load bounding box data
3800 if (header.ofs_bounds)
3802 float xyradius = 0, radius = 0;
3803 VectorClear(loadmodel->normalmins);
3804 VectorClear(loadmodel->normalmaxs);
3805 for (i = 0; i < (int)header.num_frames;i++)
3808 bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3809 bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3810 bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3811 bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);
3812 bound.maxs[1] = LittleFloat(bounds[i].maxs[1]);
3813 bound.maxs[2] = LittleFloat(bounds[i].maxs[2]);
3814 bound.xyradius = LittleFloat(bounds[i].xyradius);
3815 bound.radius = LittleFloat(bounds[i].radius);
3818 VectorCopy(bound.mins, loadmodel->normalmins);
3819 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3823 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3824 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3825 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3826 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3827 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3828 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3830 if (bound.xyradius > xyradius)
3831 xyradius = bound.xyradius;
3832 if (bound.radius > radius)
3833 radius = bound.radius;
3835 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3836 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3837 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3838 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3839 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3840 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3841 loadmodel->radius = radius;
3842 loadmodel->radius2 = radius * radius;
3845 // load triangle data
3846 // this unaligned memory access is safe (LittleLong reads as bytes)
3847 inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3848 outelements = loadmodel->surfmesh.data_element3i;
3849 for (i = 0;i < (int)header.num_triangles;i++)
3851 outelements[0] = LittleLong(inelements[0]);
3852 outelements[1] = LittleLong(inelements[1]);
3853 outelements[2] = LittleLong(inelements[2]);
3857 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3859 if (header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
3861 // this unaligned memory access is safe (LittleLong reads as bytes)
3862 inneighbors = (const int *)(pbase + header.ofs_neighbors);
3863 outneighbors = loadmodel->surfmesh.data_neighbor3i;
3864 for (i = 0;i < (int)header.num_triangles;i++)
3866 outneighbors[0] = LittleLong(inneighbors[0]);
3867 outneighbors[1] = LittleLong(inneighbors[1]);
3868 outneighbors[2] = LittleLong(inneighbors[2]);
3875 // this unaligned memory access is safe (LittleFloat reads as bytes)
3876 outvertex = loadmodel->surfmesh.data_vertex3f;
3877 for (i = 0;i < (int)header.num_vertexes;i++)
3879 outvertex[0] = LittleFloat(vposition[0]);
3880 outvertex[1] = LittleFloat(vposition[1]);
3881 outvertex[2] = LittleFloat(vposition[2]);
3886 outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3887 // this unaligned memory access is safe (LittleFloat reads as bytes)
3888 for (i = 0;i < (int)header.num_vertexes;i++)
3890 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3891 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3896 // this unaligned memory access is safe (LittleFloat reads as bytes)
3899 outnormal = loadmodel->surfmesh.data_normal3f;
3900 for (i = 0;i < (int)header.num_vertexes;i++)
3902 outnormal[0] = LittleFloat(vnormal[0]);
3903 outnormal[1] = LittleFloat(vnormal[1]);
3904 outnormal[2] = LittleFloat(vnormal[2]);
3910 // this unaligned memory access is safe (LittleFloat reads as bytes)
3911 if(vnormal && vtangent)
3913 outnormal = loadmodel->surfmesh.data_normal3f;
3914 outsvector = loadmodel->surfmesh.data_svector3f;
3915 outtvector = loadmodel->surfmesh.data_tvector3f;
3916 for (i = 0;i < (int)header.num_vertexes;i++)
3918 outsvector[0] = LittleFloat(vtangent[0]);
3919 outsvector[1] = LittleFloat(vtangent[1]);
3920 outsvector[2] = LittleFloat(vtangent[2]);
3921 if(LittleFloat(vtangent[3]) < 0)
3922 CrossProduct(outsvector, outnormal, outtvector);
3924 CrossProduct(outnormal, outsvector, outtvector);
3932 // this unaligned memory access is safe (all bytes)
3933 if (vblendindexes && vblendweights)
3935 for (i = 0; i < (int)header.num_vertexes;i++)
3937 blendweights_t weights;
3938 memcpy(weights.index, vblendindexes + i*4, 4);
3939 memcpy(weights.influence, vblendweights + i*4, 4);
3940 loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3941 loadmodel->surfmesh.data_skeletalindex4ub[i*4 ] = weights.index[0];
3942 loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3943 loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3944 loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3945 loadmodel->surfmesh.data_skeletalweight4ub[i*4 ] = weights.influence[0];
3946 loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3947 loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3948 loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3954 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3955 // this unaligned memory access is safe (LittleFloat reads as bytes)
3956 for (i = 0;i < (int)header.num_vertexes;i++)
3958 outcolor[0] = LittleFloat(vcolor4f[0]);
3959 outcolor[1] = LittleFloat(vcolor4f[1]);
3960 outcolor[2] = LittleFloat(vcolor4f[2]);
3961 outcolor[3] = LittleFloat(vcolor4f[3]);
3968 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3969 // this unaligned memory access is safe (all bytes)
3970 for (i = 0;i < (int)header.num_vertexes;i++)
3972 outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3973 outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3974 outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3975 outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3982 for (i = 0;i < (int)header.num_meshes;i++)
3985 msurface_t *surface;
3987 mesh.name = LittleLong(meshes[i].name);
3988 mesh.material = LittleLong(meshes[i].material);
3989 mesh.first_vertex = LittleLong(meshes[i].first_vertex);
3990 mesh.num_vertexes = LittleLong(meshes[i].num_vertexes);
3991 mesh.first_triangle = LittleLong(meshes[i].first_triangle);
3992 mesh.num_triangles = LittleLong(meshes[i].num_triangles);
3994 loadmodel->sortedmodelsurfaces[i] = i;
3995 surface = loadmodel->data_surfaces + i;
3996 surface->texture = loadmodel->data_textures + i;
3997 surface->num_firsttriangle = mesh.first_triangle;
3998 surface->num_triangles = mesh.num_triangles;
3999 surface->num_firstvertex = mesh.first_vertex;
4000 surface->num_vertices = mesh.num_vertexes;
4002 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
4005 Mod_FreeSkinFiles(skinfiles);
4006 Mod_MakeSortedSurfaces(loadmodel);
4008 // compute all the mesh information that was not loaded from the file
4009 if (loadmodel->surfmesh.data_element3s)
4010 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
4011 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
4013 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);
4014 if (!vnormal || !vtangent)
4015 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);
4016 if (!header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
4017 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
4018 if (!header.ofs_bounds)
4019 Mod_Alias_CalculateBoundingBox();
4021 if (!loadmodel->surfmesh.isanimated && loadmodel->surfmesh.num_triangles >= 1)
4023 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
4024 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
4025 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
4026 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
4027 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
4028 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
4031 if (joint ) Mem_Free(joint );joint = NULL;
4032 if (joint1 ) Mem_Free(joint1 );joint1 = NULL;
4033 if (pose ) Mem_Free(pose );pose = NULL;
4034 if (pose1 ) Mem_Free(pose1 );pose1 = NULL;
4036 // because shaders can do somewhat unexpected things, check for unusual features now
4037 for (i = 0;i < loadmodel->num_textures;i++)
4039 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
4040 mod->DrawSky = R_Q1BSP_DrawSky;
4041 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
4042 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;