]> git.xonotic.org Git - xonotic/darkplaces.git/blob - model_alias.c
cl_main: Keep old CL_Disconnect for simplicity. Move guts to CL_DisconnectEx
[xonotic/darkplaces.git] / model_alias.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
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.
8
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.
12
13 See the GNU General Public License for more details.
14
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.
18
19 */
20
21 #include "quakedef.h"
22 #include "image.h"
23 #include "r_shadow.h"
24 #include "mod_skeletal_animatevertices_generic.h"
25 #ifdef SSE_POSSIBLE
26 #include "mod_skeletal_animatevertices_sse.h"
27 #endif
28
29 #ifdef SSE_POSSIBLE
30 static qbool r_skeletal_use_sse_defined = false;
31 cvar_t r_skeletal_use_sse = {CF_CLIENT, "r_skeletal_use_sse", "1", "use SSE for skeletal model animation"};
32 #endif
33 cvar_t r_skeletal_debugbone = {CF_CLIENT, "r_skeletal_debugbone", "-1", "development cvar for testing skeletal model code"};
34 cvar_t r_skeletal_debugbonecomponent = {CF_CLIENT, "r_skeletal_debugbonecomponent", "3", "development cvar for testing skeletal model code"};
35 cvar_t r_skeletal_debugbonevalue = {CF_CLIENT, "r_skeletal_debugbonevalue", "100", "development cvar for testing skeletal model code"};
36 cvar_t r_skeletal_debugtranslatex = {CF_CLIENT, "r_skeletal_debugtranslatex", "1", "development cvar for testing skeletal model code"};
37 cvar_t r_skeletal_debugtranslatey = {CF_CLIENT, "r_skeletal_debugtranslatey", "1", "development cvar for testing skeletal model code"};
38 cvar_t r_skeletal_debugtranslatez = {CF_CLIENT, "r_skeletal_debugtranslatez", "1", "development cvar for testing skeletal model code"};
39 cvar_t mod_alias_supporttagscale = {CF_CLIENT | CF_SERVER, "mod_alias_supporttagscale", "1", "support scaling factors in bone/tag attachment matrices as supported by MD3"};
40 cvar_t mod_alias_force_animated = {CF_CLIENT | CF_SERVER, "mod_alias_force_animated", "", "if set to an non-empty string, overrides the is-animated flag of any alias models (for benchmarking)"};
41
42 float mod_md3_sin[320];
43
44 static size_t Mod_Skeletal_AnimateVertices_maxbonepose = 0;
45 static void *Mod_Skeletal_AnimateVertices_bonepose = NULL;
46 void Mod_Skeletal_FreeBuffers(void)
47 {
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;
52 }
53 void *Mod_Skeletal_AnimateVertices_AllocBuffers(size_t nbytes)
54 {
55         if(Mod_Skeletal_AnimateVertices_maxbonepose < nbytes)
56         {
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;
61         }
62         return Mod_Skeletal_AnimateVertices_bonepose;
63 }
64
65 void Mod_Skeletal_BuildTransforms(const model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT bonepose, float * RESTRICT boneposerelative)
66 {
67         int i, blends;
68         float m[12];
69
70         if (!bonepose)
71                 bonepose = (float * RESTRICT) Mod_Skeletal_AnimateVertices_AllocBuffers(sizeof(float[12]) * model->num_bones);
72                 
73         if (skeleton && !skeleton->relativetransforms)
74                 skeleton = NULL;
75
76         // interpolate matrices
77         if (skeleton)
78         {
79                 for (i = 0;i < model->num_bones;i++)
80                 {
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);
84                         else
85                                 memcpy(bonepose + i * 12, m, sizeof(m));
86
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);
90                 }
91         }
92         else
93         {
94                 for (i = 0;i < model->num_bones;i++)
95                 {
96                         // blend by transform each quaternion/translation into a dual-quaternion first, then blending
97                         const short * RESTRICT firstpose7s = model->data_poses7s + 7 * (frameblend[0].subframe * model->num_bones + i);
98                         float firstlerp = frameblend[0].lerp,
99                                 firsttx = firstpose7s[0], firstty = firstpose7s[1], firsttz = firstpose7s[2],
100                                 rx = firstpose7s[3] * firstlerp,
101                                 ry = firstpose7s[4] * firstlerp,
102                                 rz = firstpose7s[5] * firstlerp,
103                                 rw = firstpose7s[6] * firstlerp,
104                                 dx = firsttx*rw + firstty*rz - firsttz*ry,
105                                 dy = -firsttx*rz + firstty*rw + firsttz*rx,
106                                 dz = firsttx*ry - firstty*rx + firsttz*rw,
107                                 dw = -firsttx*rx - firstty*ry - firsttz*rz,
108                                 scale, sx, sy, sz, sw;
109                         for (blends = 1;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
110                         {
111                                 const short * RESTRICT blendpose7s = model->data_poses7s + 7 * (frameblend[blends].subframe * model->num_bones + i);
112                                 float blendlerp = frameblend[blends].lerp,
113                                         blendtx = blendpose7s[0], blendty = blendpose7s[1], blendtz = blendpose7s[2],
114                                         qx = blendpose7s[3], qy = blendpose7s[4], qz = blendpose7s[5], qw = blendpose7s[6];
115                                 if(rx*qx + ry*qy + rz*qz + rw*qw < 0) blendlerp = -blendlerp;
116                                 qx *= blendlerp;
117                                 qy *= blendlerp;
118                                 qz *= blendlerp;
119                                 qw *= blendlerp;
120                                 rx += qx;
121                                 ry += qy;
122                                 rz += qz;
123                                 rw += qw;
124                                 dx += blendtx*qw + blendty*qz - blendtz*qy;
125                                 dy += -blendtx*qz + blendty*qw + blendtz*qx;
126                                 dz += blendtx*qy - blendty*qx + blendtz*qw;
127                                 dw += -blendtx*qx - blendty*qy - blendtz*qz;
128                         }
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);
131                         sx = rx * scale;
132                         sy = ry * scale;
133                         sz = rz * scale;
134                         sw = rw * scale;
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);
154                         else
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);
159                 }
160         }
161 }
162
163 static void Mod_Skeletal_AnimateVertices(const 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)
164 {
165
166         if (!model->surfmesh.num_vertices)
167                 return;
168
169         if (!model->num_bones)
170         {
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]));
175                 return;
176         }
177
178 #ifdef SSE_POSSIBLE
179         if(r_skeletal_use_sse_defined)
180                 if(r_skeletal_use_sse.integer)
181                 {
182                         Mod_Skeletal_AnimateVertices_SSE(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f);
183                         return;
184                 }
185 #endif
186         Mod_Skeletal_AnimateVertices_Generic(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f);
187 }
188
189 void Mod_AliasInit (void)
190 {
191         int i;
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);
202 #ifdef SSE_POSSIBLE
203         if(Sys_HaveSSE())
204         {
205                 Con_Printf("Skeletal animation uses SSE code path\n");
206                 r_skeletal_use_sse_defined = true;
207                 Cvar_RegisterVariable(&r_skeletal_use_sse);
208         }
209         else
210                 Con_Printf("Skeletal animation uses generic code path (SSE disabled or not detected)\n");
211 #else
212         Con_Printf("Skeletal animation uses generic code path (SSE not compiled in)\n");
213 #endif
214 }
215
216 static int Mod_Skeletal_AddBlend(model_t *model, const blendweights_t *newweights)
217 {
218         int i;
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++)
224         {
225                 if (!memcmp(weights, newweights, sizeof(blendweights_t)))
226                         return model->num_bones + i;
227         }
228         model->surfmesh.num_blends++;
229         memcpy(weights, newweights, sizeof(blendweights_t));
230         return model->num_bones + i;
231 }
232
233 static int Mod_Skeletal_CompressBlend(model_t *model, const int *newindex, const float *newinfluence)
234 {
235         int i, total;
236         float scale;
237         blendweights_t newweights;
238         if(!newinfluence[1])
239                 return newindex[0];
240         scale = 0;
241         for (i = 0;i < 4;i++)
242                 scale += newinfluence[i];
243         scale = 255.0f / scale;
244         total = 0;
245         for (i = 0;i < 4;i++)
246         {
247                 newweights.index[i] = newindex[i];
248                 newweights.influence[i] = (unsigned char)(newinfluence[i] * scale);
249                 total += newweights.influence[i];
250         }       
251         while (total > 255)
252         {
253                 for (i = 0;i < 4;i++)
254                 {
255                         if(newweights.influence[i] > 0 && total > 255) 
256                         { 
257                                 newweights.influence[i]--;
258                                 total--; 
259                         }
260                 }
261         }
262         while (total < 255)
263         {
264                 for (i = 0; i < 4;i++)
265                 {
266                         if(newweights.influence[i] < 255 && total < 255) 
267                         { 
268                                 newweights.influence[i]++; 
269                                 total++; 
270                         }
271                 }
272         }
273         return Mod_Skeletal_AddBlend(model, &newweights);
274 }
275
276 static void Mod_MD3_AnimateVertices(const 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)
277 {
278         // vertex morph
279         int i, numblends, blendnum;
280         int numverts = model->surfmesh.num_vertices;
281         numblends = 0;
282         for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
283         {
284                 //VectorMA(translate, model->surfmesh.num_morphmdlframetranslate, frameblend[blendnum].lerp, translate);
285                 if (frameblend[blendnum].lerp > 0)
286                         numblends = blendnum + 1;
287         }
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++)
290         {
291                 const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].subframe;
292                 if (vertex3f)
293                 {
294                         float scale = frameblend[blendnum].lerp * (1.0f / 64.0f);
295                         if (blendnum == 0)
296                         {
297                                 for (i = 0;i < numverts;i++)
298                                 {
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;
302                                 }
303                         }
304                         else
305                         {
306                                 for (i = 0;i < numverts;i++)
307                                 {
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;
311                                 }
312                         }
313                 }
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.
319                 if (normal3f)
320                 {
321                         float lerp = frameblend[blendnum].lerp;
322                         if (blendnum == 0)
323                         {
324                                 for (i = 0;i < numverts;i++)
325                                 {
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;
329                                 }
330                         }
331                         else
332                         {
333                                 for (i = 0;i < numverts;i++)
334                                 {
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;
338                                 }
339                         }
340                 }
341                 if (svector3f)
342                 {
343                         const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
344                         float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
345                         if (blendnum == 0)
346                         {
347                                 for (i = 0;i < numverts;i++, texvecvert++)
348                                 {
349                                         VectorScale(texvecvert->svec, f, svector3f + i*3);
350                                         VectorScale(texvecvert->tvec, f, tvector3f + i*3);
351                                 }
352                         }
353                         else
354                         {
355                                 for (i = 0;i < numverts;i++, texvecvert++)
356                                 {
357                                         VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
358                                         VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
359                                 }
360                         }
361                 }
362         }
363 }
364 static void Mod_MDL_AnimateVertices(const 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)
365 {
366         // vertex morph
367         int i, numblends, blendnum;
368         int numverts = model->surfmesh.num_vertices;
369         float translate[3];
370         VectorClear(translate);
371         numblends = 0;
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++)
375         {
376                 if (model->surfmesh.data_morphmd2framesize6f)
377                         VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6 + 3, translate);
378                 else
379                         VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.num_morphmdlframetranslate, translate);
380                 if (frameblend[blendnum].lerp > 0)
381                         numblends = blendnum + 1;
382         }
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++)
385         {
386                 const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].subframe;
387                 if (vertex3f)
388                 {
389                         float scale[3];
390                         if (model->surfmesh.data_morphmd2framesize6f)
391                                 VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6, frameblend[blendnum].lerp, scale);
392                         else
393                                 VectorScale(model->surfmesh.num_morphmdlframescale, frameblend[blendnum].lerp, scale);
394                         if (blendnum == 0)
395                         {
396                                 for (i = 0;i < numverts;i++)
397                                 {
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];
401                                 }
402                         }
403                         else
404                         {
405                                 for (i = 0;i < numverts;i++)
406                                 {
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];
410                                 }
411                         }
412                 }
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
417                 if (normal3f)
418                 {
419                         float lerp = frameblend[blendnum].lerp;
420                         if (blendnum == 0)
421                         {
422                                 for (i = 0;i < numverts;i++)
423                                 {
424                                         const float *vn = m_bytenormals[verts[i].lightnormalindex];
425                                         VectorScale(vn, lerp, normal3f + i*3);
426                                 }
427                         }
428                         else
429                         {
430                                 for (i = 0;i < numverts;i++)
431                                 {
432                                         const float *vn = m_bytenormals[verts[i].lightnormalindex];
433                                         VectorMA(normal3f + i*3, lerp, vn, normal3f + i*3);
434                                 }
435                         }
436                 }
437                 if (svector3f)
438                 {
439                         const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
440                         float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
441                         if (blendnum == 0)
442                         {
443                                 for (i = 0;i < numverts;i++, texvecvert++)
444                                 {
445                                         VectorScale(texvecvert->svec, f, svector3f + i*3);
446                                         VectorScale(texvecvert->tvec, f, tvector3f + i*3);
447                                 }
448                         }
449                         else
450                         {
451                                 for (i = 0;i < numverts;i++, texvecvert++)
452                                 {
453                                         VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
454                                         VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
455                                 }
456                         }
457                 }
458         }
459 }
460
461 int Mod_Alias_GetTagMatrix(const model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, matrix4x4_t *outmatrix)
462 {
463         matrix4x4_t temp;
464         matrix4x4_t parentbonematrix;
465         matrix4x4_t tempbonematrix;
466         matrix4x4_t bonematrix;
467         matrix4x4_t blendmatrix;
468         int blendindex;
469         int parenttagindex;
470         int k;
471         float lerp;
472         const float *input;
473         float blendtag[12];
474         *outmatrix = identitymatrix;
475         if (skeleton && skeleton->relativetransforms)
476         {
477                 if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
478                         return 4;
479                 *outmatrix = skeleton->relativetransforms[tagindex];
480                 while ((tagindex = model->data_bones[tagindex].parent) >= 0)
481                 {
482                         temp = *outmatrix;
483                         Matrix4x4_Concat(outmatrix, &skeleton->relativetransforms[tagindex], &temp);
484                 }
485         }
486         else if (model->num_bones)
487         {
488                 if (tagindex < 0 || tagindex >= model->num_bones)
489                         return 4;
490                 Matrix4x4_Clear(&blendmatrix);
491                 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
492                 {
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)
497                         {
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);
501                         }
502                         Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
503                 }
504                 *outmatrix = blendmatrix;
505         }
506         else if (model->num_tags)
507         {
508                 if (tagindex < 0 || tagindex >= model->num_tags)
509                         return 4;
510                 for (k = 0;k < 12;k++)
511                         blendtag[k] = 0;
512                 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
513                 {
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;
518                 }
519                 Matrix4x4_FromArray12FloatGL(outmatrix, blendtag);
520         }
521
522         if(!mod_alias_supporttagscale.integer)
523                 Matrix4x4_Normalize3(outmatrix, outmatrix);
524
525         return 0;
526 }
527
528 int Mod_Alias_GetExtendedTagInfoForIndex(const 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)
529 {
530         int blendindex;
531         int k;
532         float lerp;
533         matrix4x4_t bonematrix;
534         matrix4x4_t blendmatrix;
535         const float *input;
536         float blendtag[12];
537
538         if (skeleton && skeleton->relativetransforms)
539         {
540                 if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
541                         return 1;
542                 *parentindex = skeleton->model->data_bones[tagindex].parent;
543                 *tagname = skeleton->model->data_bones[tagindex].name;
544                 *tag_localmatrix = skeleton->relativetransforms[tagindex];
545                 return 0;
546         }
547         else if (model->num_bones)
548         {
549                 if (tagindex < 0 || tagindex >= model->num_bones)
550                         return 1;
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++)
555                 {
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);
559                 }
560                 *tag_localmatrix = blendmatrix;
561                 return 0;
562         }
563         else if (model->num_tags)
564         {
565                 if (tagindex < 0 || tagindex >= model->num_tags)
566                         return 1;
567                 *parentindex = -1;
568                 *tagname = model->data_tags[tagindex].name;
569                 for (k = 0;k < 12;k++)
570                         blendtag[k] = 0;
571                 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
572                 {
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;
577                 }
578                 Matrix4x4_FromArray12FloatGL(tag_localmatrix, blendtag);
579                 return 0;
580         }
581
582         return 2;
583 }
584
585 int Mod_Alias_GetTagIndexForName(const model_t *model, unsigned int skin, const char *tagname)
586 {
587         int i;
588         if(skin >= (unsigned int)model->numskins)
589                 skin = 0;
590         if (model->num_bones)
591                 for (i = 0;i < model->num_bones;i++)
592                         if (!strcasecmp(tagname, model->data_bones[i].name))
593                                 return i + 1;
594         if (model->num_tags)
595                 for (i = 0;i < model->num_tags;i++)
596                         if (!strcasecmp(tagname, model->data_tags[i].name))
597                                 return i + 1;
598         return 0;
599 }
600
601 static void Mod_BuildBaseBonePoses(void)
602 {
603         int boneindex;
604         matrix4x4_t *basebonepose;
605         float *outinvmatrix = loadmodel->data_baseboneposeinverse;
606         matrix4x4_t bonematrix;
607         matrix4x4_t tempbonematrix;
608         if (!loadmodel->num_bones)
609                 return;
610         basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
611         for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
612         {
613                 Matrix4x4_FromBonePose7s(&bonematrix, loadmodel->num_posescale, loadmodel->data_poses7s + 7 * boneindex);
614                 if (loadmodel->data_bones[boneindex].parent >= 0)
615                 {
616                         tempbonematrix = bonematrix;
617                         Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
618                 }
619                 basebonepose[boneindex] = bonematrix;
620                 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
621                 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
622         }
623         Mem_Free(basebonepose);
624 }
625
626 static qbool Mod_Alias_CalculateBoundingBox(void)
627 {
628         int vnum;
629         qbool firstvertex = true;
630         float dist, yawradius, radius;
631         float *v;
632         qbool isanimated = false;
633         VectorClear(loadmodel->normalmins);
634         VectorClear(loadmodel->normalmaxs);
635         yawradius = 0;
636         radius = 0;
637         if (loadmodel->AnimateVertices)
638         {
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);
644                 refvertex3f = NULL;
645                 for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++)
646                 {
647                         loadmodel->AnimateVertices(loadmodel, frameblend, NULL, vertex3f, NULL, NULL, NULL);
648                         if (!refvertex3f)
649                         {
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]));
653                         }
654                         else
655                         {
656                                 if (!isanimated && memcmp(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3])))
657                                         isanimated = true;
658                         }
659                         for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
660                         {
661                                 if (firstvertex)
662                                 {
663                                         firstvertex = false;
664                                         VectorCopy(v, loadmodel->normalmins);
665                                         VectorCopy(v, loadmodel->normalmaxs);
666                                 }
667                                 else
668                                 {
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];
675                                 }
676                                 dist = v[0] * v[0] + v[1] * v[1];
677                                 if (yawradius < dist)
678                                         yawradius = dist;
679                                 dist += v[2] * v[2];
680                                 if (radius < dist)
681                                         radius = dist;
682                         }
683                 }
684                 if (vertex3f)
685                         Mem_Free(vertex3f);
686         }
687         else
688         {
689                 for (vnum = 0, v = loadmodel->surfmesh.data_vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
690                 {
691                         if (firstvertex)
692                         {
693                                 firstvertex = false;
694                                 VectorCopy(v, loadmodel->normalmins);
695                                 VectorCopy(v, loadmodel->normalmaxs);
696                         }
697                         else
698                         {
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];
705                         }
706                         dist = v[0] * v[0] + v[1] * v[1];
707                         if (yawradius < dist)
708                                 yawradius = dist;
709                         dist += v[2] * v[2];
710                         if (radius < dist)
711                                 radius = dist;
712                 }
713         }
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;
724         return isanimated;
725 }
726
727 static void Mod_Alias_MorphMesh_CompileFrames(void)
728 {
729         int i, j;
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--)
742         {
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++)
748                 {
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);
751                 }
752         }
753 }
754
755 static void Mod_MDLMD2MD3_TraceLine(model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
756 {
757         int i;
758         float segmentmins[3], segmentmaxs[3];
759         msurface_t *surface;
760         float vertex3fbuf[1024 * 3];
761         float *vertex3f = vertex3fbuf;
762         float *freevertex3f = NULL;
763         // for static cases we can just call CollisionBIH which is much faster
764         if ((frameblend == NULL || (frameblend[0].subframe == 0 && frameblend[1].lerp == 0)) && (skeleton == NULL || skeleton->relativetransforms == NULL))
765         {
766                 Mod_CollisionBIH_TraceLine(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
767                 return;
768         }
769         memset(trace, 0, sizeof(*trace));
770         trace->fraction = 1;
771         trace->hitsupercontentsmask = hitsupercontentsmask;
772         trace->skipsupercontentsmask = skipsupercontentsmask;
773         trace->skipmaterialflagsmask = skipmaterialflagsmask;
774         segmentmins[0] = min(start[0], end[0]) - 1;
775         segmentmins[1] = min(start[1], end[1]) - 1;
776         segmentmins[2] = min(start[2], end[2]) - 1;
777         segmentmaxs[0] = max(start[0], end[0]) + 1;
778         segmentmaxs[1] = max(start[1], end[1]) + 1;
779         segmentmaxs[2] = max(start[2], end[2]) + 1;
780         if (frameblend == NULL || frameblend[0].subframe != 0 || frameblend[0].lerp != 0 || skeleton != NULL)
781         {
782                 if (model->surfmesh.num_vertices > 1024)
783                         vertex3f = freevertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
784                 model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
785         }
786         else
787                 vertex3f = model->surfmesh.data_vertex3f;
788         for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
789                 Collision_TraceLineTriangleMeshFloat(trace, start, end, surface->num_triangles, model->surfmesh.data_element3i + 3 * surface->num_firsttriangle, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
790         if (freevertex3f)
791                 Mem_Free(freevertex3f);
792 }
793
794 static void Mod_MDLMD2MD3_TraceBox(model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
795 {
796         int i;
797         vec3_t shiftstart, shiftend;
798         float segmentmins[3], segmentmaxs[3];
799         msurface_t *surface;
800         float vertex3fbuf[1024*3];
801         float *vertex3f = vertex3fbuf;
802         colboxbrushf_t thisbrush_start, thisbrush_end;
803         vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
804
805         if (VectorCompare(boxmins, boxmaxs))
806         {
807                 VectorAdd(start, boxmins, shiftstart);
808                 VectorAdd(end, boxmins, shiftend);
809                 Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
810                 VectorSubtract(trace->endpos, boxmins, trace->endpos);
811                 return;
812         }
813
814         // for static cases we can just call CollisionBIH which is much faster
815         if ((frameblend == NULL || (frameblend[0].subframe == 0 && frameblend[1].lerp == 0)) && (skeleton == NULL || skeleton->relativetransforms == NULL))
816         {
817                 Mod_CollisionBIH_TraceBox(model, frameblend, skeleton, trace, start, boxmins, boxmaxs, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
818                 return;
819         }
820
821         // box trace, performed as brush trace
822         memset(trace, 0, sizeof(*trace));
823         trace->fraction = 1;
824         trace->hitsupercontentsmask = hitsupercontentsmask;
825         trace->skipsupercontentsmask = skipsupercontentsmask;
826         trace->skipmaterialflagsmask = skipmaterialflagsmask;
827         if (model->surfmesh.num_vertices > 1024)
828                 vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
829         segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1;
830         segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1;
831         segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1;
832         segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1;
833         segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1;
834         segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1;
835         VectorAdd(start, boxmins, boxstartmins);
836         VectorAdd(start, boxmaxs, boxstartmaxs);
837         VectorAdd(end, boxmins, boxendmins);
838         VectorAdd(end, boxmaxs, boxendmaxs);
839         Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL);
840         Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL);
841         model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
842         for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
843                 Collision_TraceBrushTriangleMeshFloat(trace, &thisbrush_start.brush, &thisbrush_end.brush, surface->num_triangles, model->surfmesh.data_element3i + 3 * surface->num_firsttriangle, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
844         if (vertex3f != vertex3fbuf)
845                 Mem_Free(vertex3f);
846 }
847
848 static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap)
849 {
850         int i, j;
851         for (i = 0;i < inverts;i++)
852         {
853                 if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
854                         continue;
855                 j = vertremap[i]; // not onseam
856                 if (j >= 0)
857                         out[j] = v[i];
858                 j = vertremap[i+inverts]; // onseam
859                 if (j >= 0)
860                         out[j] = v[i];
861         }
862 }
863
864 static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *vertremap)
865 {
866         int i, f, pose, groupframes;
867         float interval;
868         daliasframetype_t *pframetype;
869         daliasframe_t *pinframe;
870         daliasgroup_t *group;
871         daliasinterval_t *intervals;
872         animscene_t *scene;
873         pose = 0;
874         scene = loadmodel->animscenes;
875         for (f = 0;f < loadmodel->numframes;f++)
876         {
877                 pframetype = (daliasframetype_t *)datapointer;
878                 datapointer += sizeof(daliasframetype_t);
879                 if (LittleLong (pframetype->type) == ALIAS_SINGLE)
880                 {
881                         // a single frame is still treated as a group
882                         interval = 0.1f;
883                         groupframes = 1;
884                 }
885                 else
886                 {
887                         // read group header
888                         group = (daliasgroup_t *)datapointer;
889                         datapointer += sizeof(daliasgroup_t);
890                         groupframes = LittleLong (group->numframes);
891
892                         // intervals (time per frame)
893                         intervals = (daliasinterval_t *)datapointer;
894                         datapointer += sizeof(daliasinterval_t) * groupframes;
895
896                         interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
897                         if (interval < 0.01f)
898                         {
899                                 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
900                                 interval = 0.1f;
901                         }
902                 }
903
904                 // get scene name from first frame
905                 pinframe = (daliasframe_t *)datapointer;
906
907                 strlcpy(scene->name, pinframe->name, sizeof(scene->name));
908                 scene->firstframe = pose;
909                 scene->framecount = groupframes;
910                 scene->framerate = 1.0f / interval;
911                 scene->loop = true;
912                 scene++;
913
914                 // read frames
915                 for (i = 0;i < groupframes;i++)
916                 {
917                         datapointer += sizeof(daliasframe_t);
918                         Mod_ConvertAliasVerts(inverts, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphmdlvertex + pose * loadmodel->surfmesh.num_vertices, vertremap);
919                         datapointer += sizeof(trivertx_t) * inverts;
920                         pose++;
921                 }
922         }
923 }
924
925 void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
926 {
927         int i;
928         char stripbuf[MAX_QPATH];
929         skinfileitem_t *skinfileitem;
930         if(developer_extra.integer)
931                 Con_DPrintf("Looking up texture for %s (default: %s)\n", meshname, shadername);
932         if (skinfile)
933         {
934                 // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
935                 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
936                 {
937                         memset(skin, 0, sizeof(*skin));
938                         // see if a mesh
939                         for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
940                         {
941                                 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
942                                 if (!strcmp(skinfileitem->name, meshname))
943                                 {
944                                         Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf));
945                                         if(developer_extra.integer)
946                                                 Con_DPrintf("--> got %s from skin file\n", stripbuf);
947                                         Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
948                                         break;
949                                 }
950                         }
951                         if (!skinfileitem)
952                         {
953                                 // don't render unmentioned meshes
954                                 Mod_LoadCustomMaterial(loadmodel->mempool, skin, meshname, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing());
955                                 if(developer_extra.integer)
956                                         Con_DPrintf("--> skipping\n");
957                                 skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW;
958                         }
959                 }
960         }
961         else
962         {
963                 if(developer_extra.integer)
964                         Con_DPrintf("--> using default\n");
965                 Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf));
966                 Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
967         }
968 }
969 extern cvar_t r_nolerp_list;
970 #define BOUNDI(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%d exceeds %d - %d)", loadmodel->name, VALUE, MIN, MAX);
971 #define BOUNDF(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%f exceeds %f - %f)", loadmodel->name, VALUE, MIN, MAX);
972 void Mod_IDP0_Load(model_t *mod, void *buffer, void *bufferend)
973 {
974         int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
975         float scales, scalet, interval;
976         msurface_t *surface;
977         unsigned char *data;
978         mdl_t *pinmodel;
979         stvert_t *pinstverts;
980         dtriangle_t *pintriangles;
981         daliasskintype_t *pinskintype;
982         daliasskingroup_t *pinskingroup;
983         daliasskininterval_t *pinskinintervals;
984         daliasframetype_t *pinframetype;
985         daliasgroup_t *pinframegroup;
986         unsigned char *datapointer, *startframes, *startskins;
987         char name[MAX_QPATH];
988         skinframe_t *tempskinframe;
989         animscene_t *tempskinscenes;
990         texture_t *tempaliasskins;
991         float *vertst;
992         int *vertonseam, *vertremap;
993         skinfile_t *skinfiles;
994
995         datapointer = (unsigned char *)buffer;
996         pinmodel = (mdl_t *)datapointer;
997         datapointer += sizeof(mdl_t);
998
999         version = LittleLong (pinmodel->version);
1000         if (version != ALIAS_VERSION)
1001                 Host_Error ("%s has wrong version number (%i should be %i)",
1002                                  loadmodel->name, version, ALIAS_VERSION);
1003
1004         loadmodel->modeldatatypestring = "MDL";
1005
1006         loadmodel->type = mod_alias;
1007         loadmodel->Draw = R_Mod_Draw;
1008         loadmodel->DrawDepth = R_Mod_DrawDepth;
1009         loadmodel->DrawDebug = R_Mod_DrawDebug;
1010         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1011         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1012         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1013         loadmodel->DrawLight = R_Mod_DrawLight;
1014         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1015         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1016         // FIXME add TraceBrush!
1017         loadmodel->PointSuperContents = NULL;
1018         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1019
1020         loadmodel->num_surfaces = 1;
1021         loadmodel->submodelsurfaces_start = 0;
1022         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1023         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
1024         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1025         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1026         loadmodel->modelsurfaces_sorted[0] = 0;
1027
1028         loadmodel->numskins = LittleLong(pinmodel->numskins);
1029         BOUNDI(loadmodel->numskins,0,65536);
1030         skinwidth = LittleLong (pinmodel->skinwidth);
1031         BOUNDI(skinwidth,0,65536);
1032         skinheight = LittleLong (pinmodel->skinheight);
1033         BOUNDI(skinheight,0,65536);
1034         numverts = LittleLong(pinmodel->numverts);
1035         BOUNDI(numverts,0,65536);
1036         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
1037         BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
1038         loadmodel->numframes = LittleLong(pinmodel->numframes);
1039         BOUNDI(loadmodel->numframes,0,65536);
1040         loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
1041         BOUNDI((int)loadmodel->synctype,0,2);
1042         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1043         i = LittleLong (pinmodel->flags);
1044         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1045
1046         if (strstr(r_nolerp_list.string, loadmodel->name))
1047                 loadmodel->nolerp = true;
1048
1049         for (i = 0;i < 3;i++)
1050         {
1051                 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
1052                 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
1053         }
1054
1055         startskins = datapointer;
1056         totalskins = 0;
1057         for (i = 0;i < loadmodel->numskins;i++)
1058         {
1059                 pinskintype = (daliasskintype_t *)datapointer;
1060                 datapointer += sizeof(daliasskintype_t);
1061                 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
1062                         groupskins = 1;
1063                 else
1064                 {
1065                         pinskingroup = (daliasskingroup_t *)datapointer;
1066                         datapointer += sizeof(daliasskingroup_t);
1067                         groupskins = LittleLong(pinskingroup->numskins);
1068                         datapointer += sizeof(daliasskininterval_t) * groupskins;
1069                 }
1070
1071                 for (j = 0;j < groupskins;j++)
1072                 {
1073                         datapointer += skinwidth * skinheight;
1074                         totalskins++;
1075                 }
1076         }
1077
1078         pinstverts = (stvert_t *)datapointer;
1079         datapointer += sizeof(stvert_t) * numverts;
1080
1081         pintriangles = (dtriangle_t *)datapointer;
1082         datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
1083
1084         startframes = datapointer;
1085         loadmodel->surfmesh.num_morphframes = 0;
1086         for (i = 0;i < loadmodel->numframes;i++)
1087         {
1088                 pinframetype = (daliasframetype_t *)datapointer;
1089                 datapointer += sizeof(daliasframetype_t);
1090                 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1091                         groupframes = 1;
1092                 else
1093                 {
1094                         pinframegroup = (daliasgroup_t *)datapointer;
1095                         datapointer += sizeof(daliasgroup_t);
1096                         groupframes = LittleLong(pinframegroup->numframes);
1097                         datapointer += sizeof(daliasinterval_t) * groupframes;
1098                 }
1099
1100                 for (j = 0;j < groupframes;j++)
1101                 {
1102                         datapointer += sizeof(daliasframe_t);
1103                         datapointer += sizeof(trivertx_t) * numverts;
1104                         loadmodel->surfmesh.num_morphframes++;
1105                 }
1106         }
1107         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1108
1109         // store texture coordinates into temporary array, they will be stored
1110         // after usage is determined (triangle data)
1111         vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1112         vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1113         vertonseam = vertremap + numverts * 2;
1114
1115         scales = 1.0 / skinwidth;
1116         scalet = 1.0 / skinheight;
1117         for (i = 0;i < numverts;i++)
1118         {
1119                 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1120                 vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales;
1121                 vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet;
1122                 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1123                 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1124         }
1125
1126 // load triangle data
1127         loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1128
1129         // read the triangle elements
1130         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1131                 for (j = 0;j < 3;j++)
1132                         loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1133         // validate (note numverts is used because this is the original data)
1134         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, NULL, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1135         // now butcher the elements according to vertonseam and tri->facesfront
1136         // and then compact the vertex set to remove duplicates
1137         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1138                 if (!LittleLong(pintriangles[i].facesfront)) // backface
1139                         for (j = 0;j < 3;j++)
1140                                 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1141                                         loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1142         // count the usage
1143         // (this uses vertremap to count usage to save some memory)
1144         for (i = 0;i < numverts*2;i++)
1145                 vertremap[i] = 0;
1146         for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1147                 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1148         // build remapping table and compact array
1149         loadmodel->surfmesh.num_vertices = 0;
1150         for (i = 0;i < numverts*2;i++)
1151         {
1152                 if (vertremap[i])
1153                 {
1154                         vertremap[i] = loadmodel->surfmesh.num_vertices;
1155                         vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1156                         vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1157                         loadmodel->surfmesh.num_vertices++;
1158                 }
1159                 else
1160                         vertremap[i] = -1; // not used at all
1161         }
1162         // remap the elements to the new vertex set
1163         for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1164                 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1165         // store the texture coordinates
1166         loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1167         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1168         {
1169                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1170                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1171         }
1172
1173         // generate ushort elements array if possible
1174         if (loadmodel->surfmesh.num_vertices <= 65536)
1175                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1176         if (loadmodel->surfmesh.data_element3s)
1177                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1178                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1179
1180 // load the frames
1181         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1182         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1183         Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1184         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1185         Mod_Alias_MorphMesh_CompileFrames();
1186
1187         Mem_Free(vertst);
1188         Mem_Free(vertremap);
1189
1190         // load the skins
1191         skinfiles = Mod_LoadSkinFiles();
1192         if (skinfiles)
1193         {
1194                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1195                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1196                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1197                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1198                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1199                 Mod_FreeSkinFiles(skinfiles);
1200                 for (i = 0;i < loadmodel->numskins;i++)
1201                 {
1202                         loadmodel->skinscenes[i].firstframe = i;
1203                         loadmodel->skinscenes[i].framecount = 1;
1204                         loadmodel->skinscenes[i].loop = true;
1205                         loadmodel->skinscenes[i].framerate = 10;
1206                 }
1207         }
1208         else
1209         {
1210                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1211                 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1212                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1213                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1214                 totalskins = 0;
1215                 datapointer = startskins;
1216                 for (i = 0;i < loadmodel->numskins;i++)
1217                 {
1218                         pinskintype = (daliasskintype_t *)datapointer;
1219                         datapointer += sizeof(daliasskintype_t);
1220
1221                         if (pinskintype->type == ALIAS_SKIN_SINGLE)
1222                         {
1223                                 groupskins = 1;
1224                                 interval = 0.1f;
1225                         }
1226                         else
1227                         {
1228                                 pinskingroup = (daliasskingroup_t *)datapointer;
1229                                 datapointer += sizeof(daliasskingroup_t);
1230
1231                                 groupskins = LittleLong (pinskingroup->numskins);
1232
1233                                 pinskinintervals = (daliasskininterval_t *)datapointer;
1234                                 datapointer += sizeof(daliasskininterval_t) * groupskins;
1235
1236                                 interval = LittleFloat(pinskinintervals[0].interval);
1237                                 if (interval < 0.01f)
1238                                 {
1239                                         Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1240                                         interval = 0.1f;
1241                                 }
1242                         }
1243
1244                         dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1245                         loadmodel->skinscenes[i].firstframe = totalskins;
1246                         loadmodel->skinscenes[i].framecount = groupskins;
1247                         loadmodel->skinscenes[i].framerate = 1.0f / interval;
1248                         loadmodel->skinscenes[i].loop = true;
1249
1250                         for (j = 0;j < groupskins;j++)
1251                         {
1252                                 if (groupskins > 1)
1253                                         dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1254                                 else
1255                                         dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1256                                 if (!Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, false, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL))
1257                                         Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadInternalQuake(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight));
1258                                 datapointer += skinwidth * skinheight;
1259                                 totalskins++;
1260                         }
1261                 }
1262                 // check for skins that don't exist in the model, but do exist as external images
1263                 // (this was added because yummyluv kept pestering me about support for it)
1264                 // TODO: support shaders here?
1265                 for (;;)
1266                 {
1267                         dpsnprintf(name, sizeof(name), "%s_%i", loadmodel->name, loadmodel->numskins);
1268                         tempskinframe = R_SkinFrame_LoadExternal(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false, false);
1269                         if (!tempskinframe)
1270                                 break;
1271                         // expand the arrays to make room
1272                         tempskinscenes = loadmodel->skinscenes;
1273                         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1274                         memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1275                         Mem_Free(tempskinscenes);
1276
1277                         tempaliasskins = loadmodel->data_textures;
1278                         loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1279                         memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1280                         Mem_Free(tempaliasskins);
1281
1282                         // store the info about the new skin
1283                         Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, tempskinframe);
1284                         strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1285                         loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1286                         loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1287                         loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1288                         loadmodel->skinscenes[loadmodel->numskins].loop = true;
1289
1290                         //increase skin counts
1291                         loadmodel->num_textures++;
1292                         loadmodel->numskins++;
1293                         totalskins++;
1294
1295                         // fix up the pointers since they are pointing at the old textures array
1296                         // FIXME: this is a hack!
1297                         for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1298                                 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1299                 }
1300         }
1301
1302         surface = loadmodel->data_surfaces;
1303         surface->texture = loadmodel->data_textures;
1304         surface->num_firsttriangle = 0;
1305         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1306         surface->num_firstvertex = 0;
1307         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1308
1309         if(mod_alias_force_animated.string[0])
1310                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1311
1312         // Always make a BIH for the first frame, we can use it where possible.
1313         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1314         if (!loadmodel->surfmesh.isanimated)
1315         {
1316                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1317                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1318                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1319                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1320                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1321         }
1322 }
1323
1324 void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend)
1325 {
1326         int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1327         float iskinwidth, iskinheight;
1328         unsigned char *data;
1329         msurface_t *surface;
1330         md2_t *pinmodel;
1331         unsigned char *base, *datapointer;
1332         md2frame_t *pinframe;
1333         char *inskin;
1334         md2triangle_t *intri;
1335         unsigned short *inst;
1336         struct md2verthash_s
1337         {
1338                 struct md2verthash_s *next;
1339                 unsigned short xyz;
1340                 unsigned short st;
1341         }
1342         *hash, **md2verthash, *md2verthashdata;
1343         skinfile_t *skinfiles;
1344
1345         pinmodel = (md2_t *)buffer;
1346         base = (unsigned char *)buffer;
1347
1348         version = LittleLong (pinmodel->version);
1349         if (version != MD2ALIAS_VERSION)
1350                 Host_Error ("%s has wrong version number (%i should be %i)",
1351                         loadmodel->name, version, MD2ALIAS_VERSION);
1352
1353         loadmodel->modeldatatypestring = "MD2";
1354
1355         loadmodel->type = mod_alias;
1356         loadmodel->Draw = R_Mod_Draw;
1357         loadmodel->DrawDepth = R_Mod_DrawDepth;
1358         loadmodel->DrawDebug = R_Mod_DrawDebug;
1359         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1360         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1361         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1362         loadmodel->DrawLight = R_Mod_DrawLight;
1363         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1364         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1365         loadmodel->PointSuperContents = NULL;
1366         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1367
1368         if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1369                 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1370         if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1371                 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1372         if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1373                 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1374         if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1375                 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1376
1377         end = LittleLong(pinmodel->ofs_end);
1378         if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1379                 Host_Error ("%s is not a valid model", loadmodel->name);
1380         if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1381                 Host_Error ("%s is not a valid model", loadmodel->name);
1382         if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1383                 Host_Error ("%s is not a valid model", loadmodel->name);
1384         if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1385                 Host_Error ("%s is not a valid model", loadmodel->name);
1386         if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1387                 Host_Error ("%s is not a valid model", loadmodel->name);
1388
1389         loadmodel->numskins = LittleLong(pinmodel->num_skins);
1390         numxyz = LittleLong(pinmodel->num_xyz);
1391         numst = LittleLong(pinmodel->num_st);
1392         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1393         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1394         loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1395         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1396         skinwidth = LittleLong(pinmodel->skinwidth);
1397         skinheight = LittleLong(pinmodel->skinheight);
1398         iskinwidth = 1.0f / skinwidth;
1399         iskinheight = 1.0f / skinheight;
1400
1401         loadmodel->num_surfaces = 1;
1402         loadmodel->submodelsurfaces_start = 0;
1403         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1404         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]));
1405         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1406         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1407         loadmodel->modelsurfaces_sorted[0] = 0;
1408         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1409         loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1410         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1411
1412         loadmodel->synctype = ST_RAND;
1413
1414         // load the skins
1415         inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1416         skinfiles = Mod_LoadSkinFiles();
1417         if (skinfiles)
1418         {
1419                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1420                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1421                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1422                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1423                 Mod_FreeSkinFiles(skinfiles);
1424         }
1425         else if (loadmodel->numskins)
1426         {
1427                 // skins found (most likely not a player model)
1428                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1429                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1430                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1431                 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1432                         Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
1433         }
1434         else
1435         {
1436                 // no skins (most likely a player model)
1437                 loadmodel->numskins = 1;
1438                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1439                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1440                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1441                 Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures, loadmodel->name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing());
1442         }
1443
1444         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1445         for (i = 0;i < loadmodel->numskins;i++)
1446         {
1447                 loadmodel->skinscenes[i].firstframe = i;
1448                 loadmodel->skinscenes[i].framecount = 1;
1449                 loadmodel->skinscenes[i].loop = true;
1450                 loadmodel->skinscenes[i].framerate = 10;
1451         }
1452
1453         // load the triangles and stvert data
1454         inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1455         intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1456         md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1457         md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1458         // swap the triangle list
1459         loadmodel->surfmesh.num_vertices = 0;
1460         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1461         {
1462                 for (j = 0;j < 3;j++)
1463                 {
1464                         xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1465                         st = (unsigned short) LittleShort (intri[i].index_st[j]);
1466                         if (xyz >= numxyz)
1467                         {
1468                                 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1469                                 xyz = 0;
1470                         }
1471                         if (st >= numst)
1472                         {
1473                                 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1474                                 st = 0;
1475                         }
1476                         hashindex = (xyz * 256 + st) & 65535;
1477                         for (hash = md2verthash[hashindex];hash;hash = hash->next)
1478                                 if (hash->xyz == xyz && hash->st == st)
1479                                         break;
1480                         if (hash == NULL)
1481                         {
1482                                 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1483                                 hash->xyz = xyz;
1484                                 hash->st = st;
1485                                 hash->next = md2verthash[hashindex];
1486                                 md2verthash[hashindex] = hash;
1487                         }
1488                         loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1489                 }
1490         }
1491
1492         vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1493         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));
1494         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1495         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1496         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1497         {
1498                 int sts, stt;
1499                 hash = md2verthashdata + i;
1500                 vertremap[i] = hash->xyz;
1501                 sts = LittleShort(inst[hash->st*2+0]);
1502                 stt = LittleShort(inst[hash->st*2+1]);
1503                 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1504                 {
1505                         Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1506                         sts = 0;
1507                         stt = 0;
1508                 }
1509                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1510                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1511         }
1512
1513         Mem_Free(md2verthash);
1514         Mem_Free(md2verthashdata);
1515
1516         // generate ushort elements array if possible
1517         if (loadmodel->surfmesh.num_vertices <= 65536)
1518                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1519         if (loadmodel->surfmesh.data_element3s)
1520                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1521                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1522
1523         // load the frames
1524         datapointer = (base + LittleLong(pinmodel->ofs_frames));
1525         for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1526         {
1527                 int k;
1528                 trivertx_t *v;
1529                 trivertx_t *out;
1530                 pinframe = (md2frame_t *)datapointer;
1531                 datapointer += sizeof(md2frame_t);
1532                 // store the frame scale/translate into the appropriate array
1533                 for (j = 0;j < 3;j++)
1534                 {
1535                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1536                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1537                 }
1538                 // convert the vertices
1539                 v = (trivertx_t *)datapointer;
1540                 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1541                 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1542                         out[k] = v[vertremap[k]];
1543                 datapointer += numxyz * sizeof(trivertx_t);
1544
1545                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1546                 loadmodel->animscenes[i].firstframe = i;
1547                 loadmodel->animscenes[i].framecount = 1;
1548                 loadmodel->animscenes[i].framerate = 10;
1549                 loadmodel->animscenes[i].loop = true;
1550         }
1551
1552         Mem_Free(vertremap);
1553
1554         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1555         Mod_Alias_MorphMesh_CompileFrames();
1556         if(mod_alias_force_animated.string[0])
1557                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1558
1559         surface = loadmodel->data_surfaces;
1560         surface->texture = loadmodel->data_textures;
1561         surface->num_firsttriangle = 0;
1562         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1563         surface->num_firstvertex = 0;
1564         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1565
1566         // Always make a BIH for the first frame, we can use it where possible.
1567         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1568         if (!loadmodel->surfmesh.isanimated)
1569         {
1570                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1571                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1572                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1573                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1574                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1575         }
1576 }
1577
1578 void Mod_IDP3_Load(model_t *mod, void *buffer, void *bufferend)
1579 {
1580         int i, j, k, version, meshvertices, meshtriangles;
1581         unsigned char *data;
1582         msurface_t *surface;
1583         md3modelheader_t *pinmodel;
1584         md3frameinfo_t *pinframe;
1585         md3mesh_t *pinmesh;
1586         md3tag_t *pintag;
1587         skinfile_t *skinfiles;
1588
1589         pinmodel = (md3modelheader_t *)buffer;
1590
1591         if (memcmp(pinmodel->identifier, "IDP3", 4))
1592                 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1593         version = LittleLong (pinmodel->version);
1594         if (version != MD3VERSION)
1595                 Host_Error ("%s has wrong version number (%i should be %i)",
1596                         loadmodel->name, version, MD3VERSION);
1597
1598         skinfiles = Mod_LoadSkinFiles();
1599         if (loadmodel->numskins < 1)
1600                 loadmodel->numskins = 1;
1601
1602         loadmodel->modeldatatypestring = "MD3";
1603
1604         loadmodel->type = mod_alias;
1605         loadmodel->Draw = R_Mod_Draw;
1606         loadmodel->DrawDepth = R_Mod_DrawDepth;
1607         loadmodel->DrawDebug = R_Mod_DrawDebug;
1608         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1609         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1610         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1611         loadmodel->DrawLight = R_Mod_DrawLight;
1612         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1613         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1614         loadmodel->PointSuperContents = NULL;
1615         loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1616         loadmodel->synctype = ST_RAND;
1617         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1618         i = LittleLong (pinmodel->flags);
1619         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1620
1621         // set up some global info about the model
1622         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1623         loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1624
1625         // make skinscenes for the skins (no groups)
1626         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1627         for (i = 0;i < loadmodel->numskins;i++)
1628         {
1629                 loadmodel->skinscenes[i].firstframe = i;
1630                 loadmodel->skinscenes[i].framecount = 1;
1631                 loadmodel->skinscenes[i].loop = true;
1632                 loadmodel->skinscenes[i].framerate = 10;
1633         }
1634
1635         // load frameinfo
1636         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1637         for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1638         {
1639                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1640                 loadmodel->animscenes[i].firstframe = i;
1641                 loadmodel->animscenes[i].framecount = 1;
1642                 loadmodel->animscenes[i].framerate = 10;
1643                 loadmodel->animscenes[i].loop = true;
1644         }
1645
1646         // load tags
1647         loadmodel->num_tagframes = loadmodel->numframes;
1648         loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1649         loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1650         for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1651         {
1652                 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1653                 for (j = 0;j < 9;j++)
1654                         loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1655                 for (j = 0;j < 3;j++)
1656                         loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1657                 //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);
1658         }
1659
1660         // load meshes
1661         meshvertices = 0;
1662         meshtriangles = 0;
1663         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)))
1664         {
1665                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1666                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1667                 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1668                         Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1669                 meshvertices += LittleLong(pinmesh->num_vertices);
1670                 meshtriangles += LittleLong(pinmesh->num_triangles);
1671         }
1672
1673         loadmodel->submodelsurfaces_start = 0;
1674         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1675         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1676         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1677         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) + meshvertices * sizeof(float[2]) + meshvertices * loadmodel->numframes * sizeof(md3vertex_t));
1678         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1679         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1680         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1681         loadmodel->surfmesh.num_vertices = meshvertices;
1682         loadmodel->surfmesh.num_triangles = meshtriangles;
1683         loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1684         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1685         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1686         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1687         loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1688         if (meshvertices <= 65536)
1689         {
1690                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1691         }
1692
1693         meshvertices = 0;
1694         meshtriangles = 0;
1695         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)))
1696         {
1697                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1698                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1699                 loadmodel->modelsurfaces_sorted[i] = i;
1700                 surface = loadmodel->data_surfaces + i;
1701                 surface->texture = loadmodel->data_textures + i;
1702                 surface->num_firsttriangle = meshtriangles;
1703                 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1704                 surface->num_firstvertex = meshvertices;
1705                 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1706                 meshvertices += surface->num_vertices;
1707                 meshtriangles += surface->num_triangles;
1708
1709                 for (j = 0;j < surface->num_triangles * 3;j++)
1710                 {
1711                         int e = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1712                         loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = e;
1713                         if (loadmodel->surfmesh.data_element3s)
1714                                 loadmodel->surfmesh.data_element3s[j + surface->num_firsttriangle * 3] = e;
1715                 }
1716                 for (j = 0;j < surface->num_vertices;j++)
1717                 {
1718                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1719                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1720                 }
1721                 for (j = 0;j < loadmodel->numframes;j++)
1722                 {
1723                         const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1724                         md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1725                         for (k = 0;k < surface->num_vertices;k++, in++, out++)
1726                         {
1727                                 out->origin[0] = LittleShort(in->origin[0]);
1728                                 out->origin[1] = LittleShort(in->origin[1]);
1729                                 out->origin[2] = LittleShort(in->origin[2]);
1730                                 out->pitch = in->pitch;
1731                                 out->yaw = in->yaw;
1732                         }
1733                 }
1734
1735                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1736
1737                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, loadmodel->surfmesh.data_element3s + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1738         }
1739         Mod_Alias_MorphMesh_CompileFrames();
1740         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1741         Mod_FreeSkinFiles(skinfiles);
1742         Mod_MakeSortedSurfaces(loadmodel);
1743         if(mod_alias_force_animated.string[0])
1744                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1745
1746         // Always make a BIH for the first frame, we can use it where possible.
1747         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1748         if (!loadmodel->surfmesh.isanimated)
1749         {
1750                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1751                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1752                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1753                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1754                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1755         }
1756 }
1757
1758 void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend)
1759 {
1760         zymtype1header_t *pinmodel, *pheader;
1761         unsigned char *pbase;
1762         int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1763         float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1764         zymvertex_t *verts, *vertdata;
1765         zymscene_t *scene;
1766         zymbone_t *bone;
1767         char *shadername;
1768         skinfile_t *skinfiles;
1769         unsigned char *data;
1770         msurface_t *surface;
1771
1772         pinmodel = (zymtype1header_t *)buffer;
1773         pbase = (unsigned char *)buffer;
1774         if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1775                 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1776         if (BigLong(pinmodel->type) != 1)
1777                 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1778
1779         loadmodel->modeldatatypestring = "ZYM";
1780
1781         loadmodel->type = mod_alias;
1782         loadmodel->synctype = ST_RAND;
1783
1784         // byteswap header
1785         pheader = pinmodel;
1786         pheader->type = BigLong(pinmodel->type);
1787         pheader->filesize = BigLong(pinmodel->filesize);
1788         pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1789         pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1790         pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1791         pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1792         pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1793         pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1794         pheader->radius = BigFloat(pinmodel->radius);
1795         pheader->numverts = BigLong(pinmodel->numverts);
1796         pheader->numtris = BigLong(pinmodel->numtris);
1797         pheader->numshaders = BigLong(pinmodel->numshaders);
1798         pheader->numbones = BigLong(pinmodel->numbones);
1799         pheader->numscenes = BigLong(pinmodel->numscenes);
1800         pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1801         pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1802         pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1803         pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1804         pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1805         pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1806         pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1807         pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1808         pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1809         pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1810         pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1811         pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1812         pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1813         pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1814         pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1815         pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1816         pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1817         pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1818
1819         if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1820         {
1821                 Con_Printf("%s has no geometry\n", loadmodel->name);
1822                 return;
1823         }
1824         if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1825         {
1826                 Con_Printf("%s has no animations\n", loadmodel->name);
1827                 return;
1828         }
1829
1830         loadmodel->Draw = R_Mod_Draw;
1831         loadmodel->DrawDepth = R_Mod_DrawDepth;
1832         loadmodel->DrawDebug = R_Mod_DrawDebug;
1833         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1834         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1835         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1836         loadmodel->DrawLight = R_Mod_DrawLight;
1837         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1838         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1839         loadmodel->PointSuperContents = NULL;
1840         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1841
1842         loadmodel->numframes = pheader->numscenes;
1843         loadmodel->num_surfaces = pheader->numshaders;
1844
1845         skinfiles = Mod_LoadSkinFiles();
1846         if (loadmodel->numskins < 1)
1847                 loadmodel->numskins = 1;
1848
1849         // make skinscenes for the skins (no groups)
1850         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1851         for (i = 0;i < loadmodel->numskins;i++)
1852         {
1853                 loadmodel->skinscenes[i].firstframe = i;
1854                 loadmodel->skinscenes[i].framecount = 1;
1855                 loadmodel->skinscenes[i].loop = true;
1856                 loadmodel->skinscenes[i].framerate = 10;
1857         }
1858
1859         // model bbox
1860         // LadyHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
1861         modelradius = pheader->radius;
1862         for (i = 0;i < 3;i++)
1863         {
1864                 loadmodel->normalmins[i] = pheader->mins[i];
1865                 loadmodel->normalmaxs[i] = pheader->maxs[i];
1866                 loadmodel->rotatedmins[i] = -modelradius;
1867                 loadmodel->rotatedmaxs[i] = modelradius;
1868         }
1869         corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1870         corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1871         loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1872         if (loadmodel->yawmaxs[0] > modelradius)
1873                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1874         loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1875         loadmodel->yawmins[2] = loadmodel->normalmins[2];
1876         loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1877         loadmodel->radius = modelradius;
1878         loadmodel->radius2 = modelradius * modelradius;
1879
1880         // go through the lumps, swapping things
1881
1882         //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1883         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1884         scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1885         numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1886         for (i = 0;i < pheader->numscenes;i++)
1887         {
1888                 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1889                 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1890                 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1891                 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1892                 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1893                 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1894                         Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1895                 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1896                         Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1897                 if (loadmodel->animscenes[i].framerate < 0)
1898                         Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1899                 scene++;
1900         }
1901
1902         //zymlump_t lump_bones; // zymbone_t bone[numbones];
1903         loadmodel->num_bones = pheader->numbones;
1904         loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1905         bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1906         for (i = 0;i < pheader->numbones;i++)
1907         {
1908                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1909                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1910                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1911                 if (loadmodel->data_bones[i].parent >= i)
1912                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1913         }
1914
1915         //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1916         vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1917         bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1918         for (i = 0;i < pheader->numverts;i++)
1919         {
1920                 vertbonecounts[i] = BigLong(bonecount[i]);
1921                 if (vertbonecounts[i] != 1)
1922                         Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1923         }
1924
1925         loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1926
1927         meshvertices = pheader->numverts;
1928         meshtriangles = pheader->numtris;
1929
1930         loadmodel->submodelsurfaces_start = 0;
1931         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1932         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1933         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1934         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) + 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]));
1935         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1936         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1937         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1938         loadmodel->surfmesh.num_vertices = meshvertices;
1939         loadmodel->surfmesh.num_triangles = meshtriangles;
1940         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1941         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1942         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1943         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1944         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1945         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1946         loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
1947         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
1948         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1949         loadmodel->surfmesh.num_blends = 0;
1950         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
1951         if (loadmodel->surfmesh.num_vertices <= 65536)
1952         {
1953                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
1954         }
1955         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
1956         loadmodel->surfmesh.data_blendweights = NULL;
1957
1958         //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1959         poses = (float *) (pheader->lump_poses.start + pbase);
1960         // figure out scale of model from root bone, for compatibility with old zmodel versions
1961         tempvec[0] = BigFloat(poses[0]);
1962         tempvec[1] = BigFloat(poses[1]);
1963         tempvec[2] = BigFloat(poses[2]);
1964         modelscale = VectorLength(tempvec);
1965         biggestorigin = 0;
1966         for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
1967         {
1968                 f = fabs(BigFloat(poses[i]));
1969                 biggestorigin = max(biggestorigin, f);
1970         }
1971         loadmodel->num_posescale = biggestorigin / 32767.0f;
1972         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
1973         for (i = 0;i < numposes;i++)
1974         {
1975                 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
1976                 for (j = 0;j < loadmodel->num_bones;j++)
1977                 {
1978                         float pose[12];
1979                         matrix4x4_t posematrix;
1980                         for (k = 0;k < 12;k++)
1981                                 pose[k] = BigFloat(frameposes[j*12+k]);
1982                         //if (j < loadmodel->num_bones)
1983                         //      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));
1984                         // scale child bones to match the root scale
1985                         if (loadmodel->data_bones[j].parent >= 0)
1986                         {
1987                                 pose[3] *= modelscale;
1988                                 pose[7] *= modelscale;
1989                                 pose[11] *= modelscale;
1990                         }
1991                         // normalize rotation matrix
1992                         VectorNormalize(pose + 0);
1993                         VectorNormalize(pose + 4);
1994                         VectorNormalize(pose + 8);
1995                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
1996                         Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
1997                 }
1998         }
1999
2000         //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2001         verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2002         vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2003         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2004         // (converting from weight-blending skeletal animation to
2005         //  deformation-based skeletal animation)
2006         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2007         for (i = 0;i < loadmodel->num_bones;i++)
2008         {
2009                 float m[12];
2010                 for (k = 0;k < 12;k++)
2011                         m[k] = BigFloat(poses[i*12+k]);
2012                 if (loadmodel->data_bones[i].parent >= 0)
2013                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2014                 else
2015                         for (k = 0;k < 12;k++)
2016                                 bonepose[12*i+k] = m[k];
2017         }
2018         for (j = 0;j < pheader->numverts;j++)
2019         {
2020                 // this format really should have had a per vertexweight weight value...
2021                 // but since it does not, the weighting is completely ignored and
2022                 // only one weight is allowed per vertex
2023                 int boneindex = BigLong(vertdata[j].bonenum);
2024                 const float *m = bonepose + 12 * boneindex;
2025                 float relativeorigin[3];
2026                 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2027                 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2028                 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2029                 // transform the vertex bone weight into the base mesh
2030                 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2031                 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2032                 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2033                 // store the weight as the primary weight on this vertex
2034                 loadmodel->surfmesh.blends[j] = boneindex;
2035                 loadmodel->surfmesh.data_skeletalindex4ub[j*4  ] = boneindex;
2036                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2037                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2038                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2039                 loadmodel->surfmesh.data_skeletalweight4ub[j*4  ] = 255;
2040                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2041                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2042                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2043         }
2044         Z_Free(bonepose);
2045         // normals and tangents are calculated after elements are loaded
2046
2047         //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2048         outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2049         intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2050         for (i = 0;i < pheader->numverts;i++)
2051         {
2052                 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2053                 // flip T coordinate for OpenGL
2054                 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2055         }
2056
2057         //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2058         //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2059         //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2060
2061         //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2062         //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)
2063         // byteswap, validate, and swap winding order of tris
2064         count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2065         if (pheader->lump_render.length != count)
2066                 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2067         renderlist = (int *) (pheader->lump_render.start + pbase);
2068         renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2069         meshtriangles = 0;
2070         for (i = 0;i < loadmodel->num_surfaces;i++)
2071         {
2072                 int firstvertex, lastvertex;
2073                 if (renderlist >= renderlistend)
2074                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2075                 count = BigLong(*renderlist);renderlist++;
2076                 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2077                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2078
2079                 loadmodel->modelsurfaces_sorted[i] = i;
2080                 surface = loadmodel->data_surfaces + i;
2081                 surface->texture = loadmodel->data_textures + i;
2082                 surface->num_firsttriangle = meshtriangles;
2083                 surface->num_triangles = count;
2084                 meshtriangles += surface->num_triangles;
2085
2086                 // load the elements
2087                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2088                 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2089                 {
2090                         outelements[j*3+2] = BigLong(renderlist[0]);
2091                         outelements[j*3+1] = BigLong(renderlist[1]);
2092                         outelements[j*3+0] = BigLong(renderlist[2]);
2093                 }
2094                 // validate the elements and find the used vertex range
2095                 firstvertex = meshvertices;
2096                 lastvertex = 0;
2097                 for (j = 0;j < surface->num_triangles * 3;j++)
2098                 {
2099                         if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2100                                 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2101                         firstvertex = min(firstvertex, outelements[j]);
2102                         lastvertex = max(lastvertex, outelements[j]);
2103                 }
2104                 surface->num_firstvertex = firstvertex;
2105                 surface->num_vertices = lastvertex + 1 - firstvertex;
2106
2107                 // since zym models do not have named sections, reuse their shader
2108                 // name as the section name
2109                 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2110                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2111         }
2112         Mod_FreeSkinFiles(skinfiles);
2113         Mem_Free(vertbonecounts);
2114         Mem_Free(verts);
2115         Mod_MakeSortedSurfaces(loadmodel);
2116
2117         // compute all the mesh information that was not loaded from the file
2118         if (loadmodel->surfmesh.data_element3s)
2119                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2120                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2121         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2122         Mod_BuildBaseBonePoses();
2123         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);
2124         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);
2125         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2126         if(mod_alias_force_animated.string[0])
2127                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2128
2129         // Always make a BIH for the first frame, we can use it where possible.
2130         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2131         if (!loadmodel->surfmesh.isanimated)
2132         {
2133                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2134                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2135                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2136                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2137                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2138         }
2139 }
2140
2141 void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend)
2142 {
2143         dpmheader_t *pheader;
2144         dpmframe_t *frames;
2145         dpmbone_t *bone;
2146         dpmmesh_t *dpmmesh;
2147         unsigned char *pbase;
2148         int i, j, k, meshvertices, meshtriangles;
2149         skinfile_t *skinfiles;
2150         unsigned char *data;
2151         float *bonepose;
2152         float biggestorigin, tempvec[3], modelscale;
2153         float f;
2154         float *poses;
2155
2156         pheader = (dpmheader_t *)buffer;
2157         pbase = (unsigned char *)buffer;
2158         if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2159                 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2160         if (BigLong(pheader->type) != 2)
2161                 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2162
2163         loadmodel->modeldatatypestring = "DPM";
2164
2165         loadmodel->type = mod_alias;
2166         loadmodel->synctype = ST_RAND;
2167
2168         // byteswap header
2169         pheader->type = BigLong(pheader->type);
2170         pheader->filesize = BigLong(pheader->filesize);
2171         pheader->mins[0] = BigFloat(pheader->mins[0]);
2172         pheader->mins[1] = BigFloat(pheader->mins[1]);
2173         pheader->mins[2] = BigFloat(pheader->mins[2]);
2174         pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2175         pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2176         pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2177         pheader->yawradius = BigFloat(pheader->yawradius);
2178         pheader->allradius = BigFloat(pheader->allradius);
2179         pheader->num_bones = BigLong(pheader->num_bones);
2180         pheader->num_meshs = BigLong(pheader->num_meshs);
2181         pheader->num_frames = BigLong(pheader->num_frames);
2182         pheader->ofs_bones = BigLong(pheader->ofs_bones);
2183         pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2184         pheader->ofs_frames = BigLong(pheader->ofs_frames);
2185
2186         if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2187         {
2188                 Con_Printf("%s has no geometry\n", loadmodel->name);
2189                 return;
2190         }
2191         if (pheader->num_frames < 1)
2192         {
2193                 Con_Printf("%s has no frames\n", loadmodel->name);
2194                 return;
2195         }
2196
2197         loadmodel->Draw = R_Mod_Draw;
2198         loadmodel->DrawDepth = R_Mod_DrawDepth;
2199         loadmodel->DrawDebug = R_Mod_DrawDebug;
2200         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
2201         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
2202         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
2203         loadmodel->DrawLight = R_Mod_DrawLight;
2204         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2205         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2206         loadmodel->PointSuperContents = NULL;
2207         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2208
2209         // model bbox
2210         // LadyHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2211         for (i = 0;i < 3;i++)
2212         {
2213                 loadmodel->normalmins[i] = pheader->mins[i];
2214                 loadmodel->normalmaxs[i] = pheader->maxs[i];
2215                 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2216                 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2217                 loadmodel->rotatedmins[i] = -pheader->allradius;
2218                 loadmodel->rotatedmaxs[i] = pheader->allradius;
2219         }
2220         loadmodel->radius = pheader->allradius;
2221         loadmodel->radius2 = pheader->allradius * pheader->allradius;
2222
2223         // load external .skin files if present
2224         skinfiles = Mod_LoadSkinFiles();
2225         if (loadmodel->numskins < 1)
2226                 loadmodel->numskins = 1;
2227
2228         meshvertices = 0;
2229         meshtriangles = 0;
2230
2231         // gather combined statistics from the meshes
2232         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2233         for (i = 0;i < (int)pheader->num_meshs;i++)
2234         {
2235                 int numverts = BigLong(dpmmesh->num_verts);
2236                 meshvertices += numverts;
2237                 meshtriangles += BigLong(dpmmesh->num_tris);
2238                 dpmmesh++;
2239         }
2240
2241         loadmodel->numframes = pheader->num_frames;
2242         loadmodel->num_bones = pheader->num_bones;
2243         loadmodel->num_poses = loadmodel->numframes;
2244         loadmodel->submodelsurfaces_start = 0;
2245         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = pheader->num_meshs;
2246         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2247         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2248         // do most allocations as one merged chunk
2249         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) + 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));
2250         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2251         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2252         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2253         loadmodel->surfmesh.num_vertices = meshvertices;
2254         loadmodel->surfmesh.num_triangles = meshtriangles;
2255         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2256         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2257         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2258         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2259         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2260         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2261         loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2262         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2263         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2264         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2265         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2266         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2267         loadmodel->surfmesh.num_blends = 0;
2268         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2269         if (meshvertices <= 65536)
2270         {
2271                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2272         }
2273         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2274         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2275
2276         for (i = 0;i < loadmodel->numskins;i++)
2277         {
2278                 loadmodel->skinscenes[i].firstframe = i;
2279                 loadmodel->skinscenes[i].framecount = 1;
2280                 loadmodel->skinscenes[i].loop = true;
2281                 loadmodel->skinscenes[i].framerate = 10;
2282         }
2283
2284         // load the bone info
2285         bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2286         for (i = 0;i < loadmodel->num_bones;i++)
2287         {
2288                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2289                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2290                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2291                 if (loadmodel->data_bones[i].parent >= i)
2292                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2293         }
2294
2295         // load the frames
2296         frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2297         // figure out scale of model from root bone, for compatibility with old dpmodel versions
2298         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2299         tempvec[0] = BigFloat(poses[0]);
2300         tempvec[1] = BigFloat(poses[1]);
2301         tempvec[2] = BigFloat(poses[2]);
2302         modelscale = VectorLength(tempvec);
2303         biggestorigin = 0;
2304         for (i = 0;i < loadmodel->numframes;i++)
2305         {
2306                 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2307                 loadmodel->animscenes[i].firstframe = i;
2308                 loadmodel->animscenes[i].framecount = 1;
2309                 loadmodel->animscenes[i].loop = true;
2310                 loadmodel->animscenes[i].framerate = 10;
2311                 // load the bone poses for this frame
2312                 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2313                 for (j = 0;j < loadmodel->num_bones*12;j++)
2314                 {
2315                         f = fabs(BigFloat(poses[j]));
2316                         biggestorigin = max(biggestorigin, f);
2317                 }
2318                 // stuff not processed here: mins, maxs, yawradius, allradius
2319         }
2320         loadmodel->num_posescale = biggestorigin / 32767.0f;
2321         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2322         for (i = 0;i < loadmodel->numframes;i++)
2323         {
2324                 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2325                 for (j = 0;j < loadmodel->num_bones;j++)
2326                 {
2327                         float pose[12];
2328                         matrix4x4_t posematrix;
2329                         for (k = 0;k < 12;k++)
2330                                 pose[k] = BigFloat(frameposes[j*12+k]);
2331                         // scale child bones to match the root scale
2332                         if (loadmodel->data_bones[j].parent >= 0)
2333                         {
2334                                 pose[3] *= modelscale;
2335                                 pose[7] *= modelscale;
2336                                 pose[11] *= modelscale;
2337                         }
2338                         // normalize rotation matrix
2339                         VectorNormalize(pose + 0);
2340                         VectorNormalize(pose + 4);
2341                         VectorNormalize(pose + 8);
2342                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2343                         Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2344                 }
2345         }
2346
2347         // load the meshes now
2348         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2349         meshvertices = 0;
2350         meshtriangles = 0;
2351         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2352         // (converting from weight-blending skeletal animation to
2353         //  deformation-based skeletal animation)
2354         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2355         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2356         for (i = 0;i < loadmodel->num_bones;i++)
2357         {
2358                 float m[12];
2359                 for (k = 0;k < 12;k++)
2360                         m[k] = BigFloat(poses[i*12+k]);
2361                 if (loadmodel->data_bones[i].parent >= 0)
2362                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2363                 else
2364                         for (k = 0;k < 12;k++)
2365                                 bonepose[12*i+k] = m[k];
2366         }
2367         for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2368         {
2369                 const int *inelements;
2370                 int *outelement3i;
2371                 unsigned short *outelement3s;
2372                 const float *intexcoord;
2373                 msurface_t *surface;
2374
2375                 loadmodel->modelsurfaces_sorted[i] = i;
2376                 surface = loadmodel->data_surfaces + i;
2377                 surface->texture = loadmodel->data_textures + i;
2378                 surface->num_firsttriangle = meshtriangles;
2379                 surface->num_triangles = BigLong(dpmmesh->num_tris);
2380                 surface->num_firstvertex = meshvertices;
2381                 surface->num_vertices = BigLong(dpmmesh->num_verts);
2382                 meshvertices += surface->num_vertices;
2383                 meshtriangles += surface->num_triangles;
2384
2385                 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2386                 outelement3i = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2387                 outelement3s = loadmodel->surfmesh.data_element3s ? loadmodel->surfmesh.data_element3s + surface->num_firsttriangle * 3 : NULL;
2388                 for (j = 0;j < surface->num_triangles;j++)
2389                 {
2390                         // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2391                         outelement3i[j * 3 + 0] = surface->num_firstvertex + BigLong(inelements[j * 3 + 2]);
2392                         outelement3i[j * 3 + 1] = surface->num_firstvertex + BigLong(inelements[j * 3 + 1]);
2393                         outelement3i[j * 3 + 2] = surface->num_firstvertex + BigLong(inelements[j * 3 + 0]);
2394                         if (outelement3s)
2395                         {
2396                                 outelement3s[j * 3 + 0] = outelement3i[j * 3 + 0];
2397                                 outelement3s[j * 3 + 1] = outelement3i[j * 3 + 1];
2398                                 outelement3s[j * 3 + 2] = outelement3i[j * 3 + 2];
2399                         }
2400                 }
2401
2402                 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2403                 for (j = 0;j < surface->num_vertices*2;j++)
2404                         loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2405
2406                 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2407                 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2408                 {
2409                         int weightindex[4] = { 0, 0, 0, 0 };
2410                         float weightinfluence[4] = { 0, 0, 0, 0 };
2411                         int l;
2412                         int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2413                         data += sizeof(dpmvertex_t);
2414                         for (k = 0;k < numweights;k++)
2415                         {
2416                                 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2417                                 int boneindex = BigLong(vert->bonenum);
2418                                 const float *m = bonepose + 12 * boneindex;
2419                                 float influence = BigFloat(vert->influence);
2420                                 float relativeorigin[3], relativenormal[3];
2421                                 relativeorigin[0] = BigFloat(vert->origin[0]);
2422                                 relativeorigin[1] = BigFloat(vert->origin[1]);
2423                                 relativeorigin[2] = BigFloat(vert->origin[2]);
2424                                 relativenormal[0] = BigFloat(vert->normal[0]);
2425                                 relativenormal[1] = BigFloat(vert->normal[1]);
2426                                 relativenormal[2] = BigFloat(vert->normal[2]);
2427                                 // blend the vertex bone weights into the base mesh
2428                                 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2429                                 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2430                                 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2431                                 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2432                                 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2433                                 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2434                                 if (!k)
2435                                 {
2436                                         // store the first (and often only) weight
2437                                         weightinfluence[0] = influence;
2438                                         weightindex[0] = boneindex;
2439                                 }
2440                                 else
2441                                 {
2442                                         // sort the new weight into this vertex's weight table
2443                                         // (which only accepts up to 4 bones per vertex)
2444                                         for (l = 0;l < 4;l++)
2445                                         {
2446                                                 if (weightinfluence[l] < influence)
2447                                                 {
2448                                                         // move weaker influence weights out of the way first
2449                                                         int l2;
2450                                                         for (l2 = 3;l2 > l;l2--)
2451                                                         {
2452                                                                 weightinfluence[l2] = weightinfluence[l2-1];
2453                                                                 weightindex[l2] = weightindex[l2-1];
2454                                                         }
2455                                                         // store the new weight
2456                                                         weightinfluence[l] = influence;
2457                                                         weightindex[l] = boneindex;
2458                                                         break;
2459                                                 }
2460                                         }
2461                                 }
2462                                 data += sizeof(dpmbonevert_t);
2463                         }
2464                         loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2465                         loadmodel->surfmesh.data_skeletalindex4ub[j*4  ] = weightindex[0];
2466                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2467                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2468                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2469                         loadmodel->surfmesh.data_skeletalweight4ub[j*4  ] = (unsigned char)(weightinfluence[0]*255.0f);
2470                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2471                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2472                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2473                 }
2474
2475                 // since dpm models do not have named sections, reuse their shader name as the section name
2476                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2477
2478                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, loadmodel->surfmesh.data_element3s + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2479         }
2480         if (loadmodel->surfmesh.num_blends < meshvertices)
2481                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2482         Z_Free(bonepose);
2483         Mod_FreeSkinFiles(skinfiles);
2484         Mod_MakeSortedSurfaces(loadmodel);
2485
2486         // compute all the mesh information that was not loaded from the file
2487         Mod_BuildBaseBonePoses();
2488         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);
2489         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2490         if(mod_alias_force_animated.string[0])
2491                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2492
2493         // Always make a BIH for the first frame, we can use it where possible.
2494         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2495         if (!loadmodel->surfmesh.isanimated)
2496         {
2497                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2498                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2499                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2500                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2501                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2502         }
2503 }
2504
2505 // no idea why PSK/PSA files contain weird quaternions but they do...
2506 #define PSKQUATNEGATIONS
2507 void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
2508 {
2509         int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2510         int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2511         fs_offset_t filesize;
2512         pskpnts_t *pnts;
2513         pskvtxw_t *vtxw;
2514         pskface_t *faces;
2515         pskmatt_t *matts;
2516         pskboneinfo_t *bones;
2517         pskrawweights_t *rawweights;
2518         //pskboneinfo_t *animbones;
2519         pskaniminfo_t *anims;
2520         pskanimkeys_t *animkeys;
2521         void *animfilebuffer, *animbuffer, *animbufferend;
2522         unsigned char *data;
2523         pskchunk_t *pchunk;
2524         skinfile_t *skinfiles;
2525         char animname[MAX_QPATH];
2526         size_t size;
2527         float biggestorigin;
2528
2529         pchunk = (pskchunk_t *)buffer;
2530         if (strcmp(pchunk->id, "ACTRHEAD"))
2531                 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2532
2533         loadmodel->modeldatatypestring = "PSK";
2534
2535         loadmodel->type = mod_alias;
2536         loadmodel->Draw = R_Mod_Draw;
2537         loadmodel->DrawDepth = R_Mod_DrawDepth;
2538         loadmodel->DrawDebug = R_Mod_DrawDebug;
2539         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
2540         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
2541         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
2542         loadmodel->DrawLight = R_Mod_DrawLight;
2543         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2544         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2545         loadmodel->PointSuperContents = NULL;
2546         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2547         loadmodel->synctype = ST_RAND;
2548
2549         FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2550         strlcat(animname, ".psa", sizeof(animname));
2551         animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2552         animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2553         if (!animbuffer)
2554                 animbufferend = animbuffer;
2555
2556         numpnts = 0;
2557         pnts = NULL;
2558         numvtxw = 0;
2559         vtxw = NULL;
2560         numfaces = 0;
2561         faces = NULL;
2562         nummatts = 0;
2563         matts = NULL;
2564         numbones = 0;
2565         bones = NULL;
2566         numrawweights = 0;
2567         rawweights = NULL;
2568         numanims = 0;
2569         anims = NULL;
2570         numanimkeys = 0;
2571         animkeys = NULL;
2572
2573         while (buffer < bufferend)
2574         {
2575                 pchunk = (pskchunk_t *)buffer;
2576                 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2577                 version = LittleLong(pchunk->version);
2578                 recordsize = LittleLong(pchunk->recordsize);
2579                 numrecords = LittleLong(pchunk->numrecords);
2580                 if (developer_extra.integer)
2581                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2582                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2583                         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);
2584                 if (!strcmp(pchunk->id, "ACTRHEAD"))
2585                 {
2586                         // nothing to do
2587                 }
2588                 else if (!strcmp(pchunk->id, "PNTS0000"))
2589                 {
2590                         pskpnts_t *p;
2591                         if (recordsize != sizeof(*p))
2592                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2593                         // byteswap in place and keep the pointer
2594                         numpnts = numrecords;
2595                         pnts = (pskpnts_t *)buffer;
2596                         for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2597                         {
2598                                 p->origin[0] = LittleFloat(p->origin[0]);
2599                                 p->origin[1] = LittleFloat(p->origin[1]);
2600                                 p->origin[2] = LittleFloat(p->origin[2]);
2601                         }
2602                         buffer = p;
2603                 }
2604                 else if (!strcmp(pchunk->id, "VTXW0000"))
2605                 {
2606                         pskvtxw_t *p;
2607                         if (recordsize != sizeof(*p))
2608                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2609                         // byteswap in place and keep the pointer
2610                         numvtxw = numrecords;
2611                         vtxw = (pskvtxw_t *)buffer;
2612                         for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2613                         {
2614                                 p->pntsindex = LittleShort(p->pntsindex);
2615                                 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2616                                 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2617                                 if (p->pntsindex >= numpnts)
2618                                 {
2619                                         Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2620                                         p->pntsindex = 0;
2621                                 }
2622                         }
2623                         buffer = p;
2624                 }
2625                 else if (!strcmp(pchunk->id, "FACE0000"))
2626                 {
2627                         pskface_t *p;
2628                         if (recordsize != sizeof(*p))
2629                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2630                         // byteswap in place and keep the pointer
2631                         numfaces = numrecords;
2632                         faces = (pskface_t *)buffer;
2633                         for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2634                         {
2635                                 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2636                                 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2637                                 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2638                                 p->group = LittleLong(p->group);
2639                                 if (p->vtxwindex[0] >= numvtxw)
2640                                 {
2641                                         Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2642                                         p->vtxwindex[0] = 0;
2643                                 }
2644                                 if (p->vtxwindex[1] >= numvtxw)
2645                                 {
2646                                         Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2647                                         p->vtxwindex[1] = 0;
2648                                 }
2649                                 if (p->vtxwindex[2] >= numvtxw)
2650                                 {
2651                                         Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2652                                         p->vtxwindex[2] = 0;
2653                                 }
2654                         }
2655                         buffer = p;
2656                 }
2657                 else if (!strcmp(pchunk->id, "MATT0000"))
2658                 {
2659                         pskmatt_t *p;
2660                         if (recordsize != sizeof(*p))
2661                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2662                         // byteswap in place and keep the pointer
2663                         nummatts = numrecords;
2664                         matts = (pskmatt_t *)buffer;
2665                         for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2666                         {
2667                                 // nothing to do
2668                         }
2669                         buffer = p;
2670                 }
2671                 else if (!strcmp(pchunk->id, "REFSKELT"))
2672                 {
2673                         pskboneinfo_t *p;
2674                         if (recordsize != sizeof(*p))
2675                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2676                         // byteswap in place and keep the pointer
2677                         numbones = numrecords;
2678                         bones = (pskboneinfo_t *)buffer;
2679                         for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2680                         {
2681                                 p->numchildren = LittleLong(p->numchildren);
2682                                 p->parent = LittleLong(p->parent);
2683                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2684                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2685                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2686                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2687                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2688                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2689                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2690                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2691                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2692                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2693                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2694 #ifdef PSKQUATNEGATIONS
2695                                 if (index)
2696                                 {
2697                                         p->basepose.quat[0] *= -1;
2698                                         p->basepose.quat[1] *= -1;
2699                                         p->basepose.quat[2] *= -1;
2700                                 }
2701                                 else
2702                                 {
2703                                         p->basepose.quat[0] *=  1;
2704                                         p->basepose.quat[1] *= -1;
2705                                         p->basepose.quat[2] *=  1;
2706                                 }
2707 #endif
2708                                 if (p->parent < 0 || p->parent >= numbones)
2709                                 {
2710                                         Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2711                                         p->parent = 0;
2712                                 }
2713                         }
2714                         buffer = p;
2715                 }
2716                 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2717                 {
2718                         pskrawweights_t *p;
2719                         if (recordsize != sizeof(*p))
2720                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2721                         // byteswap in place and keep the pointer
2722                         numrawweights = numrecords;
2723                         rawweights = (pskrawweights_t *)buffer;
2724                         for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2725                         {
2726                                 p->weight = LittleFloat(p->weight);
2727                                 p->pntsindex = LittleLong(p->pntsindex);
2728                                 p->boneindex = LittleLong(p->boneindex);
2729                                 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2730                                 {
2731                                         Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2732                                         p->pntsindex = 0;
2733                                 }
2734                                 if (p->boneindex < 0 || p->boneindex >= numbones)
2735                                 {
2736                                         Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2737                                         p->boneindex = 0;
2738                                 }
2739                         }
2740                         buffer = p;
2741                 }
2742         }
2743
2744         while (animbuffer < animbufferend)
2745         {
2746                 pchunk = (pskchunk_t *)animbuffer;
2747                 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2748                 version = LittleLong(pchunk->version);
2749                 recordsize = LittleLong(pchunk->recordsize);
2750                 numrecords = LittleLong(pchunk->numrecords);
2751                 if (developer_extra.integer)
2752                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2753                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2754                         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);
2755                 if (!strcmp(pchunk->id, "ANIMHEAD"))
2756                 {
2757                         // nothing to do
2758                 }
2759                 else if (!strcmp(pchunk->id, "BONENAMES"))
2760                 {
2761                         pskboneinfo_t *p;
2762                         if (recordsize != sizeof(*p))
2763                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2764                         // byteswap in place and keep the pointer
2765                         numanimbones = numrecords;
2766                         //animbones = (pskboneinfo_t *)animbuffer;
2767                         // NOTE: supposedly psa does not need to match the psk model, the
2768                         // bones missing from the psa would simply use their base
2769                         // positions from the psk, but this is hard for me to implement
2770                         // and people can easily make animations that match.
2771                         if (numanimbones != numbones)
2772                                 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2773                         for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2774                         {
2775                                 p->numchildren = LittleLong(p->numchildren);
2776                                 p->parent = LittleLong(p->parent);
2777                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2778                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2779                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2780                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2781                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2782                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2783                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2784                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2785                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2786                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2787                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2788 #ifdef PSKQUATNEGATIONS
2789                                 if (index)
2790                                 {
2791                                         p->basepose.quat[0] *= -1;
2792                                         p->basepose.quat[1] *= -1;
2793                                         p->basepose.quat[2] *= -1;
2794                                 }
2795                                 else
2796                                 {
2797                                         p->basepose.quat[0] *=  1;
2798                                         p->basepose.quat[1] *= -1;
2799                                         p->basepose.quat[2] *=  1;
2800                                 }
2801 #endif
2802                                 if (p->parent < 0 || p->parent >= numanimbones)
2803                                 {
2804                                         Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2805                                         p->parent = 0;
2806                                 }
2807                                 // check that bones are the same as in the base
2808                                 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2809                                         Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2810                         }
2811                         animbuffer = p;
2812                 }
2813                 else if (!strcmp(pchunk->id, "ANIMINFO"))
2814                 {
2815                         pskaniminfo_t *p;
2816                         if (recordsize != sizeof(*p))
2817                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2818                         // byteswap in place and keep the pointer
2819                         numanims = numrecords;
2820                         anims = (pskaniminfo_t *)animbuffer;
2821                         for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2822                         {
2823                                 p->numbones = LittleLong(p->numbones);
2824                                 p->playtime = LittleFloat(p->playtime);
2825                                 p->fps = LittleFloat(p->fps);
2826                                 p->firstframe = LittleLong(p->firstframe);
2827                                 p->numframes = LittleLong(p->numframes);
2828                                 if (p->numbones != numbones)
2829                                         Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2830                         }
2831                         animbuffer = p;
2832                 }
2833                 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2834                 {
2835                         pskanimkeys_t *p;
2836                         if (recordsize != sizeof(*p))
2837                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2838                         numanimkeys = numrecords;
2839                         animkeys = (pskanimkeys_t *)animbuffer;
2840                         for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2841                         {
2842                                 p->origin[0] = LittleFloat(p->origin[0]);
2843                                 p->origin[1] = LittleFloat(p->origin[1]);
2844                                 p->origin[2] = LittleFloat(p->origin[2]);
2845                                 p->quat[0] = LittleFloat(p->quat[0]);
2846                                 p->quat[1] = LittleFloat(p->quat[1]);
2847                                 p->quat[2] = LittleFloat(p->quat[2]);
2848                                 p->quat[3] = LittleFloat(p->quat[3]);
2849                                 p->frametime = LittleFloat(p->frametime);
2850 #ifdef PSKQUATNEGATIONS
2851                                 if (index % numbones)
2852                                 {
2853                                         p->quat[0] *= -1;
2854                                         p->quat[1] *= -1;
2855                                         p->quat[2] *= -1;
2856                                 }
2857                                 else
2858                                 {
2859                                         p->quat[0] *=  1;
2860                                         p->quat[1] *= -1;
2861                                         p->quat[2] *=  1;
2862                                 }
2863 #endif
2864                         }
2865                         animbuffer = p;
2866                         // TODO: allocate bonepose stuff
2867                 }
2868                 else
2869                         Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2870         }
2871
2872         if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2873                 Host_Error("%s: missing required chunks", loadmodel->name);
2874
2875         if (numanims)
2876         {
2877                 loadmodel->numframes = 0;
2878                 for (index = 0;index < numanims;index++)
2879                         loadmodel->numframes += anims[index].numframes;
2880                 if (numanimkeys != numbones * loadmodel->numframes)
2881                         Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2882         }
2883         else
2884                 loadmodel->numframes = loadmodel->num_poses = 1;
2885
2886         meshvertices = numvtxw;
2887         meshtriangles = numfaces;
2888
2889         // load external .skin files if present
2890         skinfiles = Mod_LoadSkinFiles();
2891         if (loadmodel->numskins < 1)
2892                 loadmodel->numskins = 1;
2893         loadmodel->num_bones = numbones;
2894         loadmodel->num_poses = loadmodel->numframes;
2895         loadmodel->submodelsurfaces_start = 0;
2896         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = nummatts;
2897         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2898         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2899         loadmodel->surfmesh.num_vertices = meshvertices;
2900         loadmodel->surfmesh.num_triangles = meshtriangles;
2901         // do most allocations as one merged chunk
2902         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]) + 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);
2903         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2904         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2905         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2906         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2907         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2908         loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2909         loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2910         loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2911         loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2912         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2913         loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2914         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2915         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2916         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2917         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2918         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2919         loadmodel->surfmesh.num_blends = 0;
2920         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2921         if (loadmodel->surfmesh.num_vertices <= 65536)
2922         {
2923                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2924         }
2925         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2926         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
2927
2928         for (i = 0;i < loadmodel->numskins;i++)
2929         {
2930                 loadmodel->skinscenes[i].firstframe = i;
2931                 loadmodel->skinscenes[i].framecount = 1;
2932                 loadmodel->skinscenes[i].loop = true;
2933                 loadmodel->skinscenes[i].framerate = 10;
2934         }
2935
2936         // create surfaces
2937         for (index = 0, i = 0;index < nummatts;index++)
2938         {
2939                 // since psk models do not have named sections, reuse their shader name as the section name
2940                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2941                 loadmodel->modelsurfaces_sorted[index] = index;
2942                 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2943                 loadmodel->data_surfaces[index].num_firstvertex = 0;
2944                 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2945         }
2946
2947         // copy over the vertex locations and texcoords
2948         for (index = 0;index < numvtxw;index++)
2949         {
2950                 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
2951                 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
2952                 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
2953                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
2954                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
2955         }
2956
2957         // loading the faces is complicated because we need to sort them into surfaces by mattindex
2958         for (index = 0;index < numfaces;index++)
2959                 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
2960         for (index = 0, i = 0;index < nummatts;index++)
2961         {
2962                 loadmodel->data_surfaces[index].num_firsttriangle = i;
2963                 i += loadmodel->data_surfaces[index].num_triangles;
2964                 loadmodel->data_surfaces[index].num_triangles = 0;
2965         }
2966         for (index = 0;index < numfaces;index++)
2967         {
2968                 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
2969                 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
2970                 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
2971                 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
2972         }
2973
2974         // copy over the bones
2975         for (index = 0;index < numbones;index++)
2976         {
2977                 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
2978                 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
2979                 if (loadmodel->data_bones[index].parent >= index)
2980                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
2981         }
2982
2983         // convert the basepose data
2984         if (loadmodel->num_bones)
2985         {
2986                 int boneindex;
2987                 matrix4x4_t *basebonepose;
2988                 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
2989                 matrix4x4_t bonematrix;
2990                 matrix4x4_t tempbonematrix;
2991                 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
2992                 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
2993                 {
2994                         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]);
2995                         if (loadmodel->data_bones[boneindex].parent >= 0)
2996                         {
2997                                 tempbonematrix = bonematrix;
2998                                 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
2999                         }
3000                         basebonepose[boneindex] = bonematrix;
3001                         Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3002                         Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3003                 }
3004                 Mem_Free(basebonepose);
3005         }
3006
3007         // sort the psk point weights into the vertex weight tables
3008         // (which only accept up to 4 bones per vertex)
3009         for (index = 0;index < numvtxw;index++)
3010         {
3011                 int weightindex[4] = { 0, 0, 0, 0 };
3012                 float weightinfluence[4] = { 0, 0, 0, 0 };
3013                 int l;
3014                 for (j = 0;j < numrawweights;j++)
3015                 {
3016                         if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3017                         {
3018                                 int boneindex = rawweights[j].boneindex;
3019                                 float influence = rawweights[j].weight;
3020                                 for (l = 0;l < 4;l++)
3021                                 {
3022                                         if (weightinfluence[l] < influence)
3023                                         {
3024                                                 // move lower influence weights out of the way first
3025                                                 int l2;
3026                                                 for (l2 = 3;l2 > l;l2--)
3027                                                 {
3028                                                         weightinfluence[l2] = weightinfluence[l2-1];
3029                                                         weightindex[l2] = weightindex[l2-1];
3030                                                 }
3031                                                 // store the new weight
3032                                                 weightinfluence[l] = influence;
3033                                                 weightindex[l] = boneindex;
3034                                                 break;
3035                                         }
3036                                 }
3037                         }
3038                 }
3039                 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3040                 loadmodel->surfmesh.data_skeletalindex4ub[index*4  ] = weightindex[0];
3041                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3042                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3043                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3044                 loadmodel->surfmesh.data_skeletalweight4ub[index*4  ] = (unsigned char)(weightinfluence[0]*255.0f);
3045                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3046                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3047                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3048         }
3049         if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3050                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3051
3052         // set up the animscenes based on the anims
3053         if (numanims)
3054         {
3055                 for (index = 0, i = 0;index < numanims;index++)
3056                 {
3057                         for (j = 0;j < anims[index].numframes;j++, i++)
3058                         {
3059                                 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3060                                 loadmodel->animscenes[i].firstframe = i;
3061                                 loadmodel->animscenes[i].framecount = 1;
3062                                 loadmodel->animscenes[i].loop = true;
3063                                 loadmodel->animscenes[i].framerate = anims[index].fps;
3064                         }
3065                 }
3066                 // calculate the scaling value for bone origins so they can be compressed to short
3067                 biggestorigin = 0;
3068                 for (index = 0;index < numanimkeys;index++)
3069                 {
3070                         pskanimkeys_t *k = animkeys + index;
3071                         biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3072                         biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3073                         biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3074                 }
3075                 loadmodel->num_posescale = biggestorigin / 32767.0f;
3076                 if (loadmodel->num_posescale == 0) // don't divide by zero
3077                         loadmodel->num_posescale = 1.0;
3078                 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3079         
3080                 // load the poses from the animkeys
3081                 for (index = 0;index < numanimkeys;index++)
3082                 {
3083                         pskanimkeys_t *k = animkeys + index;
3084                         float quat[4];
3085                         Vector4Copy(k->quat, quat);
3086                         if (quat[3] > 0)
3087                                 Vector4Negate(quat, quat);
3088                         Vector4Normalize2(quat, quat);
3089                         // compress poses to the short[7] format for longterm storage
3090                         loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3091                         loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3092                         loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3093                         loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3094                         loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3095                         loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3096                         loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3097                 }
3098         }
3099         else
3100         {
3101                 strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3102                 loadmodel->animscenes[0].firstframe = 0;
3103                 loadmodel->animscenes[0].framecount = 1;
3104                 loadmodel->animscenes[0].loop = true;
3105                 loadmodel->animscenes[0].framerate = 10;
3106
3107                 // calculate the scaling value for bone origins so they can be compressed to short
3108                 biggestorigin = 0;
3109                 for (index = 0;index < numbones;index++)
3110                 {
3111                         pskboneinfo_t *p = bones + index;
3112                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3113                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3114                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3115                 }
3116                 loadmodel->num_posescale = biggestorigin / 32767.0f;
3117                 if (loadmodel->num_posescale == 0) // don't divide by zero
3118                         loadmodel->num_posescale = 1.0;
3119                 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3120         
3121                 // load the basepose as a frame
3122                 for (index = 0;index < numbones;index++)
3123                 {
3124                         pskboneinfo_t *p = bones + index;
3125                         float quat[4];
3126                         Vector4Copy(p->basepose.quat, quat);
3127                         if (quat[3] > 0)
3128                                 Vector4Negate(quat, quat);
3129                         Vector4Normalize2(quat, quat);
3130                         // compress poses to the short[7] format for longterm storage
3131                         loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3132                         loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3133                         loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3134                         loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3135                         loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3136                         loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3137                         loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3138                 }
3139         }
3140
3141         Mod_FreeSkinFiles(skinfiles);
3142         if (animfilebuffer)
3143                 Mem_Free(animfilebuffer);
3144         Mod_MakeSortedSurfaces(loadmodel);
3145
3146         // compute all the mesh information that was not loaded from the file
3147         // TODO: honor smoothing groups somehow?
3148         if (loadmodel->surfmesh.data_element3s)
3149                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3150                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3151         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3152         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);
3153         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);
3154         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3155         if(mod_alias_force_animated.string[0])
3156                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3157
3158         // Always make a BIH for the first frame, we can use it where possible.
3159         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3160         if (!loadmodel->surfmesh.isanimated)
3161         {
3162                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3163                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3164                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3165                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3166                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3167         }
3168 }
3169
3170 void Mod_INTERQUAKEMODEL_Load(model_t *mod, void *buffer, void *bufferend)
3171 {
3172         unsigned char *data;
3173         const char *text;
3174         const unsigned char *pbase, *pend;
3175         iqmheader_t header;
3176         skinfile_t *skinfiles;
3177         int i, j, k, meshvertices, meshtriangles;
3178         float biggestorigin;
3179         const unsigned int *inelements;
3180         int *outelements;
3181         float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3182         // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3183         const float *vnormal = NULL;
3184         const float *vposition = NULL;
3185         const float *vtangent = NULL;
3186         const float *vtexcoord = NULL;
3187         const float *vcolor4f = NULL;
3188         const unsigned char *vblendindexes = NULL;
3189         const unsigned char *vblendweights = NULL;
3190         const unsigned char *vcolor4ub = NULL;
3191         const unsigned short *framedata = NULL;
3192         // temporary memory allocations (because the data in the file may be misaligned)
3193         iqmanim_t *anims = NULL;
3194         iqmbounds_t *bounds = NULL;
3195         iqmjoint1_t *joint1 = NULL;
3196         iqmjoint_t *joint = NULL;
3197         iqmmesh_t *meshes = NULL;
3198         iqmpose1_t *pose1 = NULL;
3199         iqmpose_t *pose = NULL;
3200         iqmvertexarray_t *vas = NULL;
3201
3202         pbase = (unsigned char *)buffer;
3203         pend = (unsigned char *)bufferend;
3204
3205         if (pbase + sizeof(iqmheader_t) > pend)
3206                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3207
3208         // copy struct (otherwise it may be misaligned)
3209         // LadyHavoc: okay it's definitely not misaligned here, but for consistency...
3210         memcpy(&header, pbase, sizeof(iqmheader_t));
3211
3212         if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3213                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3214         if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3215                 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3216
3217         loadmodel->modeldatatypestring = "IQM";
3218
3219         loadmodel->type = mod_alias;
3220         loadmodel->synctype = ST_RAND;
3221
3222         // byteswap header
3223         header.version = LittleLong(header.version);
3224         header.filesize = LittleLong(header.filesize);
3225         header.flags = LittleLong(header.flags);
3226         header.num_text = LittleLong(header.num_text);
3227         header.ofs_text = LittleLong(header.ofs_text);
3228         header.num_meshes = LittleLong(header.num_meshes);
3229         header.ofs_meshes = LittleLong(header.ofs_meshes);
3230         header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3231         header.num_vertexes = LittleLong(header.num_vertexes);
3232         header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3233         header.num_triangles = LittleLong(header.num_triangles);
3234         header.ofs_triangles = LittleLong(header.ofs_triangles);
3235         header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3236         header.num_joints = LittleLong(header.num_joints);
3237         header.ofs_joints = LittleLong(header.ofs_joints);
3238         header.num_poses = LittleLong(header.num_poses);
3239         header.ofs_poses = LittleLong(header.ofs_poses);
3240         header.num_anims = LittleLong(header.num_anims);
3241         header.ofs_anims = LittleLong(header.ofs_anims);
3242         header.num_frames = LittleLong(header.num_frames);
3243         header.num_framechannels = LittleLong(header.num_framechannels);
3244         header.ofs_frames = LittleLong(header.ofs_frames);
3245         header.ofs_bounds = LittleLong(header.ofs_bounds);
3246         header.num_comment = LittleLong(header.num_comment);
3247         header.ofs_comment = LittleLong(header.ofs_comment);
3248         header.num_extensions = LittleLong(header.num_extensions);
3249         header.ofs_extensions = LittleLong(header.ofs_extensions);
3250
3251         if (header.version == 1)
3252         {
3253                 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3254                         pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3255                 {
3256                         Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3257                         return;
3258                 }
3259         }
3260         else
3261         {
3262                 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3263                         pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3264                 {
3265                         Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3266                         return;
3267                 }
3268         }
3269         if (pbase + header.ofs_text + header.num_text > pend ||
3270                 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3271                 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3272                 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3273                 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3274                 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3275                 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3276                 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3277                 pbase + header.ofs_comment + header.num_comment > pend)
3278         {
3279                 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3280                 return;
3281         }
3282
3283         // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3284         if (header.num_vertexarrays)
3285                 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3286         if (header.num_anims)
3287                 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3288         if (header.ofs_bounds)
3289                 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3290         if (header.num_meshes)
3291                 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3292
3293         for (i = 0;i < (int)header.num_vertexarrays;i++)
3294         {
3295                 iqmvertexarray_t va;
3296                 size_t vsize;
3297                 va.type = LittleLong(vas[i].type);
3298                 va.flags = LittleLong(vas[i].flags);
3299                 va.format = LittleLong(vas[i].format);
3300                 va.size = LittleLong(vas[i].size);
3301                 va.offset = LittleLong(vas[i].offset);
3302                 vsize = header.num_vertexes*va.size;
3303                 switch (va.format)
3304                 { 
3305                 case IQM_FLOAT: vsize *= sizeof(float); break;
3306                 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3307                 default: continue;
3308                 }
3309                 if (pbase + va.offset + vsize > pend)
3310                         continue;
3311                 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3312                 switch (va.type)
3313                 {
3314                 case IQM_POSITION:
3315                         if (va.format == IQM_FLOAT && va.size == 3)
3316                                 vposition = (const float *)(pbase + va.offset);
3317                         break;
3318                 case IQM_TEXCOORD:
3319                         if (va.format == IQM_FLOAT && va.size == 2)
3320                                 vtexcoord = (const float *)(pbase + va.offset);
3321                         break;
3322                 case IQM_NORMAL:
3323                         if (va.format == IQM_FLOAT && va.size == 3)
3324                                 vnormal = (const float *)(pbase + va.offset);
3325                         break;
3326                 case IQM_TANGENT:
3327                         if (va.format == IQM_FLOAT && va.size == 4)
3328                                 vtangent = (const float *)(pbase + va.offset);
3329                         break;
3330                 case IQM_BLENDINDEXES:
3331                         if (va.format == IQM_UBYTE && va.size == 4)
3332                                 vblendindexes = (const unsigned char *)(pbase + va.offset);
3333                         break;
3334                 case IQM_BLENDWEIGHTS:
3335                         if (va.format == IQM_UBYTE && va.size == 4)
3336                                 vblendweights = (const unsigned char *)(pbase + va.offset);
3337                         break;
3338                 case IQM_COLOR:
3339                         if (va.format == IQM_FLOAT && va.size == 4)
3340                                 vcolor4f = (const float *)(pbase + va.offset);
3341                         if (va.format == IQM_UBYTE && va.size == 4)
3342                                 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3343                         break;
3344                 }
3345         }
3346         if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3347         {
3348                 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3349                 return;
3350         }
3351
3352         text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3353
3354         loadmodel->Draw = R_Mod_Draw;
3355         loadmodel->DrawDepth = R_Mod_DrawDepth;
3356         loadmodel->DrawDebug = R_Mod_DrawDebug;
3357         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
3358         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
3359         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
3360         loadmodel->DrawLight = R_Mod_DrawLight;
3361         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3362         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3363         loadmodel->PointSuperContents = NULL;
3364         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3365
3366         // load external .skin files if present
3367         skinfiles = Mod_LoadSkinFiles();
3368         if (loadmodel->numskins < 1)
3369                 loadmodel->numskins = 1;
3370
3371         loadmodel->numframes = max(header.num_anims, 1);
3372         loadmodel->num_bones = header.num_joints;
3373         loadmodel->num_poses = max(header.num_frames, 1);
3374         loadmodel->submodelsurfaces_start = 0;
3375         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = header.num_meshes;
3376         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3377         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3378
3379         meshvertices = header.num_vertexes;
3380         meshtriangles = header.num_triangles;
3381
3382         // do most allocations as one merged chunk
3383         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) + 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));
3384         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3385         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3386         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3387         loadmodel->surfmesh.num_vertices = meshvertices;
3388         loadmodel->surfmesh.num_triangles = meshtriangles;
3389         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3390         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3391         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3392         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3393         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3394         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3395         if (vcolor4f || vcolor4ub)
3396         {
3397                 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]);
3398         }
3399         if (vblendindexes && vblendweights)
3400         {
3401                 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3402                 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3403         }
3404         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3405         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3406         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3407         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3408         if (vblendindexes && vblendweights)
3409         {
3410                 loadmodel->surfmesh.num_blends = 0;
3411                 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3412         }
3413         if (meshvertices <= 65536)
3414         {
3415                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3416         }
3417         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3418         if (vblendindexes && vblendweights)
3419                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3420
3421         for (i = 0;i < loadmodel->numskins;i++)
3422         {
3423                 loadmodel->skinscenes[i].firstframe = i;
3424                 loadmodel->skinscenes[i].framecount = 1;
3425                 loadmodel->skinscenes[i].loop = true;
3426                 loadmodel->skinscenes[i].framerate = 10;
3427         }
3428
3429         // load the bone info
3430         if (header.version == 1)
3431         {
3432                 iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3433                 if (loadmodel->num_bones)
3434                         joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3435                 for (i = 0;i < loadmodel->num_bones;i++)
3436                 {
3437                         matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3438                         joint1[i].name = LittleLong(injoint1[i].name);
3439                         joint1[i].parent = LittleLong(injoint1[i].parent);
3440                         for (j = 0;j < 3;j++)
3441                         {
3442                                 joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
3443                                 joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
3444                                 joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
3445                         }
3446                         strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3447                         loadmodel->data_bones[i].parent = joint1[i].parent;
3448                         if (loadmodel->data_bones[i].parent >= i)
3449                                 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3450                         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]);
3451                         Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3452                         if (loadmodel->data_bones[i].parent >= 0)
3453                         {
3454                                 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3455                                 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3456                                 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3457                         }
3458                         else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3459                 }
3460         }
3461         else
3462         {
3463                 iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
3464                 if (header.num_joints)
3465                         joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3466                 for (i = 0;i < loadmodel->num_bones;i++)
3467                 {
3468                         matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3469                         joint[i].name = LittleLong(injoint[i].name);
3470                         joint[i].parent = LittleLong(injoint[i].parent);
3471                         for (j = 0;j < 3;j++)
3472                         {
3473                                 joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
3474                                 joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
3475                                 joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
3476                         }
3477                         joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
3478                         strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3479                         loadmodel->data_bones[i].parent = joint[i].parent;
3480                         if (loadmodel->data_bones[i].parent >= i)
3481                                 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3482                         if (joint[i].rotation[3] > 0)
3483                                 Vector4Negate(joint[i].rotation, joint[i].rotation);
3484                         Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3485                         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]);
3486                         Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3487                         if (loadmodel->data_bones[i].parent >= 0)
3488                         {
3489                                 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3490                                 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3491                                 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3492                         }       
3493                         else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3494                 }
3495         }
3496
3497         // set up the animscenes based on the anims
3498         for (i = 0;i < (int)header.num_anims;i++)
3499         {
3500                 iqmanim_t anim;
3501                 anim.name = LittleLong(anims[i].name);
3502                 anim.first_frame = LittleLong(anims[i].first_frame);
3503                 anim.num_frames = LittleLong(anims[i].num_frames);
3504                 anim.framerate = LittleFloat(anims[i].framerate);
3505                 anim.flags = LittleLong(anims[i].flags);
3506                 strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3507                 loadmodel->animscenes[i].firstframe = anim.first_frame;
3508                 loadmodel->animscenes[i].framecount = anim.num_frames;
3509                 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3510                 loadmodel->animscenes[i].framerate = anim.framerate;
3511         }
3512         if (header.num_anims <= 0)
3513         {
3514                 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3515                 loadmodel->animscenes[0].firstframe = 0;
3516                 loadmodel->animscenes[0].framecount = 1;
3517                 loadmodel->animscenes[0].loop = true;
3518                 loadmodel->animscenes[0].framerate = 10;
3519         }
3520
3521         loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3522         if(mod_alias_force_animated.string[0])
3523                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3524
3525         biggestorigin = 0;
3526         if (header.version == 1)
3527         {
3528                 iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3529                 if (header.num_poses)
3530                         pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3531                 for (i = 0;i < (int)header.num_poses;i++)
3532                 {
3533                         float f;
3534                         pose1[i].parent = LittleLong(inpose1[i].parent);
3535                         pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
3536                         for (j = 0;j < 9;j++)
3537                         {
3538                                 pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
3539                                 pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
3540                         }
3541                         f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3542                         f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3543                         f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3544                         f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3545                         f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3546                         f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3547                 }
3548                 if (header.num_frames <= 0)
3549                 {
3550                         for (i = 0;i < loadmodel->num_bones;i++)
3551                         {
3552                                 float f;
3553                                 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3554                                 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3555                                 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3556                         }
3557                 }
3558         }
3559         else
3560         {
3561                 iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
3562                 if (header.num_poses)
3563                         pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3564                 for (i = 0;i < (int)header.num_poses;i++)
3565                 {
3566                         float f;
3567                         pose[i].parent = LittleLong(inpose[i].parent);
3568                         pose[i].channelmask = LittleLong(inpose[i].channelmask);
3569                         for (j = 0;j < 10;j++)
3570                         {
3571                                 pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
3572                                 pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
3573                         }
3574                         f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3575                         f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3576                         f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3577                         f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3578                         f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3579                         f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3580                 }
3581                 if (header.num_frames <= 0)
3582                 {
3583                         for (i = 0;i < loadmodel->num_bones;i++)
3584                         {
3585                                 float f;
3586                                 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3587                                 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3588                                 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3589                         }
3590                 }
3591         }
3592         loadmodel->num_posescale = biggestorigin / 32767.0f;
3593         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3594
3595         // load the pose data
3596         // this unaligned memory access is safe (LittleShort reads as bytes)
3597         framedata = (const unsigned short *)(pbase + header.ofs_frames);
3598         if (header.version == 1)
3599         {
3600                 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3601                 {
3602                         for (j = 0;j < (int)header.num_poses;j++, k++)
3603                         {
3604                                 float qx, qy, qz, qw;
3605                                 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));
3606                                 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));
3607                                 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));
3608                                 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3609                                 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3610                                 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3611                                 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3612                                 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3613                                 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3614                                 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3615                                 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3616                                 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3617                                 // skip scale data for now
3618                                 if(pose1[j].channelmask&64) framedata++;
3619                                 if(pose1[j].channelmask&128) framedata++;
3620                                 if(pose1[j].channelmask&256) framedata++;
3621                         }
3622                 }
3623                 if (header.num_frames <= 0)
3624                 {
3625                         for (i = 0;i < loadmodel->num_bones;i++)
3626                         {
3627                                 float qx, qy, qz, qw;
3628                                 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3629                                 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3630                                 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3631                                 qx = joint1[i].rotation[0];
3632                                 qy = joint1[i].rotation[1];
3633                                 qz = joint1[i].rotation[2];
3634                                 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3635                                 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3636                                 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3637                                 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3638                                 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3639                                 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3640                         }
3641                 }
3642         }
3643         else
3644         {
3645                 for (i = 0, k = 0;i < (int)header.num_frames;i++)       
3646                 {
3647                         for (j = 0;j < (int)header.num_poses;j++, k++)
3648                         {
3649                                 float rot[4];
3650                                 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));
3651                                 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));
3652                                 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));
3653                                 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3654                                 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3655                                 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3656                                 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3657                                 if (rot[3] > 0)
3658                                         Vector4Negate(rot, rot);
3659                                 Vector4Normalize2(rot, rot);
3660                                 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3661                                 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3662                                 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3663                                 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3664                                 // skip scale data for now
3665                                 if(pose[j].channelmask&128) framedata++;
3666                                 if(pose[j].channelmask&256) framedata++;
3667                                 if(pose[j].channelmask&512) framedata++;
3668                         }
3669                 }
3670                 if (header.num_frames <= 0)
3671                 {
3672                         for (i = 0;i < loadmodel->num_bones;i++)
3673                         {
3674                                 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3675                                 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3676                                 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3677                                 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3678                                 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3679                                 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3680                                 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3681                         }
3682                 }
3683         }
3684
3685         // load bounding box data
3686         if (header.ofs_bounds)
3687         {
3688                 float xyradius = 0, radius = 0;
3689                 VectorClear(loadmodel->normalmins);
3690                 VectorClear(loadmodel->normalmaxs);
3691                 for (i = 0; i < (int)header.num_frames;i++)
3692                 {
3693                         iqmbounds_t bound;
3694                         bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3695                         bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3696                         bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3697                         bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);                 
3698                         bound.maxs[1] = LittleFloat(bounds[i].maxs[1]); 
3699                         bound.maxs[2] = LittleFloat(bounds[i].maxs[2]); 
3700                         bound.xyradius = LittleFloat(bounds[i].xyradius);
3701                         bound.radius = LittleFloat(bounds[i].radius);
3702                         if (!i)
3703                         {
3704                                 VectorCopy(bound.mins, loadmodel->normalmins);
3705                                 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3706                         }
3707                         else
3708                         {
3709                                 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3710                                 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3711                                 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3712                                 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3713                                 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3714                                 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3715                         }
3716                         if (bound.xyradius > xyradius)
3717                                 xyradius = bound.xyradius;
3718                         if (bound.radius > radius)
3719                                 radius = bound.radius;
3720                 }
3721                 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3722                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3723                 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3724                 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3725                 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3726                 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3727                 loadmodel->radius = radius;
3728                 loadmodel->radius2 = radius * radius;
3729         }
3730
3731         // load triangle data
3732         // this unaligned memory access is safe (LittleLong reads as bytes)
3733         inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3734         outelements = loadmodel->surfmesh.data_element3i;
3735         for (i = 0;i < (int)header.num_triangles;i++)
3736         {
3737                 outelements[0] = LittleLong(inelements[0]);
3738                 outelements[1] = LittleLong(inelements[1]);
3739                 outelements[2] = LittleLong(inelements[2]);
3740                 outelements += 3;
3741                 inelements += 3;
3742         }
3743         if (loadmodel->surfmesh.data_element3s)
3744                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3745                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3746         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3747
3748         // load vertex data
3749         // this unaligned memory access is safe (LittleFloat reads as bytes)
3750         outvertex = loadmodel->surfmesh.data_vertex3f;
3751         for (i = 0;i < (int)header.num_vertexes;i++)
3752         {
3753                 outvertex[0] = LittleFloat(vposition[0]);
3754                 outvertex[1] = LittleFloat(vposition[1]);
3755                 outvertex[2] = LittleFloat(vposition[2]);
3756                 vposition += 3;
3757                 outvertex += 3;
3758         }
3759
3760         outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3761         // this unaligned memory access is safe (LittleFloat reads as bytes)
3762         for (i = 0;i < (int)header.num_vertexes;i++)
3763         {
3764                 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3765                 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3766                 vtexcoord += 2;
3767                 outtexcoord += 2;
3768         }
3769
3770         // this unaligned memory access is safe (LittleFloat reads as bytes)
3771         if(vnormal)
3772         {
3773                 outnormal = loadmodel->surfmesh.data_normal3f;
3774                 for (i = 0;i < (int)header.num_vertexes;i++)
3775                 {
3776                         outnormal[0] = LittleFloat(vnormal[0]);
3777                         outnormal[1] = LittleFloat(vnormal[1]);
3778                         outnormal[2] = LittleFloat(vnormal[2]);
3779                         vnormal += 3;
3780                         outnormal += 3;
3781                 }
3782         }
3783
3784         // this unaligned memory access is safe (LittleFloat reads as bytes)
3785         if(vnormal && vtangent)
3786         {
3787                 outnormal = loadmodel->surfmesh.data_normal3f;
3788                 outsvector = loadmodel->surfmesh.data_svector3f;
3789                 outtvector = loadmodel->surfmesh.data_tvector3f;
3790                 for (i = 0;i < (int)header.num_vertexes;i++)
3791                 {
3792                         outsvector[0] = LittleFloat(vtangent[0]);
3793                         outsvector[1] = LittleFloat(vtangent[1]);
3794                         outsvector[2] = LittleFloat(vtangent[2]);
3795                         if(LittleFloat(vtangent[3]) < 0)
3796                                 CrossProduct(outsvector, outnormal, outtvector);
3797                         else
3798                                 CrossProduct(outnormal, outsvector, outtvector);
3799                         vtangent += 4;
3800                         outnormal += 3;
3801                         outsvector += 3;
3802                         outtvector += 3;
3803                 }
3804         }
3805
3806         // this unaligned memory access is safe (all bytes)
3807         if (vblendindexes && vblendweights)
3808         {
3809                 for (i = 0; i < (int)header.num_vertexes;i++)
3810                 {
3811                         blendweights_t weights;
3812                         memcpy(weights.index, vblendindexes + i*4, 4);
3813                         memcpy(weights.influence, vblendweights + i*4, 4);
3814                         loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3815                         loadmodel->surfmesh.data_skeletalindex4ub[i*4  ] = weights.index[0];
3816                         loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3817                         loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3818                         loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3819                         loadmodel->surfmesh.data_skeletalweight4ub[i*4  ] = weights.influence[0];
3820                         loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3821                         loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3822                         loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3823                 }
3824         }
3825
3826         if (vcolor4f)
3827         {
3828                 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3829                 // this unaligned memory access is safe (LittleFloat reads as bytes)
3830                 for (i = 0;i < (int)header.num_vertexes;i++)
3831                 {
3832                         outcolor[0] = LittleFloat(vcolor4f[0]);
3833                         outcolor[1] = LittleFloat(vcolor4f[1]);
3834                         outcolor[2] = LittleFloat(vcolor4f[2]);
3835                         outcolor[3] = LittleFloat(vcolor4f[3]);
3836                         vcolor4f += 4;
3837                         outcolor += 4;
3838                 }
3839         }
3840         else if (vcolor4ub)
3841         {
3842                 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3843                 // this unaligned memory access is safe (all bytes)
3844                 for (i = 0;i < (int)header.num_vertexes;i++)
3845                 {
3846                         outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3847                         outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3848                         outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3849                         outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3850                         vcolor4ub += 4;
3851                         outcolor += 4;
3852                 }
3853         }
3854
3855         // load meshes
3856         for (i = 0;i < (int)header.num_meshes;i++)
3857         {
3858                 iqmmesh_t mesh;
3859                 msurface_t *surface;
3860
3861                 mesh.name = LittleLong(meshes[i].name);
3862                 mesh.material = LittleLong(meshes[i].material);
3863                 mesh.first_vertex = LittleLong(meshes[i].first_vertex);
3864                 mesh.num_vertexes = LittleLong(meshes[i].num_vertexes);
3865                 mesh.first_triangle = LittleLong(meshes[i].first_triangle);
3866                 mesh.num_triangles = LittleLong(meshes[i].num_triangles);
3867
3868                 loadmodel->modelsurfaces_sorted[i] = i;
3869                 surface = loadmodel->data_surfaces + i;
3870                 surface->texture = loadmodel->data_textures + i;
3871                 surface->num_firsttriangle = mesh.first_triangle;
3872                 surface->num_triangles = mesh.num_triangles;
3873                 surface->num_firstvertex = mesh.first_vertex;
3874                 surface->num_vertices = mesh.num_vertexes;
3875
3876                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
3877         }
3878
3879         Mod_FreeSkinFiles(skinfiles);
3880         Mod_MakeSortedSurfaces(loadmodel);
3881
3882         // compute all the mesh information that was not loaded from the file
3883         if (!vnormal)
3884                 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);
3885         if (!vnormal || !vtangent)
3886                 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);
3887         if (!header.ofs_bounds)
3888                 Mod_Alias_CalculateBoundingBox();
3889
3890         // Always make a BIH for the first frame, we can use it where possible.
3891         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3892         if (!loadmodel->surfmesh.isanimated)
3893         {
3894                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3895                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3896                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3897                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3898                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3899         }
3900
3901         if (joint        ) Mem_Free(joint        );joint         = NULL;
3902         if (joint1       ) Mem_Free(joint1       );joint1        = NULL;
3903         if (pose         ) Mem_Free(pose         );pose          = NULL;
3904         if (pose1        ) Mem_Free(pose1        );pose1         = NULL;
3905 }