]> git.xonotic.org Git - xonotic/darkplaces.git/blob - model_alias.c
Replaced some model fields and changed their purpose slightly to simplify a lot of...
[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->DrawSky = NULL;
1008         loadmodel->DrawAddWaterPlanes = NULL;
1009         loadmodel->Draw = R_Mod_Draw;
1010         loadmodel->DrawDepth = R_Mod_DrawDepth;
1011         loadmodel->DrawDebug = R_Mod_DrawDebug;
1012         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1013         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1014         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1015         loadmodel->DrawLight = R_Mod_DrawLight;
1016         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1017         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1018         // FIXME add TraceBrush!
1019         loadmodel->PointSuperContents = NULL;
1020         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1021
1022         loadmodel->num_surfaces = 1;
1023         loadmodel->submodelsurfaces_start = 0;
1024         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1025         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
1026         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1027         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1028         loadmodel->modelsurfaces_sorted[0] = 0;
1029
1030         loadmodel->numskins = LittleLong(pinmodel->numskins);
1031         BOUNDI(loadmodel->numskins,0,65536);
1032         skinwidth = LittleLong (pinmodel->skinwidth);
1033         BOUNDI(skinwidth,0,65536);
1034         skinheight = LittleLong (pinmodel->skinheight);
1035         BOUNDI(skinheight,0,65536);
1036         numverts = LittleLong(pinmodel->numverts);
1037         BOUNDI(numverts,0,65536);
1038         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
1039         BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
1040         loadmodel->numframes = LittleLong(pinmodel->numframes);
1041         BOUNDI(loadmodel->numframes,0,65536);
1042         loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
1043         BOUNDI((int)loadmodel->synctype,0,2);
1044         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1045         i = LittleLong (pinmodel->flags);
1046         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1047
1048         if (strstr(r_nolerp_list.string, loadmodel->name))
1049                 loadmodel->nolerp = true;
1050
1051         for (i = 0;i < 3;i++)
1052         {
1053                 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
1054                 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
1055         }
1056
1057         startskins = datapointer;
1058         totalskins = 0;
1059         for (i = 0;i < loadmodel->numskins;i++)
1060         {
1061                 pinskintype = (daliasskintype_t *)datapointer;
1062                 datapointer += sizeof(daliasskintype_t);
1063                 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
1064                         groupskins = 1;
1065                 else
1066                 {
1067                         pinskingroup = (daliasskingroup_t *)datapointer;
1068                         datapointer += sizeof(daliasskingroup_t);
1069                         groupskins = LittleLong(pinskingroup->numskins);
1070                         datapointer += sizeof(daliasskininterval_t) * groupskins;
1071                 }
1072
1073                 for (j = 0;j < groupskins;j++)
1074                 {
1075                         datapointer += skinwidth * skinheight;
1076                         totalskins++;
1077                 }
1078         }
1079
1080         pinstverts = (stvert_t *)datapointer;
1081         datapointer += sizeof(stvert_t) * numverts;
1082
1083         pintriangles = (dtriangle_t *)datapointer;
1084         datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
1085
1086         startframes = datapointer;
1087         loadmodel->surfmesh.num_morphframes = 0;
1088         for (i = 0;i < loadmodel->numframes;i++)
1089         {
1090                 pinframetype = (daliasframetype_t *)datapointer;
1091                 datapointer += sizeof(daliasframetype_t);
1092                 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1093                         groupframes = 1;
1094                 else
1095                 {
1096                         pinframegroup = (daliasgroup_t *)datapointer;
1097                         datapointer += sizeof(daliasgroup_t);
1098                         groupframes = LittleLong(pinframegroup->numframes);
1099                         datapointer += sizeof(daliasinterval_t) * groupframes;
1100                 }
1101
1102                 for (j = 0;j < groupframes;j++)
1103                 {
1104                         datapointer += sizeof(daliasframe_t);
1105                         datapointer += sizeof(trivertx_t) * numverts;
1106                         loadmodel->surfmesh.num_morphframes++;
1107                 }
1108         }
1109         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1110
1111         // store texture coordinates into temporary array, they will be stored
1112         // after usage is determined (triangle data)
1113         vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1114         vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1115         vertonseam = vertremap + numverts * 2;
1116
1117         scales = 1.0 / skinwidth;
1118         scalet = 1.0 / skinheight;
1119         for (i = 0;i < numverts;i++)
1120         {
1121                 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1122                 vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales;
1123                 vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet;
1124                 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1125                 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1126         }
1127
1128 // load triangle data
1129         loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1130
1131         // read the triangle elements
1132         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1133                 for (j = 0;j < 3;j++)
1134                         loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1135         // validate (note numverts is used because this is the original data)
1136         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, NULL, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1137         // now butcher the elements according to vertonseam and tri->facesfront
1138         // and then compact the vertex set to remove duplicates
1139         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1140                 if (!LittleLong(pintriangles[i].facesfront)) // backface
1141                         for (j = 0;j < 3;j++)
1142                                 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1143                                         loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1144         // count the usage
1145         // (this uses vertremap to count usage to save some memory)
1146         for (i = 0;i < numverts*2;i++)
1147                 vertremap[i] = 0;
1148         for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1149                 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1150         // build remapping table and compact array
1151         loadmodel->surfmesh.num_vertices = 0;
1152         for (i = 0;i < numverts*2;i++)
1153         {
1154                 if (vertremap[i])
1155                 {
1156                         vertremap[i] = loadmodel->surfmesh.num_vertices;
1157                         vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1158                         vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1159                         loadmodel->surfmesh.num_vertices++;
1160                 }
1161                 else
1162                         vertremap[i] = -1; // not used at all
1163         }
1164         // remap the elements to the new vertex set
1165         for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1166                 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1167         // store the texture coordinates
1168         loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1169         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1170         {
1171                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1172                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1173         }
1174
1175         // generate ushort elements array if possible
1176         if (loadmodel->surfmesh.num_vertices <= 65536)
1177                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1178         if (loadmodel->surfmesh.data_element3s)
1179                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1180                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1181
1182 // load the frames
1183         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1184         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1185         Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1186         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1187         Mod_Alias_MorphMesh_CompileFrames();
1188
1189         Mem_Free(vertst);
1190         Mem_Free(vertremap);
1191
1192         // load the skins
1193         skinfiles = Mod_LoadSkinFiles();
1194         if (skinfiles)
1195         {
1196                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1197                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1198                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1199                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1200                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1201                 Mod_FreeSkinFiles(skinfiles);
1202                 for (i = 0;i < loadmodel->numskins;i++)
1203                 {
1204                         loadmodel->skinscenes[i].firstframe = i;
1205                         loadmodel->skinscenes[i].framecount = 1;
1206                         loadmodel->skinscenes[i].loop = true;
1207                         loadmodel->skinscenes[i].framerate = 10;
1208                 }
1209         }
1210         else
1211         {
1212                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1213                 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1214                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1215                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1216                 totalskins = 0;
1217                 datapointer = startskins;
1218                 for (i = 0;i < loadmodel->numskins;i++)
1219                 {
1220                         pinskintype = (daliasskintype_t *)datapointer;
1221                         datapointer += sizeof(daliasskintype_t);
1222
1223                         if (pinskintype->type == ALIAS_SKIN_SINGLE)
1224                         {
1225                                 groupskins = 1;
1226                                 interval = 0.1f;
1227                         }
1228                         else
1229                         {
1230                                 pinskingroup = (daliasskingroup_t *)datapointer;
1231                                 datapointer += sizeof(daliasskingroup_t);
1232
1233                                 groupskins = LittleLong (pinskingroup->numskins);
1234
1235                                 pinskinintervals = (daliasskininterval_t *)datapointer;
1236                                 datapointer += sizeof(daliasskininterval_t) * groupskins;
1237
1238                                 interval = LittleFloat(pinskinintervals[0].interval);
1239                                 if (interval < 0.01f)
1240                                 {
1241                                         Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1242                                         interval = 0.1f;
1243                                 }
1244                         }
1245
1246                         dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1247                         loadmodel->skinscenes[i].firstframe = totalskins;
1248                         loadmodel->skinscenes[i].framecount = groupskins;
1249                         loadmodel->skinscenes[i].framerate = 1.0f / interval;
1250                         loadmodel->skinscenes[i].loop = true;
1251
1252                         for (j = 0;j < groupskins;j++)
1253                         {
1254                                 if (groupskins > 1)
1255                                         dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1256                                 else
1257                                         dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1258                                 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))
1259                                         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));
1260                                 datapointer += skinwidth * skinheight;
1261                                 totalskins++;
1262                         }
1263                 }
1264                 // check for skins that don't exist in the model, but do exist as external images
1265                 // (this was added because yummyluv kept pestering me about support for it)
1266                 // TODO: support shaders here?
1267                 for (;;)
1268                 {
1269                         dpsnprintf(name, sizeof(name), "%s_%i", loadmodel->name, loadmodel->numskins);
1270                         tempskinframe = R_SkinFrame_LoadExternal(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false, false);
1271                         if (!tempskinframe)
1272                                 break;
1273                         // expand the arrays to make room
1274                         tempskinscenes = loadmodel->skinscenes;
1275                         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1276                         memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1277                         Mem_Free(tempskinscenes);
1278
1279                         tempaliasskins = loadmodel->data_textures;
1280                         loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1281                         memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1282                         Mem_Free(tempaliasskins);
1283
1284                         // store the info about the new skin
1285                         Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, tempskinframe);
1286                         strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1287                         loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1288                         loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1289                         loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1290                         loadmodel->skinscenes[loadmodel->numskins].loop = true;
1291
1292                         //increase skin counts
1293                         loadmodel->num_textures++;
1294                         loadmodel->numskins++;
1295                         totalskins++;
1296
1297                         // fix up the pointers since they are pointing at the old textures array
1298                         // FIXME: this is a hack!
1299                         for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1300                                 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1301                 }
1302         }
1303
1304         surface = loadmodel->data_surfaces;
1305         surface->texture = loadmodel->data_textures;
1306         surface->num_firsttriangle = 0;
1307         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1308         surface->num_firstvertex = 0;
1309         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1310
1311         if(mod_alias_force_animated.string[0])
1312                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1313
1314         // Always make a BIH for the first frame, we can use it where possible.
1315         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1316         if (!loadmodel->surfmesh.isanimated)
1317         {
1318                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1319                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1320                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1321                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1322                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1323         }
1324
1325         // because shaders can do somewhat unexpected things, check for unusual features now
1326         for (i = 0;i < loadmodel->num_textures;i++)
1327         {
1328                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1329                         mod->DrawSky = R_Mod_DrawSky;
1330                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1331                         mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
1332         }
1333 }
1334
1335 void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend)
1336 {
1337         int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1338         float iskinwidth, iskinheight;
1339         unsigned char *data;
1340         msurface_t *surface;
1341         md2_t *pinmodel;
1342         unsigned char *base, *datapointer;
1343         md2frame_t *pinframe;
1344         char *inskin;
1345         md2triangle_t *intri;
1346         unsigned short *inst;
1347         struct md2verthash_s
1348         {
1349                 struct md2verthash_s *next;
1350                 unsigned short xyz;
1351                 unsigned short st;
1352         }
1353         *hash, **md2verthash, *md2verthashdata;
1354         skinfile_t *skinfiles;
1355
1356         pinmodel = (md2_t *)buffer;
1357         base = (unsigned char *)buffer;
1358
1359         version = LittleLong (pinmodel->version);
1360         if (version != MD2ALIAS_VERSION)
1361                 Host_Error ("%s has wrong version number (%i should be %i)",
1362                         loadmodel->name, version, MD2ALIAS_VERSION);
1363
1364         loadmodel->modeldatatypestring = "MD2";
1365
1366         loadmodel->type = mod_alias;
1367         loadmodel->DrawSky = NULL;
1368         loadmodel->DrawAddWaterPlanes = NULL;
1369         loadmodel->Draw = R_Mod_Draw;
1370         loadmodel->DrawDepth = R_Mod_DrawDepth;
1371         loadmodel->DrawDebug = R_Mod_DrawDebug;
1372         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1373         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1374         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1375         loadmodel->DrawLight = R_Mod_DrawLight;
1376         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1377         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1378         loadmodel->PointSuperContents = NULL;
1379         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1380
1381         if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1382                 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1383         if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1384                 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1385         if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1386                 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1387         if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1388                 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1389
1390         end = LittleLong(pinmodel->ofs_end);
1391         if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1392                 Host_Error ("%s is not a valid model", loadmodel->name);
1393         if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1394                 Host_Error ("%s is not a valid model", loadmodel->name);
1395         if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1396                 Host_Error ("%s is not a valid model", loadmodel->name);
1397         if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1398                 Host_Error ("%s is not a valid model", loadmodel->name);
1399         if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1400                 Host_Error ("%s is not a valid model", loadmodel->name);
1401
1402         loadmodel->numskins = LittleLong(pinmodel->num_skins);
1403         numxyz = LittleLong(pinmodel->num_xyz);
1404         numst = LittleLong(pinmodel->num_st);
1405         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1406         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1407         loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1408         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1409         skinwidth = LittleLong(pinmodel->skinwidth);
1410         skinheight = LittleLong(pinmodel->skinheight);
1411         iskinwidth = 1.0f / skinwidth;
1412         iskinheight = 1.0f / skinheight;
1413
1414         loadmodel->num_surfaces = 1;
1415         loadmodel->submodelsurfaces_start = 0;
1416         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1417         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]));
1418         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1419         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1420         loadmodel->modelsurfaces_sorted[0] = 0;
1421         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1422         loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1423         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1424
1425         loadmodel->synctype = ST_RAND;
1426
1427         // load the skins
1428         inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1429         skinfiles = Mod_LoadSkinFiles();
1430         if (skinfiles)
1431         {
1432                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1433                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1434                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1435                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1436                 Mod_FreeSkinFiles(skinfiles);
1437         }
1438         else if (loadmodel->numskins)
1439         {
1440                 // skins found (most likely not a player model)
1441                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1442                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1443                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1444                 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1445                         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);
1446         }
1447         else
1448         {
1449                 // no skins (most likely a player model)
1450                 loadmodel->numskins = 1;
1451                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1452                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1453                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1454                 Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures, loadmodel->name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing());
1455         }
1456
1457         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1458         for (i = 0;i < loadmodel->numskins;i++)
1459         {
1460                 loadmodel->skinscenes[i].firstframe = i;
1461                 loadmodel->skinscenes[i].framecount = 1;
1462                 loadmodel->skinscenes[i].loop = true;
1463                 loadmodel->skinscenes[i].framerate = 10;
1464         }
1465
1466         // load the triangles and stvert data
1467         inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1468         intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1469         md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1470         md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1471         // swap the triangle list
1472         loadmodel->surfmesh.num_vertices = 0;
1473         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1474         {
1475                 for (j = 0;j < 3;j++)
1476                 {
1477                         xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1478                         st = (unsigned short) LittleShort (intri[i].index_st[j]);
1479                         if (xyz >= numxyz)
1480                         {
1481                                 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1482                                 xyz = 0;
1483                         }
1484                         if (st >= numst)
1485                         {
1486                                 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1487                                 st = 0;
1488                         }
1489                         hashindex = (xyz * 256 + st) & 65535;
1490                         for (hash = md2verthash[hashindex];hash;hash = hash->next)
1491                                 if (hash->xyz == xyz && hash->st == st)
1492                                         break;
1493                         if (hash == NULL)
1494                         {
1495                                 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1496                                 hash->xyz = xyz;
1497                                 hash->st = st;
1498                                 hash->next = md2verthash[hashindex];
1499                                 md2verthash[hashindex] = hash;
1500                         }
1501                         loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1502                 }
1503         }
1504
1505         vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1506         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));
1507         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1508         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1509         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1510         {
1511                 int sts, stt;
1512                 hash = md2verthashdata + i;
1513                 vertremap[i] = hash->xyz;
1514                 sts = LittleShort(inst[hash->st*2+0]);
1515                 stt = LittleShort(inst[hash->st*2+1]);
1516                 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1517                 {
1518                         Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1519                         sts = 0;
1520                         stt = 0;
1521                 }
1522                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1523                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1524         }
1525
1526         Mem_Free(md2verthash);
1527         Mem_Free(md2verthashdata);
1528
1529         // generate ushort elements array if possible
1530         if (loadmodel->surfmesh.num_vertices <= 65536)
1531                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1532         if (loadmodel->surfmesh.data_element3s)
1533                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1534                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1535
1536         // load the frames
1537         datapointer = (base + LittleLong(pinmodel->ofs_frames));
1538         for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1539         {
1540                 int k;
1541                 trivertx_t *v;
1542                 trivertx_t *out;
1543                 pinframe = (md2frame_t *)datapointer;
1544                 datapointer += sizeof(md2frame_t);
1545                 // store the frame scale/translate into the appropriate array
1546                 for (j = 0;j < 3;j++)
1547                 {
1548                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1549                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1550                 }
1551                 // convert the vertices
1552                 v = (trivertx_t *)datapointer;
1553                 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1554                 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1555                         out[k] = v[vertremap[k]];
1556                 datapointer += numxyz * sizeof(trivertx_t);
1557
1558                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1559                 loadmodel->animscenes[i].firstframe = i;
1560                 loadmodel->animscenes[i].framecount = 1;
1561                 loadmodel->animscenes[i].framerate = 10;
1562                 loadmodel->animscenes[i].loop = true;
1563         }
1564
1565         Mem_Free(vertremap);
1566
1567         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1568         Mod_Alias_MorphMesh_CompileFrames();
1569         if(mod_alias_force_animated.string[0])
1570                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1571
1572         surface = loadmodel->data_surfaces;
1573         surface->texture = loadmodel->data_textures;
1574         surface->num_firsttriangle = 0;
1575         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1576         surface->num_firstvertex = 0;
1577         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1578
1579         // Always make a BIH for the first frame, we can use it where possible.
1580         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1581         if (!loadmodel->surfmesh.isanimated)
1582         {
1583                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1584                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1585                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1586                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1587                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1588         }
1589
1590         // because shaders can do somewhat unexpected things, check for unusual features now
1591         for (i = 0;i < loadmodel->num_textures;i++)
1592         {
1593                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1594                         mod->DrawSky = R_Mod_DrawSky;
1595                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1596                         mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
1597         }
1598 }
1599
1600 void Mod_IDP3_Load(model_t *mod, void *buffer, void *bufferend)
1601 {
1602         int i, j, k, version, meshvertices, meshtriangles;
1603         unsigned char *data;
1604         msurface_t *surface;
1605         md3modelheader_t *pinmodel;
1606         md3frameinfo_t *pinframe;
1607         md3mesh_t *pinmesh;
1608         md3tag_t *pintag;
1609         skinfile_t *skinfiles;
1610
1611         pinmodel = (md3modelheader_t *)buffer;
1612
1613         if (memcmp(pinmodel->identifier, "IDP3", 4))
1614                 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1615         version = LittleLong (pinmodel->version);
1616         if (version != MD3VERSION)
1617                 Host_Error ("%s has wrong version number (%i should be %i)",
1618                         loadmodel->name, version, MD3VERSION);
1619
1620         skinfiles = Mod_LoadSkinFiles();
1621         if (loadmodel->numskins < 1)
1622                 loadmodel->numskins = 1;
1623
1624         loadmodel->modeldatatypestring = "MD3";
1625
1626         loadmodel->type = mod_alias;
1627         loadmodel->DrawSky = NULL;
1628         loadmodel->DrawAddWaterPlanes = NULL;
1629         loadmodel->Draw = R_Mod_Draw;
1630         loadmodel->DrawDepth = R_Mod_DrawDepth;
1631         loadmodel->DrawDebug = R_Mod_DrawDebug;
1632         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1633         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1634         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1635         loadmodel->DrawLight = R_Mod_DrawLight;
1636         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1637         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1638         loadmodel->PointSuperContents = NULL;
1639         loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1640         loadmodel->synctype = ST_RAND;
1641         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1642         i = LittleLong (pinmodel->flags);
1643         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1644
1645         // set up some global info about the model
1646         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1647         loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1648
1649         // make skinscenes for the skins (no groups)
1650         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1651         for (i = 0;i < loadmodel->numskins;i++)
1652         {
1653                 loadmodel->skinscenes[i].firstframe = i;
1654                 loadmodel->skinscenes[i].framecount = 1;
1655                 loadmodel->skinscenes[i].loop = true;
1656                 loadmodel->skinscenes[i].framerate = 10;
1657         }
1658
1659         // load frameinfo
1660         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1661         for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1662         {
1663                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1664                 loadmodel->animscenes[i].firstframe = i;
1665                 loadmodel->animscenes[i].framecount = 1;
1666                 loadmodel->animscenes[i].framerate = 10;
1667                 loadmodel->animscenes[i].loop = true;
1668         }
1669
1670         // load tags
1671         loadmodel->num_tagframes = loadmodel->numframes;
1672         loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1673         loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1674         for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1675         {
1676                 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1677                 for (j = 0;j < 9;j++)
1678                         loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1679                 for (j = 0;j < 3;j++)
1680                         loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1681                 //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);
1682         }
1683
1684         // load meshes
1685         meshvertices = 0;
1686         meshtriangles = 0;
1687         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)))
1688         {
1689                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1690                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1691                 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1692                         Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1693                 meshvertices += LittleLong(pinmesh->num_vertices);
1694                 meshtriangles += LittleLong(pinmesh->num_triangles);
1695         }
1696
1697         loadmodel->submodelsurfaces_start = 0;
1698         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1699         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1700         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1701         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));
1702         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1703         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1704         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1705         loadmodel->surfmesh.num_vertices = meshvertices;
1706         loadmodel->surfmesh.num_triangles = meshtriangles;
1707         loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1708         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1709         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1710         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1711         loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1712         if (meshvertices <= 65536)
1713         {
1714                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1715         }
1716
1717         meshvertices = 0;
1718         meshtriangles = 0;
1719         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)))
1720         {
1721                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1722                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1723                 loadmodel->modelsurfaces_sorted[i] = i;
1724                 surface = loadmodel->data_surfaces + i;
1725                 surface->texture = loadmodel->data_textures + i;
1726                 surface->num_firsttriangle = meshtriangles;
1727                 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1728                 surface->num_firstvertex = meshvertices;
1729                 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1730                 meshvertices += surface->num_vertices;
1731                 meshtriangles += surface->num_triangles;
1732
1733                 for (j = 0;j < surface->num_triangles * 3;j++)
1734                 {
1735                         int e = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1736                         loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = e;
1737                         if (loadmodel->surfmesh.data_element3s)
1738                                 loadmodel->surfmesh.data_element3s[j + surface->num_firsttriangle * 3] = e;
1739                 }
1740                 for (j = 0;j < surface->num_vertices;j++)
1741                 {
1742                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1743                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1744                 }
1745                 for (j = 0;j < loadmodel->numframes;j++)
1746                 {
1747                         const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1748                         md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1749                         for (k = 0;k < surface->num_vertices;k++, in++, out++)
1750                         {
1751                                 out->origin[0] = LittleShort(in->origin[0]);
1752                                 out->origin[1] = LittleShort(in->origin[1]);
1753                                 out->origin[2] = LittleShort(in->origin[2]);
1754                                 out->pitch = in->pitch;
1755                                 out->yaw = in->yaw;
1756                         }
1757                 }
1758
1759                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1760
1761                 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__);
1762         }
1763         Mod_Alias_MorphMesh_CompileFrames();
1764         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1765         Mod_FreeSkinFiles(skinfiles);
1766         Mod_MakeSortedSurfaces(loadmodel);
1767         if(mod_alias_force_animated.string[0])
1768                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1769
1770         // Always make a BIH for the first frame, we can use it where possible.
1771         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1772         if (!loadmodel->surfmesh.isanimated)
1773         {
1774                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1775                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1776                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1777                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1778                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1779         }
1780
1781         // because shaders can do somewhat unexpected things, check for unusual features now
1782         for (i = 0;i < loadmodel->num_textures;i++)
1783         {
1784                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1785                         mod->DrawSky = R_Mod_DrawSky;
1786                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1787                         mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
1788         }
1789 }
1790
1791 void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend)
1792 {
1793         zymtype1header_t *pinmodel, *pheader;
1794         unsigned char *pbase;
1795         int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1796         float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1797         zymvertex_t *verts, *vertdata;
1798         zymscene_t *scene;
1799         zymbone_t *bone;
1800         char *shadername;
1801         skinfile_t *skinfiles;
1802         unsigned char *data;
1803         msurface_t *surface;
1804
1805         pinmodel = (zymtype1header_t *)buffer;
1806         pbase = (unsigned char *)buffer;
1807         if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1808                 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1809         if (BigLong(pinmodel->type) != 1)
1810                 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1811
1812         loadmodel->modeldatatypestring = "ZYM";
1813
1814         loadmodel->type = mod_alias;
1815         loadmodel->synctype = ST_RAND;
1816
1817         // byteswap header
1818         pheader = pinmodel;
1819         pheader->type = BigLong(pinmodel->type);
1820         pheader->filesize = BigLong(pinmodel->filesize);
1821         pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1822         pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1823         pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1824         pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1825         pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1826         pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1827         pheader->radius = BigFloat(pinmodel->radius);
1828         pheader->numverts = BigLong(pinmodel->numverts);
1829         pheader->numtris = BigLong(pinmodel->numtris);
1830         pheader->numshaders = BigLong(pinmodel->numshaders);
1831         pheader->numbones = BigLong(pinmodel->numbones);
1832         pheader->numscenes = BigLong(pinmodel->numscenes);
1833         pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1834         pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1835         pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1836         pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1837         pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1838         pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1839         pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1840         pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1841         pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1842         pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1843         pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1844         pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1845         pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1846         pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1847         pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1848         pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1849         pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1850         pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1851
1852         if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1853         {
1854                 Con_Printf("%s has no geometry\n", loadmodel->name);
1855                 return;
1856         }
1857         if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1858         {
1859                 Con_Printf("%s has no animations\n", loadmodel->name);
1860                 return;
1861         }
1862
1863         loadmodel->DrawSky = NULL;
1864         loadmodel->DrawAddWaterPlanes = NULL;
1865         loadmodel->Draw = R_Mod_Draw;
1866         loadmodel->DrawDepth = R_Mod_DrawDepth;
1867         loadmodel->DrawDebug = R_Mod_DrawDebug;
1868         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
1869         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
1870         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
1871         loadmodel->DrawLight = R_Mod_DrawLight;
1872         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1873         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1874         loadmodel->PointSuperContents = NULL;
1875         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1876
1877         loadmodel->numframes = pheader->numscenes;
1878         loadmodel->num_surfaces = pheader->numshaders;
1879
1880         skinfiles = Mod_LoadSkinFiles();
1881         if (loadmodel->numskins < 1)
1882                 loadmodel->numskins = 1;
1883
1884         // make skinscenes for the skins (no groups)
1885         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1886         for (i = 0;i < loadmodel->numskins;i++)
1887         {
1888                 loadmodel->skinscenes[i].firstframe = i;
1889                 loadmodel->skinscenes[i].framecount = 1;
1890                 loadmodel->skinscenes[i].loop = true;
1891                 loadmodel->skinscenes[i].framerate = 10;
1892         }
1893
1894         // model bbox
1895         // LadyHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
1896         modelradius = pheader->radius;
1897         for (i = 0;i < 3;i++)
1898         {
1899                 loadmodel->normalmins[i] = pheader->mins[i];
1900                 loadmodel->normalmaxs[i] = pheader->maxs[i];
1901                 loadmodel->rotatedmins[i] = -modelradius;
1902                 loadmodel->rotatedmaxs[i] = modelradius;
1903         }
1904         corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1905         corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1906         loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1907         if (loadmodel->yawmaxs[0] > modelradius)
1908                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1909         loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1910         loadmodel->yawmins[2] = loadmodel->normalmins[2];
1911         loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1912         loadmodel->radius = modelradius;
1913         loadmodel->radius2 = modelradius * modelradius;
1914
1915         // go through the lumps, swapping things
1916
1917         //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1918         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1919         scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1920         numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1921         for (i = 0;i < pheader->numscenes;i++)
1922         {
1923                 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1924                 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1925                 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1926                 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1927                 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1928                 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1929                         Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1930                 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1931                         Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1932                 if (loadmodel->animscenes[i].framerate < 0)
1933                         Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1934                 scene++;
1935         }
1936
1937         //zymlump_t lump_bones; // zymbone_t bone[numbones];
1938         loadmodel->num_bones = pheader->numbones;
1939         loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1940         bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1941         for (i = 0;i < pheader->numbones;i++)
1942         {
1943                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1944                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1945                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1946                 if (loadmodel->data_bones[i].parent >= i)
1947                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1948         }
1949
1950         //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1951         vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1952         bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1953         for (i = 0;i < pheader->numverts;i++)
1954         {
1955                 vertbonecounts[i] = BigLong(bonecount[i]);
1956                 if (vertbonecounts[i] != 1)
1957                         Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1958         }
1959
1960         loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1961
1962         meshvertices = pheader->numverts;
1963         meshtriangles = pheader->numtris;
1964
1965         loadmodel->submodelsurfaces_start = 0;
1966         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces;
1967         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1968         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1969         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]));
1970         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1971         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1972         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1973         loadmodel->surfmesh.num_vertices = meshvertices;
1974         loadmodel->surfmesh.num_triangles = meshtriangles;
1975         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1976         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1977         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1978         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1979         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1980         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1981         loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
1982         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
1983         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1984         loadmodel->surfmesh.num_blends = 0;
1985         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
1986         if (loadmodel->surfmesh.num_vertices <= 65536)
1987         {
1988                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
1989         }
1990         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
1991         loadmodel->surfmesh.data_blendweights = NULL;
1992
1993         //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1994         poses = (float *) (pheader->lump_poses.start + pbase);
1995         // figure out scale of model from root bone, for compatibility with old zmodel versions
1996         tempvec[0] = BigFloat(poses[0]);
1997         tempvec[1] = BigFloat(poses[1]);
1998         tempvec[2] = BigFloat(poses[2]);
1999         modelscale = VectorLength(tempvec);
2000         biggestorigin = 0;
2001         for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
2002         {
2003                 f = fabs(BigFloat(poses[i]));
2004                 biggestorigin = max(biggestorigin, f);
2005         }
2006         loadmodel->num_posescale = biggestorigin / 32767.0f;
2007         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2008         for (i = 0;i < numposes;i++)
2009         {
2010                 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
2011                 for (j = 0;j < loadmodel->num_bones;j++)
2012                 {
2013                         float pose[12];
2014                         matrix4x4_t posematrix;
2015                         for (k = 0;k < 12;k++)
2016                                 pose[k] = BigFloat(frameposes[j*12+k]);
2017                         //if (j < loadmodel->num_bones)
2018                         //      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));
2019                         // scale child bones to match the root scale
2020                         if (loadmodel->data_bones[j].parent >= 0)
2021                         {
2022                                 pose[3] *= modelscale;
2023                                 pose[7] *= modelscale;
2024                                 pose[11] *= modelscale;
2025                         }
2026                         // normalize rotation matrix
2027                         VectorNormalize(pose + 0);
2028                         VectorNormalize(pose + 4);
2029                         VectorNormalize(pose + 8);
2030                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2031                         Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2032                 }
2033         }
2034
2035         //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2036         verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2037         vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2038         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2039         // (converting from weight-blending skeletal animation to
2040         //  deformation-based skeletal animation)
2041         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2042         for (i = 0;i < loadmodel->num_bones;i++)
2043         {
2044                 float m[12];
2045                 for (k = 0;k < 12;k++)
2046                         m[k] = BigFloat(poses[i*12+k]);
2047                 if (loadmodel->data_bones[i].parent >= 0)
2048                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2049                 else
2050                         for (k = 0;k < 12;k++)
2051                                 bonepose[12*i+k] = m[k];
2052         }
2053         for (j = 0;j < pheader->numverts;j++)
2054         {
2055                 // this format really should have had a per vertexweight weight value...
2056                 // but since it does not, the weighting is completely ignored and
2057                 // only one weight is allowed per vertex
2058                 int boneindex = BigLong(vertdata[j].bonenum);
2059                 const float *m = bonepose + 12 * boneindex;
2060                 float relativeorigin[3];
2061                 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2062                 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2063                 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2064                 // transform the vertex bone weight into the base mesh
2065                 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2066                 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2067                 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2068                 // store the weight as the primary weight on this vertex
2069                 loadmodel->surfmesh.blends[j] = boneindex;
2070                 loadmodel->surfmesh.data_skeletalindex4ub[j*4  ] = boneindex;
2071                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2072                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2073                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2074                 loadmodel->surfmesh.data_skeletalweight4ub[j*4  ] = 255;
2075                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2076                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2077                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2078         }
2079         Z_Free(bonepose);
2080         // normals and tangents are calculated after elements are loaded
2081
2082         //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2083         outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2084         intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2085         for (i = 0;i < pheader->numverts;i++)
2086         {
2087                 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2088                 // flip T coordinate for OpenGL
2089                 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2090         }
2091
2092         //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2093         //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2094         //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2095
2096         //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2097         //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)
2098         // byteswap, validate, and swap winding order of tris
2099         count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2100         if (pheader->lump_render.length != count)
2101                 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2102         renderlist = (int *) (pheader->lump_render.start + pbase);
2103         renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2104         meshtriangles = 0;
2105         for (i = 0;i < loadmodel->num_surfaces;i++)
2106         {
2107                 int firstvertex, lastvertex;
2108                 if (renderlist >= renderlistend)
2109                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2110                 count = BigLong(*renderlist);renderlist++;
2111                 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2112                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2113
2114                 loadmodel->modelsurfaces_sorted[i] = i;
2115                 surface = loadmodel->data_surfaces + i;
2116                 surface->texture = loadmodel->data_textures + i;
2117                 surface->num_firsttriangle = meshtriangles;
2118                 surface->num_triangles = count;
2119                 meshtriangles += surface->num_triangles;
2120
2121                 // load the elements
2122                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2123                 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2124                 {
2125                         outelements[j*3+2] = BigLong(renderlist[0]);
2126                         outelements[j*3+1] = BigLong(renderlist[1]);
2127                         outelements[j*3+0] = BigLong(renderlist[2]);
2128                 }
2129                 // validate the elements and find the used vertex range
2130                 firstvertex = meshvertices;
2131                 lastvertex = 0;
2132                 for (j = 0;j < surface->num_triangles * 3;j++)
2133                 {
2134                         if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2135                                 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2136                         firstvertex = min(firstvertex, outelements[j]);
2137                         lastvertex = max(lastvertex, outelements[j]);
2138                 }
2139                 surface->num_firstvertex = firstvertex;
2140                 surface->num_vertices = lastvertex + 1 - firstvertex;
2141
2142                 // since zym models do not have named sections, reuse their shader
2143                 // name as the section name
2144                 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2145                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2146         }
2147         Mod_FreeSkinFiles(skinfiles);
2148         Mem_Free(vertbonecounts);
2149         Mem_Free(verts);
2150         Mod_MakeSortedSurfaces(loadmodel);
2151
2152         // compute all the mesh information that was not loaded from the file
2153         if (loadmodel->surfmesh.data_element3s)
2154                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2155                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2156         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2157         Mod_BuildBaseBonePoses();
2158         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);
2159         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);
2160         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2161         if(mod_alias_force_animated.string[0])
2162                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2163
2164         // Always make a BIH for the first frame, we can use it where possible.
2165         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2166         if (!loadmodel->surfmesh.isanimated)
2167         {
2168                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2169                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2170                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2171                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2172                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2173         }
2174
2175         // because shaders can do somewhat unexpected things, check for unusual features now
2176         for (i = 0;i < loadmodel->num_textures;i++)
2177         {
2178                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2179                         mod->DrawSky = R_Mod_DrawSky;
2180                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2181                         mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
2182         }
2183 }
2184
2185 void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend)
2186 {
2187         dpmheader_t *pheader;
2188         dpmframe_t *frames;
2189         dpmbone_t *bone;
2190         dpmmesh_t *dpmmesh;
2191         unsigned char *pbase;
2192         int i, j, k, meshvertices, meshtriangles;
2193         skinfile_t *skinfiles;
2194         unsigned char *data;
2195         float *bonepose;
2196         float biggestorigin, tempvec[3], modelscale;
2197         float f;
2198         float *poses;
2199
2200         pheader = (dpmheader_t *)buffer;
2201         pbase = (unsigned char *)buffer;
2202         if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2203                 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2204         if (BigLong(pheader->type) != 2)
2205                 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2206
2207         loadmodel->modeldatatypestring = "DPM";
2208
2209         loadmodel->type = mod_alias;
2210         loadmodel->synctype = ST_RAND;
2211
2212         // byteswap header
2213         pheader->type = BigLong(pheader->type);
2214         pheader->filesize = BigLong(pheader->filesize);
2215         pheader->mins[0] = BigFloat(pheader->mins[0]);
2216         pheader->mins[1] = BigFloat(pheader->mins[1]);
2217         pheader->mins[2] = BigFloat(pheader->mins[2]);
2218         pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2219         pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2220         pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2221         pheader->yawradius = BigFloat(pheader->yawradius);
2222         pheader->allradius = BigFloat(pheader->allradius);
2223         pheader->num_bones = BigLong(pheader->num_bones);
2224         pheader->num_meshs = BigLong(pheader->num_meshs);
2225         pheader->num_frames = BigLong(pheader->num_frames);
2226         pheader->ofs_bones = BigLong(pheader->ofs_bones);
2227         pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2228         pheader->ofs_frames = BigLong(pheader->ofs_frames);
2229
2230         if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2231         {
2232                 Con_Printf("%s has no geometry\n", loadmodel->name);
2233                 return;
2234         }
2235         if (pheader->num_frames < 1)
2236         {
2237                 Con_Printf("%s has no frames\n", loadmodel->name);
2238                 return;
2239         }
2240
2241         loadmodel->DrawSky = NULL;
2242         loadmodel->DrawAddWaterPlanes = NULL;
2243         loadmodel->Draw = R_Mod_Draw;
2244         loadmodel->DrawDepth = R_Mod_DrawDepth;
2245         loadmodel->DrawDebug = R_Mod_DrawDebug;
2246         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
2247         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
2248         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
2249         loadmodel->DrawLight = R_Mod_DrawLight;
2250         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2251         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2252         loadmodel->PointSuperContents = NULL;
2253         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2254
2255         // model bbox
2256         // LadyHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2257         for (i = 0;i < 3;i++)
2258         {
2259                 loadmodel->normalmins[i] = pheader->mins[i];
2260                 loadmodel->normalmaxs[i] = pheader->maxs[i];
2261                 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2262                 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2263                 loadmodel->rotatedmins[i] = -pheader->allradius;
2264                 loadmodel->rotatedmaxs[i] = pheader->allradius;
2265         }
2266         loadmodel->radius = pheader->allradius;
2267         loadmodel->radius2 = pheader->allradius * pheader->allradius;
2268
2269         // load external .skin files if present
2270         skinfiles = Mod_LoadSkinFiles();
2271         if (loadmodel->numskins < 1)
2272                 loadmodel->numskins = 1;
2273
2274         meshvertices = 0;
2275         meshtriangles = 0;
2276
2277         // gather combined statistics from the meshes
2278         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2279         for (i = 0;i < (int)pheader->num_meshs;i++)
2280         {
2281                 int numverts = BigLong(dpmmesh->num_verts);
2282                 meshvertices += numverts;
2283                 meshtriangles += BigLong(dpmmesh->num_tris);
2284                 dpmmesh++;
2285         }
2286
2287         loadmodel->numframes = pheader->num_frames;
2288         loadmodel->num_bones = pheader->num_bones;
2289         loadmodel->num_poses = loadmodel->numframes;
2290         loadmodel->submodelsurfaces_start = 0;
2291         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = pheader->num_meshs;
2292         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2293         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2294         // do most allocations as one merged chunk
2295         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));
2296         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2297         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2298         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2299         loadmodel->surfmesh.num_vertices = meshvertices;
2300         loadmodel->surfmesh.num_triangles = meshtriangles;
2301         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2302         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2303         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2304         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2305         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2306         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2307         loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2308         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2309         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2310         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2311         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2312         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2313         loadmodel->surfmesh.num_blends = 0;
2314         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2315         if (meshvertices <= 65536)
2316         {
2317                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2318         }
2319         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2320         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2321
2322         for (i = 0;i < loadmodel->numskins;i++)
2323         {
2324                 loadmodel->skinscenes[i].firstframe = i;
2325                 loadmodel->skinscenes[i].framecount = 1;
2326                 loadmodel->skinscenes[i].loop = true;
2327                 loadmodel->skinscenes[i].framerate = 10;
2328         }
2329
2330         // load the bone info
2331         bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2332         for (i = 0;i < loadmodel->num_bones;i++)
2333         {
2334                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2335                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2336                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2337                 if (loadmodel->data_bones[i].parent >= i)
2338                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2339         }
2340
2341         // load the frames
2342         frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2343         // figure out scale of model from root bone, for compatibility with old dpmodel versions
2344         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2345         tempvec[0] = BigFloat(poses[0]);
2346         tempvec[1] = BigFloat(poses[1]);
2347         tempvec[2] = BigFloat(poses[2]);
2348         modelscale = VectorLength(tempvec);
2349         biggestorigin = 0;
2350         for (i = 0;i < loadmodel->numframes;i++)
2351         {
2352                 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2353                 loadmodel->animscenes[i].firstframe = i;
2354                 loadmodel->animscenes[i].framecount = 1;
2355                 loadmodel->animscenes[i].loop = true;
2356                 loadmodel->animscenes[i].framerate = 10;
2357                 // load the bone poses for this frame
2358                 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2359                 for (j = 0;j < loadmodel->num_bones*12;j++)
2360                 {
2361                         f = fabs(BigFloat(poses[j]));
2362                         biggestorigin = max(biggestorigin, f);
2363                 }
2364                 // stuff not processed here: mins, maxs, yawradius, allradius
2365         }
2366         loadmodel->num_posescale = biggestorigin / 32767.0f;
2367         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2368         for (i = 0;i < loadmodel->numframes;i++)
2369         {
2370                 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2371                 for (j = 0;j < loadmodel->num_bones;j++)
2372                 {
2373                         float pose[12];
2374                         matrix4x4_t posematrix;
2375                         for (k = 0;k < 12;k++)
2376                                 pose[k] = BigFloat(frameposes[j*12+k]);
2377                         // scale child bones to match the root scale
2378                         if (loadmodel->data_bones[j].parent >= 0)
2379                         {
2380                                 pose[3] *= modelscale;
2381                                 pose[7] *= modelscale;
2382                                 pose[11] *= modelscale;
2383                         }
2384                         // normalize rotation matrix
2385                         VectorNormalize(pose + 0);
2386                         VectorNormalize(pose + 4);
2387                         VectorNormalize(pose + 8);
2388                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2389                         Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2390                 }
2391         }
2392
2393         // load the meshes now
2394         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2395         meshvertices = 0;
2396         meshtriangles = 0;
2397         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2398         // (converting from weight-blending skeletal animation to
2399         //  deformation-based skeletal animation)
2400         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2401         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2402         for (i = 0;i < loadmodel->num_bones;i++)
2403         {
2404                 float m[12];
2405                 for (k = 0;k < 12;k++)
2406                         m[k] = BigFloat(poses[i*12+k]);
2407                 if (loadmodel->data_bones[i].parent >= 0)
2408                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2409                 else
2410                         for (k = 0;k < 12;k++)
2411                                 bonepose[12*i+k] = m[k];
2412         }
2413         for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2414         {
2415                 const int *inelements;
2416                 int *outelement3i;
2417                 unsigned short *outelement3s;
2418                 const float *intexcoord;
2419                 msurface_t *surface;
2420
2421                 loadmodel->modelsurfaces_sorted[i] = i;
2422                 surface = loadmodel->data_surfaces + i;
2423                 surface->texture = loadmodel->data_textures + i;
2424                 surface->num_firsttriangle = meshtriangles;
2425                 surface->num_triangles = BigLong(dpmmesh->num_tris);
2426                 surface->num_firstvertex = meshvertices;
2427                 surface->num_vertices = BigLong(dpmmesh->num_verts);
2428                 meshvertices += surface->num_vertices;
2429                 meshtriangles += surface->num_triangles;
2430
2431                 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2432                 outelement3i = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2433                 outelement3s = loadmodel->surfmesh.data_element3s ? loadmodel->surfmesh.data_element3s + surface->num_firsttriangle * 3 : NULL;
2434                 for (j = 0;j < surface->num_triangles;j++)
2435                 {
2436                         // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2437                         outelement3i[j * 3 + 0] = surface->num_firstvertex + BigLong(inelements[j * 3 + 2]);
2438                         outelement3i[j * 3 + 1] = surface->num_firstvertex + BigLong(inelements[j * 3 + 1]);
2439                         outelement3i[j * 3 + 2] = surface->num_firstvertex + BigLong(inelements[j * 3 + 0]);
2440                         if (outelement3s)
2441                         {
2442                                 outelement3s[j * 3 + 0] = outelement3i[j * 3 + 0];
2443                                 outelement3s[j * 3 + 1] = outelement3i[j * 3 + 1];
2444                                 outelement3s[j * 3 + 2] = outelement3i[j * 3 + 2];
2445                         }
2446                 }
2447
2448                 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2449                 for (j = 0;j < surface->num_vertices*2;j++)
2450                         loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2451
2452                 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2453                 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2454                 {
2455                         int weightindex[4] = { 0, 0, 0, 0 };
2456                         float weightinfluence[4] = { 0, 0, 0, 0 };
2457                         int l;
2458                         int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2459                         data += sizeof(dpmvertex_t);
2460                         for (k = 0;k < numweights;k++)
2461                         {
2462                                 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2463                                 int boneindex = BigLong(vert->bonenum);
2464                                 const float *m = bonepose + 12 * boneindex;
2465                                 float influence = BigFloat(vert->influence);
2466                                 float relativeorigin[3], relativenormal[3];
2467                                 relativeorigin[0] = BigFloat(vert->origin[0]);
2468                                 relativeorigin[1] = BigFloat(vert->origin[1]);
2469                                 relativeorigin[2] = BigFloat(vert->origin[2]);
2470                                 relativenormal[0] = BigFloat(vert->normal[0]);
2471                                 relativenormal[1] = BigFloat(vert->normal[1]);
2472                                 relativenormal[2] = BigFloat(vert->normal[2]);
2473                                 // blend the vertex bone weights into the base mesh
2474                                 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2475                                 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2476                                 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2477                                 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2478                                 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2479                                 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2480                                 if (!k)
2481                                 {
2482                                         // store the first (and often only) weight
2483                                         weightinfluence[0] = influence;
2484                                         weightindex[0] = boneindex;
2485                                 }
2486                                 else
2487                                 {
2488                                         // sort the new weight into this vertex's weight table
2489                                         // (which only accepts up to 4 bones per vertex)
2490                                         for (l = 0;l < 4;l++)
2491                                         {
2492                                                 if (weightinfluence[l] < influence)
2493                                                 {
2494                                                         // move weaker influence weights out of the way first
2495                                                         int l2;
2496                                                         for (l2 = 3;l2 > l;l2--)
2497                                                         {
2498                                                                 weightinfluence[l2] = weightinfluence[l2-1];
2499                                                                 weightindex[l2] = weightindex[l2-1];
2500                                                         }
2501                                                         // store the new weight
2502                                                         weightinfluence[l] = influence;
2503                                                         weightindex[l] = boneindex;
2504                                                         break;
2505                                                 }
2506                                         }
2507                                 }
2508                                 data += sizeof(dpmbonevert_t);
2509                         }
2510                         loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2511                         loadmodel->surfmesh.data_skeletalindex4ub[j*4  ] = weightindex[0];
2512                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2513                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2514                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2515                         loadmodel->surfmesh.data_skeletalweight4ub[j*4  ] = (unsigned char)(weightinfluence[0]*255.0f);
2516                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2517                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2518                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2519                 }
2520
2521                 // since dpm models do not have named sections, reuse their shader name as the section name
2522                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2523
2524                 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__);
2525         }
2526         if (loadmodel->surfmesh.num_blends < meshvertices)
2527                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2528         Z_Free(bonepose);
2529         Mod_FreeSkinFiles(skinfiles);
2530         Mod_MakeSortedSurfaces(loadmodel);
2531
2532         // compute all the mesh information that was not loaded from the file
2533         Mod_BuildBaseBonePoses();
2534         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);
2535         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2536         if(mod_alias_force_animated.string[0])
2537                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2538
2539         // Always make a BIH for the first frame, we can use it where possible.
2540         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2541         if (!loadmodel->surfmesh.isanimated)
2542         {
2543                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2544                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2545                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2546                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2547                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2548         }
2549
2550         // because shaders can do somewhat unexpected things, check for unusual features now
2551         for (i = 0;i < loadmodel->num_textures;i++)
2552         {
2553                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2554                         mod->DrawSky = R_Mod_DrawSky;
2555                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2556                         mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
2557         }
2558 }
2559
2560 // no idea why PSK/PSA files contain weird quaternions but they do...
2561 #define PSKQUATNEGATIONS
2562 void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
2563 {
2564         int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2565         int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2566         fs_offset_t filesize;
2567         pskpnts_t *pnts;
2568         pskvtxw_t *vtxw;
2569         pskface_t *faces;
2570         pskmatt_t *matts;
2571         pskboneinfo_t *bones;
2572         pskrawweights_t *rawweights;
2573         //pskboneinfo_t *animbones;
2574         pskaniminfo_t *anims;
2575         pskanimkeys_t *animkeys;
2576         void *animfilebuffer, *animbuffer, *animbufferend;
2577         unsigned char *data;
2578         pskchunk_t *pchunk;
2579         skinfile_t *skinfiles;
2580         char animname[MAX_QPATH];
2581         size_t size;
2582         float biggestorigin;
2583
2584         pchunk = (pskchunk_t *)buffer;
2585         if (strcmp(pchunk->id, "ACTRHEAD"))
2586                 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2587
2588         loadmodel->modeldatatypestring = "PSK";
2589
2590         loadmodel->type = mod_alias;
2591         loadmodel->DrawSky = NULL;
2592         loadmodel->DrawAddWaterPlanes = NULL;
2593         loadmodel->Draw = R_Mod_Draw;
2594         loadmodel->DrawDepth = R_Mod_DrawDepth;
2595         loadmodel->DrawDebug = R_Mod_DrawDebug;
2596         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
2597         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
2598         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
2599         loadmodel->DrawLight = R_Mod_DrawLight;
2600         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2601         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2602         loadmodel->PointSuperContents = NULL;
2603         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2604         loadmodel->synctype = ST_RAND;
2605
2606         FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2607         strlcat(animname, ".psa", sizeof(animname));
2608         animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2609         animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2610         if (!animbuffer)
2611                 animbufferend = animbuffer;
2612
2613         numpnts = 0;
2614         pnts = NULL;
2615         numvtxw = 0;
2616         vtxw = NULL;
2617         numfaces = 0;
2618         faces = NULL;
2619         nummatts = 0;
2620         matts = NULL;
2621         numbones = 0;
2622         bones = NULL;
2623         numrawweights = 0;
2624         rawweights = NULL;
2625         numanims = 0;
2626         anims = NULL;
2627         numanimkeys = 0;
2628         animkeys = NULL;
2629
2630         while (buffer < bufferend)
2631         {
2632                 pchunk = (pskchunk_t *)buffer;
2633                 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2634                 version = LittleLong(pchunk->version);
2635                 recordsize = LittleLong(pchunk->recordsize);
2636                 numrecords = LittleLong(pchunk->numrecords);
2637                 if (developer_extra.integer)
2638                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2639                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2640                         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);
2641                 if (!strcmp(pchunk->id, "ACTRHEAD"))
2642                 {
2643                         // nothing to do
2644                 }
2645                 else if (!strcmp(pchunk->id, "PNTS0000"))
2646                 {
2647                         pskpnts_t *p;
2648                         if (recordsize != sizeof(*p))
2649                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2650                         // byteswap in place and keep the pointer
2651                         numpnts = numrecords;
2652                         pnts = (pskpnts_t *)buffer;
2653                         for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2654                         {
2655                                 p->origin[0] = LittleFloat(p->origin[0]);
2656                                 p->origin[1] = LittleFloat(p->origin[1]);
2657                                 p->origin[2] = LittleFloat(p->origin[2]);
2658                         }
2659                         buffer = p;
2660                 }
2661                 else if (!strcmp(pchunk->id, "VTXW0000"))
2662                 {
2663                         pskvtxw_t *p;
2664                         if (recordsize != sizeof(*p))
2665                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2666                         // byteswap in place and keep the pointer
2667                         numvtxw = numrecords;
2668                         vtxw = (pskvtxw_t *)buffer;
2669                         for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2670                         {
2671                                 p->pntsindex = LittleShort(p->pntsindex);
2672                                 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2673                                 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2674                                 if (p->pntsindex >= numpnts)
2675                                 {
2676                                         Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2677                                         p->pntsindex = 0;
2678                                 }
2679                         }
2680                         buffer = p;
2681                 }
2682                 else if (!strcmp(pchunk->id, "FACE0000"))
2683                 {
2684                         pskface_t *p;
2685                         if (recordsize != sizeof(*p))
2686                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2687                         // byteswap in place and keep the pointer
2688                         numfaces = numrecords;
2689                         faces = (pskface_t *)buffer;
2690                         for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2691                         {
2692                                 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2693                                 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2694                                 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2695                                 p->group = LittleLong(p->group);
2696                                 if (p->vtxwindex[0] >= numvtxw)
2697                                 {
2698                                         Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2699                                         p->vtxwindex[0] = 0;
2700                                 }
2701                                 if (p->vtxwindex[1] >= numvtxw)
2702                                 {
2703                                         Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2704                                         p->vtxwindex[1] = 0;
2705                                 }
2706                                 if (p->vtxwindex[2] >= numvtxw)
2707                                 {
2708                                         Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2709                                         p->vtxwindex[2] = 0;
2710                                 }
2711                         }
2712                         buffer = p;
2713                 }
2714                 else if (!strcmp(pchunk->id, "MATT0000"))
2715                 {
2716                         pskmatt_t *p;
2717                         if (recordsize != sizeof(*p))
2718                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2719                         // byteswap in place and keep the pointer
2720                         nummatts = numrecords;
2721                         matts = (pskmatt_t *)buffer;
2722                         for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2723                         {
2724                                 // nothing to do
2725                         }
2726                         buffer = p;
2727                 }
2728                 else if (!strcmp(pchunk->id, "REFSKELT"))
2729                 {
2730                         pskboneinfo_t *p;
2731                         if (recordsize != sizeof(*p))
2732                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2733                         // byteswap in place and keep the pointer
2734                         numbones = numrecords;
2735                         bones = (pskboneinfo_t *)buffer;
2736                         for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2737                         {
2738                                 p->numchildren = LittleLong(p->numchildren);
2739                                 p->parent = LittleLong(p->parent);
2740                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2741                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2742                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2743                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2744                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2745                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2746                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2747                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2748                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2749                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2750                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2751 #ifdef PSKQUATNEGATIONS
2752                                 if (index)
2753                                 {
2754                                         p->basepose.quat[0] *= -1;
2755                                         p->basepose.quat[1] *= -1;
2756                                         p->basepose.quat[2] *= -1;
2757                                 }
2758                                 else
2759                                 {
2760                                         p->basepose.quat[0] *=  1;
2761                                         p->basepose.quat[1] *= -1;
2762                                         p->basepose.quat[2] *=  1;
2763                                 }
2764 #endif
2765                                 if (p->parent < 0 || p->parent >= numbones)
2766                                 {
2767                                         Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2768                                         p->parent = 0;
2769                                 }
2770                         }
2771                         buffer = p;
2772                 }
2773                 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2774                 {
2775                         pskrawweights_t *p;
2776                         if (recordsize != sizeof(*p))
2777                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2778                         // byteswap in place and keep the pointer
2779                         numrawweights = numrecords;
2780                         rawweights = (pskrawweights_t *)buffer;
2781                         for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2782                         {
2783                                 p->weight = LittleFloat(p->weight);
2784                                 p->pntsindex = LittleLong(p->pntsindex);
2785                                 p->boneindex = LittleLong(p->boneindex);
2786                                 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2787                                 {
2788                                         Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2789                                         p->pntsindex = 0;
2790                                 }
2791                                 if (p->boneindex < 0 || p->boneindex >= numbones)
2792                                 {
2793                                         Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2794                                         p->boneindex = 0;
2795                                 }
2796                         }
2797                         buffer = p;
2798                 }
2799         }
2800
2801         while (animbuffer < animbufferend)
2802         {
2803                 pchunk = (pskchunk_t *)animbuffer;
2804                 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2805                 version = LittleLong(pchunk->version);
2806                 recordsize = LittleLong(pchunk->recordsize);
2807                 numrecords = LittleLong(pchunk->numrecords);
2808                 if (developer_extra.integer)
2809                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2810                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2811                         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);
2812                 if (!strcmp(pchunk->id, "ANIMHEAD"))
2813                 {
2814                         // nothing to do
2815                 }
2816                 else if (!strcmp(pchunk->id, "BONENAMES"))
2817                 {
2818                         pskboneinfo_t *p;
2819                         if (recordsize != sizeof(*p))
2820                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2821                         // byteswap in place and keep the pointer
2822                         numanimbones = numrecords;
2823                         //animbones = (pskboneinfo_t *)animbuffer;
2824                         // NOTE: supposedly psa does not need to match the psk model, the
2825                         // bones missing from the psa would simply use their base
2826                         // positions from the psk, but this is hard for me to implement
2827                         // and people can easily make animations that match.
2828                         if (numanimbones != numbones)
2829                                 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2830                         for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2831                         {
2832                                 p->numchildren = LittleLong(p->numchildren);
2833                                 p->parent = LittleLong(p->parent);
2834                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2835                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2836                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2837                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2838                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2839                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2840                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2841                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2842                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2843                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2844                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2845 #ifdef PSKQUATNEGATIONS
2846                                 if (index)
2847                                 {
2848                                         p->basepose.quat[0] *= -1;
2849                                         p->basepose.quat[1] *= -1;
2850                                         p->basepose.quat[2] *= -1;
2851                                 }
2852                                 else
2853                                 {
2854                                         p->basepose.quat[0] *=  1;
2855                                         p->basepose.quat[1] *= -1;
2856                                         p->basepose.quat[2] *=  1;
2857                                 }
2858 #endif
2859                                 if (p->parent < 0 || p->parent >= numanimbones)
2860                                 {
2861                                         Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2862                                         p->parent = 0;
2863                                 }
2864                                 // check that bones are the same as in the base
2865                                 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2866                                         Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2867                         }
2868                         animbuffer = p;
2869                 }
2870                 else if (!strcmp(pchunk->id, "ANIMINFO"))
2871                 {
2872                         pskaniminfo_t *p;
2873                         if (recordsize != sizeof(*p))
2874                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2875                         // byteswap in place and keep the pointer
2876                         numanims = numrecords;
2877                         anims = (pskaniminfo_t *)animbuffer;
2878                         for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2879                         {
2880                                 p->numbones = LittleLong(p->numbones);
2881                                 p->playtime = LittleFloat(p->playtime);
2882                                 p->fps = LittleFloat(p->fps);
2883                                 p->firstframe = LittleLong(p->firstframe);
2884                                 p->numframes = LittleLong(p->numframes);
2885                                 if (p->numbones != numbones)
2886                                         Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2887                         }
2888                         animbuffer = p;
2889                 }
2890                 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2891                 {
2892                         pskanimkeys_t *p;
2893                         if (recordsize != sizeof(*p))
2894                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2895                         numanimkeys = numrecords;
2896                         animkeys = (pskanimkeys_t *)animbuffer;
2897                         for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2898                         {
2899                                 p->origin[0] = LittleFloat(p->origin[0]);
2900                                 p->origin[1] = LittleFloat(p->origin[1]);
2901                                 p->origin[2] = LittleFloat(p->origin[2]);
2902                                 p->quat[0] = LittleFloat(p->quat[0]);
2903                                 p->quat[1] = LittleFloat(p->quat[1]);
2904                                 p->quat[2] = LittleFloat(p->quat[2]);
2905                                 p->quat[3] = LittleFloat(p->quat[3]);
2906                                 p->frametime = LittleFloat(p->frametime);
2907 #ifdef PSKQUATNEGATIONS
2908                                 if (index % numbones)
2909                                 {
2910                                         p->quat[0] *= -1;
2911                                         p->quat[1] *= -1;
2912                                         p->quat[2] *= -1;
2913                                 }
2914                                 else
2915                                 {
2916                                         p->quat[0] *=  1;
2917                                         p->quat[1] *= -1;
2918                                         p->quat[2] *=  1;
2919                                 }
2920 #endif
2921                         }
2922                         animbuffer = p;
2923                         // TODO: allocate bonepose stuff
2924                 }
2925                 else
2926                         Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2927         }
2928
2929         if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2930                 Host_Error("%s: missing required chunks", loadmodel->name);
2931
2932         if (numanims)
2933         {
2934                 loadmodel->numframes = 0;
2935                 for (index = 0;index < numanims;index++)
2936                         loadmodel->numframes += anims[index].numframes;
2937                 if (numanimkeys != numbones * loadmodel->numframes)
2938                         Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2939         }
2940         else
2941                 loadmodel->numframes = loadmodel->num_poses = 1;
2942
2943         meshvertices = numvtxw;
2944         meshtriangles = numfaces;
2945
2946         // load external .skin files if present
2947         skinfiles = Mod_LoadSkinFiles();
2948         if (loadmodel->numskins < 1)
2949                 loadmodel->numskins = 1;
2950         loadmodel->num_bones = numbones;
2951         loadmodel->num_poses = loadmodel->numframes;
2952         loadmodel->submodelsurfaces_start = 0;
2953         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = nummatts;
2954         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2955         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2956         loadmodel->surfmesh.num_vertices = meshvertices;
2957         loadmodel->surfmesh.num_triangles = meshtriangles;
2958         // do most allocations as one merged chunk
2959         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);
2960         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2961         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2962         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2963         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2964         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2965         loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2966         loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2967         loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2968         loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2969         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2970         loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2971         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2972         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2973         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2974         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2975         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2976         loadmodel->surfmesh.num_blends = 0;
2977         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2978         if (loadmodel->surfmesh.num_vertices <= 65536)
2979         {
2980                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2981         }
2982         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2983         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
2984
2985         for (i = 0;i < loadmodel->numskins;i++)
2986         {
2987                 loadmodel->skinscenes[i].firstframe = i;
2988                 loadmodel->skinscenes[i].framecount = 1;
2989                 loadmodel->skinscenes[i].loop = true;
2990                 loadmodel->skinscenes[i].framerate = 10;
2991         }
2992
2993         // create surfaces
2994         for (index = 0, i = 0;index < nummatts;index++)
2995         {
2996                 // since psk models do not have named sections, reuse their shader name as the section name
2997                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2998                 loadmodel->modelsurfaces_sorted[index] = index;
2999                 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
3000                 loadmodel->data_surfaces[index].num_firstvertex = 0;
3001                 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
3002         }
3003
3004         // copy over the vertex locations and texcoords
3005         for (index = 0;index < numvtxw;index++)
3006         {
3007                 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
3008                 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
3009                 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
3010                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
3011                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
3012         }
3013
3014         // loading the faces is complicated because we need to sort them into surfaces by mattindex
3015         for (index = 0;index < numfaces;index++)
3016                 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
3017         for (index = 0, i = 0;index < nummatts;index++)
3018         {
3019                 loadmodel->data_surfaces[index].num_firsttriangle = i;
3020                 i += loadmodel->data_surfaces[index].num_triangles;
3021                 loadmodel->data_surfaces[index].num_triangles = 0;
3022         }
3023         for (index = 0;index < numfaces;index++)
3024         {
3025                 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
3026                 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
3027                 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
3028                 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
3029         }
3030
3031         // copy over the bones
3032         for (index = 0;index < numbones;index++)
3033         {
3034                 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
3035                 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
3036                 if (loadmodel->data_bones[index].parent >= index)
3037                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
3038         }
3039
3040         // convert the basepose data
3041         if (loadmodel->num_bones)
3042         {
3043                 int boneindex;
3044                 matrix4x4_t *basebonepose;
3045                 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
3046                 matrix4x4_t bonematrix;
3047                 matrix4x4_t tempbonematrix;
3048                 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
3049                 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
3050                 {
3051                         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]);
3052                         if (loadmodel->data_bones[boneindex].parent >= 0)
3053                         {
3054                                 tempbonematrix = bonematrix;
3055                                 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3056                         }
3057                         basebonepose[boneindex] = bonematrix;
3058                         Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3059                         Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3060                 }
3061                 Mem_Free(basebonepose);
3062         }
3063
3064         // sort the psk point weights into the vertex weight tables
3065         // (which only accept up to 4 bones per vertex)
3066         for (index = 0;index < numvtxw;index++)
3067         {
3068                 int weightindex[4] = { 0, 0, 0, 0 };
3069                 float weightinfluence[4] = { 0, 0, 0, 0 };
3070                 int l;
3071                 for (j = 0;j < numrawweights;j++)
3072                 {
3073                         if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3074                         {
3075                                 int boneindex = rawweights[j].boneindex;
3076                                 float influence = rawweights[j].weight;
3077                                 for (l = 0;l < 4;l++)
3078                                 {
3079                                         if (weightinfluence[l] < influence)
3080                                         {
3081                                                 // move lower influence weights out of the way first
3082                                                 int l2;
3083                                                 for (l2 = 3;l2 > l;l2--)
3084                                                 {
3085                                                         weightinfluence[l2] = weightinfluence[l2-1];
3086                                                         weightindex[l2] = weightindex[l2-1];
3087                                                 }
3088                                                 // store the new weight
3089                                                 weightinfluence[l] = influence;
3090                                                 weightindex[l] = boneindex;
3091                                                 break;
3092                                         }
3093                                 }
3094                         }
3095                 }
3096                 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3097                 loadmodel->surfmesh.data_skeletalindex4ub[index*4  ] = weightindex[0];
3098                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3099                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3100                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3101                 loadmodel->surfmesh.data_skeletalweight4ub[index*4  ] = (unsigned char)(weightinfluence[0]*255.0f);
3102                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3103                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3104                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3105         }
3106         if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3107                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3108
3109         // set up the animscenes based on the anims
3110         if (numanims)
3111         {
3112                 for (index = 0, i = 0;index < numanims;index++)
3113                 {
3114                         for (j = 0;j < anims[index].numframes;j++, i++)
3115                         {
3116                                 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3117                                 loadmodel->animscenes[i].firstframe = i;
3118                                 loadmodel->animscenes[i].framecount = 1;
3119                                 loadmodel->animscenes[i].loop = true;
3120                                 loadmodel->animscenes[i].framerate = anims[index].fps;
3121                         }
3122                 }
3123                 // calculate the scaling value for bone origins so they can be compressed to short
3124                 biggestorigin = 0;
3125                 for (index = 0;index < numanimkeys;index++)
3126                 {
3127                         pskanimkeys_t *k = animkeys + index;
3128                         biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3129                         biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3130                         biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3131                 }
3132                 loadmodel->num_posescale = biggestorigin / 32767.0f;
3133                 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3134         
3135                 // load the poses from the animkeys
3136                 for (index = 0;index < numanimkeys;index++)
3137                 {
3138                         pskanimkeys_t *k = animkeys + index;
3139                         float quat[4];
3140                         Vector4Copy(k->quat, quat);
3141                         if (quat[3] > 0)
3142                                 Vector4Negate(quat, quat);
3143                         Vector4Normalize2(quat, quat);
3144                         // compress poses to the short[7] format for longterm storage
3145                         loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3146                         loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3147                         loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3148                         loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3149                         loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3150                         loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3151                         loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3152                 }
3153         }
3154         else
3155         {
3156                 strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3157                 loadmodel->animscenes[0].firstframe = 0;
3158                 loadmodel->animscenes[0].framecount = 1;
3159                 loadmodel->animscenes[0].loop = true;
3160                 loadmodel->animscenes[0].framerate = 10;
3161
3162                 // calculate the scaling value for bone origins so they can be compressed to short
3163                 biggestorigin = 0;
3164                 for (index = 0;index < numbones;index++)
3165                 {
3166                         pskboneinfo_t *p = bones + index;
3167                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3168                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3169                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3170                 }
3171                 loadmodel->num_posescale = biggestorigin / 32767.0f;
3172                 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3173         
3174                 // load the basepose as a frame
3175                 for (index = 0;index < numbones;index++)
3176                 {
3177                         pskboneinfo_t *p = bones + index;
3178                         float quat[4];
3179                         Vector4Copy(p->basepose.quat, quat);
3180                         if (quat[3] > 0)
3181                                 Vector4Negate(quat, quat);
3182                         Vector4Normalize2(quat, quat);
3183                         // compress poses to the short[7] format for longterm storage
3184                         loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3185                         loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3186                         loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3187                         loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3188                         loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3189                         loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3190                         loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3191                 }
3192         }
3193
3194         Mod_FreeSkinFiles(skinfiles);
3195         if (animfilebuffer)
3196                 Mem_Free(animfilebuffer);
3197         Mod_MakeSortedSurfaces(loadmodel);
3198
3199         // compute all the mesh information that was not loaded from the file
3200         // TODO: honor smoothing groups somehow?
3201         if (loadmodel->surfmesh.data_element3s)
3202                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3203                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3204         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3205         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);
3206         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);
3207         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3208         if(mod_alias_force_animated.string[0])
3209                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3210
3211         // Always make a BIH for the first frame, we can use it where possible.
3212         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3213         if (!loadmodel->surfmesh.isanimated)
3214         {
3215                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3216                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3217                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3218                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3219                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3220         }
3221
3222         // because shaders can do somewhat unexpected things, check for unusual features now
3223         for (i = 0;i < loadmodel->num_textures;i++)
3224         {
3225                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3226                         mod->DrawSky = R_Mod_DrawSky;
3227                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3228                         mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
3229         }
3230 }
3231
3232 void Mod_INTERQUAKEMODEL_Load(model_t *mod, void *buffer, void *bufferend)
3233 {
3234         unsigned char *data;
3235         const char *text;
3236         const unsigned char *pbase, *pend;
3237         iqmheader_t header;
3238         skinfile_t *skinfiles;
3239         int i, j, k, meshvertices, meshtriangles;
3240         float biggestorigin;
3241         const unsigned int *inelements;
3242         int *outelements;
3243         float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3244         // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3245         const float *vnormal = NULL;
3246         const float *vposition = NULL;
3247         const float *vtangent = NULL;
3248         const float *vtexcoord = NULL;
3249         const float *vcolor4f = NULL;
3250         const unsigned char *vblendindexes = NULL;
3251         const unsigned char *vblendweights = NULL;
3252         const unsigned char *vcolor4ub = NULL;
3253         const unsigned short *framedata = NULL;
3254         // temporary memory allocations (because the data in the file may be misaligned)
3255         iqmanim_t *anims = NULL;
3256         iqmbounds_t *bounds = NULL;
3257         iqmjoint1_t *joint1 = NULL;
3258         iqmjoint_t *joint = NULL;
3259         iqmmesh_t *meshes = NULL;
3260         iqmpose1_t *pose1 = NULL;
3261         iqmpose_t *pose = NULL;
3262         iqmvertexarray_t *vas = NULL;
3263
3264         pbase = (unsigned char *)buffer;
3265         pend = (unsigned char *)bufferend;
3266
3267         if (pbase + sizeof(iqmheader_t) > pend)
3268                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3269
3270         // copy struct (otherwise it may be misaligned)
3271         // LadyHavoc: okay it's definitely not misaligned here, but for consistency...
3272         memcpy(&header, pbase, sizeof(iqmheader_t));
3273
3274         if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3275                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3276         if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3277                 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3278
3279         loadmodel->modeldatatypestring = "IQM";
3280
3281         loadmodel->type = mod_alias;
3282         loadmodel->synctype = ST_RAND;
3283
3284         // byteswap header
3285         header.version = LittleLong(header.version);
3286         header.filesize = LittleLong(header.filesize);
3287         header.flags = LittleLong(header.flags);
3288         header.num_text = LittleLong(header.num_text);
3289         header.ofs_text = LittleLong(header.ofs_text);
3290         header.num_meshes = LittleLong(header.num_meshes);
3291         header.ofs_meshes = LittleLong(header.ofs_meshes);
3292         header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3293         header.num_vertexes = LittleLong(header.num_vertexes);
3294         header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3295         header.num_triangles = LittleLong(header.num_triangles);
3296         header.ofs_triangles = LittleLong(header.ofs_triangles);
3297         header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3298         header.num_joints = LittleLong(header.num_joints);
3299         header.ofs_joints = LittleLong(header.ofs_joints);
3300         header.num_poses = LittleLong(header.num_poses);
3301         header.ofs_poses = LittleLong(header.ofs_poses);
3302         header.num_anims = LittleLong(header.num_anims);
3303         header.ofs_anims = LittleLong(header.ofs_anims);
3304         header.num_frames = LittleLong(header.num_frames);
3305         header.num_framechannels = LittleLong(header.num_framechannels);
3306         header.ofs_frames = LittleLong(header.ofs_frames);
3307         header.ofs_bounds = LittleLong(header.ofs_bounds);
3308         header.num_comment = LittleLong(header.num_comment);
3309         header.ofs_comment = LittleLong(header.ofs_comment);
3310         header.num_extensions = LittleLong(header.num_extensions);
3311         header.ofs_extensions = LittleLong(header.ofs_extensions);
3312
3313         if (header.version == 1)
3314         {
3315                 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3316                         pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3317                 {
3318                         Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3319                         return;
3320                 }
3321         }
3322         else
3323         {
3324                 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3325                         pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3326                 {
3327                         Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3328                         return;
3329                 }
3330         }
3331         if (pbase + header.ofs_text + header.num_text > pend ||
3332                 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3333                 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3334                 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3335                 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3336                 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3337                 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3338                 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3339                 pbase + header.ofs_comment + header.num_comment > pend)
3340         {
3341                 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3342                 return;
3343         }
3344
3345         // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3346         if (header.num_vertexarrays)
3347                 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3348         if (header.num_anims)
3349                 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3350         if (header.ofs_bounds)
3351                 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3352         if (header.num_meshes)
3353                 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3354
3355         for (i = 0;i < (int)header.num_vertexarrays;i++)
3356         {
3357                 iqmvertexarray_t va;
3358                 size_t vsize;
3359                 va.type = LittleLong(vas[i].type);
3360                 va.flags = LittleLong(vas[i].flags);
3361                 va.format = LittleLong(vas[i].format);
3362                 va.size = LittleLong(vas[i].size);
3363                 va.offset = LittleLong(vas[i].offset);
3364                 vsize = header.num_vertexes*va.size;
3365                 switch (va.format)
3366                 { 
3367                 case IQM_FLOAT: vsize *= sizeof(float); break;
3368                 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3369                 default: continue;
3370                 }
3371                 if (pbase + va.offset + vsize > pend)
3372                         continue;
3373                 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3374                 switch (va.type)
3375                 {
3376                 case IQM_POSITION:
3377                         if (va.format == IQM_FLOAT && va.size == 3)
3378                                 vposition = (const float *)(pbase + va.offset);
3379                         break;
3380                 case IQM_TEXCOORD:
3381                         if (va.format == IQM_FLOAT && va.size == 2)
3382                                 vtexcoord = (const float *)(pbase + va.offset);
3383                         break;
3384                 case IQM_NORMAL:
3385                         if (va.format == IQM_FLOAT && va.size == 3)
3386                                 vnormal = (const float *)(pbase + va.offset);
3387                         break;
3388                 case IQM_TANGENT:
3389                         if (va.format == IQM_FLOAT && va.size == 4)
3390                                 vtangent = (const float *)(pbase + va.offset);
3391                         break;
3392                 case IQM_BLENDINDEXES:
3393                         if (va.format == IQM_UBYTE && va.size == 4)
3394                                 vblendindexes = (const unsigned char *)(pbase + va.offset);
3395                         break;
3396                 case IQM_BLENDWEIGHTS:
3397                         if (va.format == IQM_UBYTE && va.size == 4)
3398                                 vblendweights = (const unsigned char *)(pbase + va.offset);
3399                         break;
3400                 case IQM_COLOR:
3401                         if (va.format == IQM_FLOAT && va.size == 4)
3402                                 vcolor4f = (const float *)(pbase + va.offset);
3403                         if (va.format == IQM_UBYTE && va.size == 4)
3404                                 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3405                         break;
3406                 }
3407         }
3408         if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3409         {
3410                 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3411                 return;
3412         }
3413
3414         text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3415
3416         loadmodel->DrawSky = NULL;
3417         loadmodel->DrawAddWaterPlanes = NULL;
3418         loadmodel->Draw = R_Mod_Draw;
3419         loadmodel->DrawDepth = R_Mod_DrawDepth;
3420         loadmodel->DrawDebug = R_Mod_DrawDebug;
3421         loadmodel->DrawPrepass = R_Mod_DrawPrepass;
3422         loadmodel->CompileShadowMap = R_Mod_CompileShadowMap;
3423         loadmodel->DrawShadowMap = R_Mod_DrawShadowMap;
3424         loadmodel->DrawLight = R_Mod_DrawLight;
3425         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3426         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3427         loadmodel->PointSuperContents = NULL;
3428         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3429
3430         // load external .skin files if present
3431         skinfiles = Mod_LoadSkinFiles();
3432         if (loadmodel->numskins < 1)
3433                 loadmodel->numskins = 1;
3434
3435         loadmodel->numframes = max(header.num_anims, 1);
3436         loadmodel->num_bones = header.num_joints;
3437         loadmodel->num_poses = max(header.num_frames, 1);
3438         loadmodel->submodelsurfaces_start = 0;
3439         loadmodel->submodelsurfaces_end = loadmodel->num_surfaces = header.num_meshes;
3440         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3441         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3442
3443         meshvertices = header.num_vertexes;
3444         meshtriangles = header.num_triangles;
3445
3446         // do most allocations as one merged chunk
3447         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));
3448         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3449         loadmodel->modelsurfaces_sorted = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3450         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3451         loadmodel->surfmesh.num_vertices = meshvertices;
3452         loadmodel->surfmesh.num_triangles = meshtriangles;
3453         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3454         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3455         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3456         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3457         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3458         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3459         if (vcolor4f || vcolor4ub)
3460         {
3461                 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]);
3462         }
3463         if (vblendindexes && vblendweights)
3464         {
3465                 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3466                 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3467         }
3468         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3469         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3470         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3471         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3472         if (vblendindexes && vblendweights)
3473         {
3474                 loadmodel->surfmesh.num_blends = 0;
3475                 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3476         }
3477         if (meshvertices <= 65536)
3478         {
3479                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3480         }
3481         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3482         if (vblendindexes && vblendweights)
3483                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3484
3485         for (i = 0;i < loadmodel->numskins;i++)
3486         {
3487                 loadmodel->skinscenes[i].firstframe = i;
3488                 loadmodel->skinscenes[i].framecount = 1;
3489                 loadmodel->skinscenes[i].loop = true;
3490                 loadmodel->skinscenes[i].framerate = 10;
3491         }
3492
3493         // load the bone info
3494         if (header.version == 1)
3495         {
3496                 iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3497                 if (loadmodel->num_bones)
3498                         joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3499                 for (i = 0;i < loadmodel->num_bones;i++)
3500                 {
3501                         matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3502                         joint1[i].name = LittleLong(injoint1[i].name);
3503                         joint1[i].parent = LittleLong(injoint1[i].parent);
3504                         for (j = 0;j < 3;j++)
3505                         {
3506                                 joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
3507                                 joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
3508                                 joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
3509                         }
3510                         strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3511                         loadmodel->data_bones[i].parent = joint1[i].parent;
3512                         if (loadmodel->data_bones[i].parent >= i)
3513                                 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3514                         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]);
3515                         Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3516                         if (loadmodel->data_bones[i].parent >= 0)
3517                         {
3518                                 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3519                                 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3520                                 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3521                         }
3522                         else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3523                 }
3524         }
3525         else
3526         {
3527                 iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
3528                 if (header.num_joints)
3529                         joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3530                 for (i = 0;i < loadmodel->num_bones;i++)
3531                 {
3532                         matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3533                         joint[i].name = LittleLong(injoint[i].name);
3534                         joint[i].parent = LittleLong(injoint[i].parent);
3535                         for (j = 0;j < 3;j++)
3536                         {
3537                                 joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
3538                                 joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
3539                                 joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
3540                         }
3541                         joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
3542                         strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3543                         loadmodel->data_bones[i].parent = joint[i].parent;
3544                         if (loadmodel->data_bones[i].parent >= i)
3545                                 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3546                         if (joint[i].rotation[3] > 0)
3547                                 Vector4Negate(joint[i].rotation, joint[i].rotation);
3548                         Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3549                         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]);
3550                         Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3551                         if (loadmodel->data_bones[i].parent >= 0)
3552                         {
3553                                 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3554                                 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3555                                 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3556                         }       
3557                         else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3558                 }
3559         }
3560
3561         // set up the animscenes based on the anims
3562         for (i = 0;i < (int)header.num_anims;i++)
3563         {
3564                 iqmanim_t anim;
3565                 anim.name = LittleLong(anims[i].name);
3566                 anim.first_frame = LittleLong(anims[i].first_frame);
3567                 anim.num_frames = LittleLong(anims[i].num_frames);
3568                 anim.framerate = LittleFloat(anims[i].framerate);
3569                 anim.flags = LittleLong(anims[i].flags);
3570                 strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3571                 loadmodel->animscenes[i].firstframe = anim.first_frame;
3572                 loadmodel->animscenes[i].framecount = anim.num_frames;
3573                 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3574                 loadmodel->animscenes[i].framerate = anim.framerate;
3575         }
3576         if (header.num_anims <= 0)
3577         {
3578                 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3579                 loadmodel->animscenes[0].firstframe = 0;
3580                 loadmodel->animscenes[0].framecount = 1;
3581                 loadmodel->animscenes[0].loop = true;
3582                 loadmodel->animscenes[0].framerate = 10;
3583         }
3584
3585         loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3586         if(mod_alias_force_animated.string[0])
3587                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3588
3589         biggestorigin = 0;
3590         if (header.version == 1)
3591         {
3592                 iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3593                 if (header.num_poses)
3594                         pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3595                 for (i = 0;i < (int)header.num_poses;i++)
3596                 {
3597                         float f;
3598                         pose1[i].parent = LittleLong(inpose1[i].parent);
3599                         pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
3600                         for (j = 0;j < 9;j++)
3601                         {
3602                                 pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
3603                                 pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
3604                         }
3605                         f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3606                         f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3607                         f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3608                         f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3609                         f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3610                         f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3611                 }
3612                 if (header.num_frames <= 0)
3613                 {
3614                         for (i = 0;i < loadmodel->num_bones;i++)
3615                         {
3616                                 float f;
3617                                 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3618                                 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3619                                 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3620                         }
3621                 }
3622         }
3623         else
3624         {
3625                 iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
3626                 if (header.num_poses)
3627                         pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3628                 for (i = 0;i < (int)header.num_poses;i++)
3629                 {
3630                         float f;
3631                         pose[i].parent = LittleLong(inpose[i].parent);
3632                         pose[i].channelmask = LittleLong(inpose[i].channelmask);
3633                         for (j = 0;j < 10;j++)
3634                         {
3635                                 pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
3636                                 pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
3637                         }
3638                         f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3639                         f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3640                         f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3641                         f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3642                         f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3643                         f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3644                 }
3645                 if (header.num_frames <= 0)
3646                 {
3647                         for (i = 0;i < loadmodel->num_bones;i++)
3648                         {
3649                                 float f;
3650                                 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3651                                 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3652                                 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3653                         }
3654                 }
3655         }
3656         loadmodel->num_posescale = biggestorigin / 32767.0f;
3657         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3658
3659         // load the pose data
3660         // this unaligned memory access is safe (LittleShort reads as bytes)
3661         framedata = (const unsigned short *)(pbase + header.ofs_frames);
3662         if (header.version == 1)
3663         {
3664                 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3665                 {
3666                         for (j = 0;j < (int)header.num_poses;j++, k++)
3667                         {
3668                                 float qx, qy, qz, qw;
3669                                 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));
3670                                 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));
3671                                 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));
3672                                 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3673                                 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3674                                 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3675                                 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3676                                 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3677                                 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3678                                 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3679                                 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3680                                 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3681                                 // skip scale data for now
3682                                 if(pose1[j].channelmask&64) framedata++;
3683                                 if(pose1[j].channelmask&128) framedata++;
3684                                 if(pose1[j].channelmask&256) framedata++;
3685                         }
3686                 }
3687                 if (header.num_frames <= 0)
3688                 {
3689                         for (i = 0;i < loadmodel->num_bones;i++)
3690                         {
3691                                 float qx, qy, qz, qw;
3692                                 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3693                                 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3694                                 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3695                                 qx = joint1[i].rotation[0];
3696                                 qy = joint1[i].rotation[1];
3697                                 qz = joint1[i].rotation[2];
3698                                 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3699                                 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3700                                 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3701                                 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3702                                 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3703                                 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3704                         }
3705                 }
3706         }
3707         else
3708         {
3709                 for (i = 0, k = 0;i < (int)header.num_frames;i++)       
3710                 {
3711                         for (j = 0;j < (int)header.num_poses;j++, k++)
3712                         {
3713                                 float rot[4];
3714                                 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));
3715                                 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));
3716                                 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));
3717                                 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3718                                 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3719                                 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3720                                 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3721                                 if (rot[3] > 0)
3722                                         Vector4Negate(rot, rot);
3723                                 Vector4Normalize2(rot, rot);
3724                                 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3725                                 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3726                                 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3727                                 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3728                                 // skip scale data for now
3729                                 if(pose[j].channelmask&128) framedata++;
3730                                 if(pose[j].channelmask&256) framedata++;
3731                                 if(pose[j].channelmask&512) framedata++;
3732                         }
3733                 }
3734                 if (header.num_frames <= 0)
3735                 {
3736                         for (i = 0;i < loadmodel->num_bones;i++)
3737                         {
3738                                 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3739                                 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3740                                 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3741                                 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3742                                 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3743                                 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3744                                 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3745                         }
3746                 }
3747         }
3748
3749         // load bounding box data
3750         if (header.ofs_bounds)
3751         {
3752                 float xyradius = 0, radius = 0;
3753                 VectorClear(loadmodel->normalmins);
3754                 VectorClear(loadmodel->normalmaxs);
3755                 for (i = 0; i < (int)header.num_frames;i++)
3756                 {
3757                         iqmbounds_t bound;
3758                         bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3759                         bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3760                         bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3761                         bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);                 
3762                         bound.maxs[1] = LittleFloat(bounds[i].maxs[1]); 
3763                         bound.maxs[2] = LittleFloat(bounds[i].maxs[2]); 
3764                         bound.xyradius = LittleFloat(bounds[i].xyradius);
3765                         bound.radius = LittleFloat(bounds[i].radius);
3766                         if (!i)
3767                         {
3768                                 VectorCopy(bound.mins, loadmodel->normalmins);
3769                                 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3770                         }
3771                         else
3772                         {
3773                                 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3774                                 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3775                                 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3776                                 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3777                                 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3778                                 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3779                         }
3780                         if (bound.xyradius > xyradius)
3781                                 xyradius = bound.xyradius;
3782                         if (bound.radius > radius)
3783                                 radius = bound.radius;
3784                 }
3785                 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3786                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3787                 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3788                 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3789                 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3790                 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3791                 loadmodel->radius = radius;
3792                 loadmodel->radius2 = radius * radius;
3793         }
3794
3795         // load triangle data
3796         // this unaligned memory access is safe (LittleLong reads as bytes)
3797         inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3798         outelements = loadmodel->surfmesh.data_element3i;
3799         for (i = 0;i < (int)header.num_triangles;i++)
3800         {
3801                 outelements[0] = LittleLong(inelements[0]);
3802                 outelements[1] = LittleLong(inelements[1]);
3803                 outelements[2] = LittleLong(inelements[2]);
3804                 outelements += 3;
3805                 inelements += 3;
3806         }
3807         if (loadmodel->surfmesh.data_element3s)
3808                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3809                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3810         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3811
3812         // load vertex data
3813         // this unaligned memory access is safe (LittleFloat reads as bytes)
3814         outvertex = loadmodel->surfmesh.data_vertex3f;
3815         for (i = 0;i < (int)header.num_vertexes;i++)
3816         {
3817                 outvertex[0] = LittleFloat(vposition[0]);
3818                 outvertex[1] = LittleFloat(vposition[1]);
3819                 outvertex[2] = LittleFloat(vposition[2]);
3820                 vposition += 3;
3821                 outvertex += 3;
3822         }
3823
3824         outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3825         // this unaligned memory access is safe (LittleFloat reads as bytes)
3826         for (i = 0;i < (int)header.num_vertexes;i++)
3827         {
3828                 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3829                 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3830                 vtexcoord += 2;
3831                 outtexcoord += 2;
3832         }
3833
3834         // this unaligned memory access is safe (LittleFloat reads as bytes)
3835         if(vnormal)
3836         {
3837                 outnormal = loadmodel->surfmesh.data_normal3f;
3838                 for (i = 0;i < (int)header.num_vertexes;i++)
3839                 {
3840                         outnormal[0] = LittleFloat(vnormal[0]);
3841                         outnormal[1] = LittleFloat(vnormal[1]);
3842                         outnormal[2] = LittleFloat(vnormal[2]);
3843                         vnormal += 3;
3844                         outnormal += 3;
3845                 }
3846         }
3847
3848         // this unaligned memory access is safe (LittleFloat reads as bytes)
3849         if(vnormal && vtangent)
3850         {
3851                 outnormal = loadmodel->surfmesh.data_normal3f;
3852                 outsvector = loadmodel->surfmesh.data_svector3f;
3853                 outtvector = loadmodel->surfmesh.data_tvector3f;
3854                 for (i = 0;i < (int)header.num_vertexes;i++)
3855                 {
3856                         outsvector[0] = LittleFloat(vtangent[0]);
3857                         outsvector[1] = LittleFloat(vtangent[1]);
3858                         outsvector[2] = LittleFloat(vtangent[2]);
3859                         if(LittleFloat(vtangent[3]) < 0)
3860                                 CrossProduct(outsvector, outnormal, outtvector);
3861                         else
3862                                 CrossProduct(outnormal, outsvector, outtvector);
3863                         vtangent += 4;
3864                         outnormal += 3;
3865                         outsvector += 3;
3866                         outtvector += 3;
3867                 }
3868         }
3869
3870         // this unaligned memory access is safe (all bytes)
3871         if (vblendindexes && vblendweights)
3872         {
3873                 for (i = 0; i < (int)header.num_vertexes;i++)
3874                 {
3875                         blendweights_t weights;
3876                         memcpy(weights.index, vblendindexes + i*4, 4);
3877                         memcpy(weights.influence, vblendweights + i*4, 4);
3878                         loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3879                         loadmodel->surfmesh.data_skeletalindex4ub[i*4  ] = weights.index[0];
3880                         loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3881                         loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3882                         loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3883                         loadmodel->surfmesh.data_skeletalweight4ub[i*4  ] = weights.influence[0];
3884                         loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3885                         loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3886                         loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3887                 }
3888         }
3889
3890         if (vcolor4f)
3891         {
3892                 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3893                 // this unaligned memory access is safe (LittleFloat reads as bytes)
3894                 for (i = 0;i < (int)header.num_vertexes;i++)
3895                 {
3896                         outcolor[0] = LittleFloat(vcolor4f[0]);
3897                         outcolor[1] = LittleFloat(vcolor4f[1]);
3898                         outcolor[2] = LittleFloat(vcolor4f[2]);
3899                         outcolor[3] = LittleFloat(vcolor4f[3]);
3900                         vcolor4f += 4;
3901                         outcolor += 4;
3902                 }
3903         }
3904         else if (vcolor4ub)
3905         {
3906                 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3907                 // this unaligned memory access is safe (all bytes)
3908                 for (i = 0;i < (int)header.num_vertexes;i++)
3909                 {
3910                         outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3911                         outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3912                         outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3913                         outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3914                         vcolor4ub += 4;
3915                         outcolor += 4;
3916                 }
3917         }
3918
3919         // load meshes
3920         for (i = 0;i < (int)header.num_meshes;i++)
3921         {
3922                 iqmmesh_t mesh;
3923                 msurface_t *surface;
3924
3925                 mesh.name = LittleLong(meshes[i].name);
3926                 mesh.material = LittleLong(meshes[i].material);
3927                 mesh.first_vertex = LittleLong(meshes[i].first_vertex);
3928                 mesh.num_vertexes = LittleLong(meshes[i].num_vertexes);
3929                 mesh.first_triangle = LittleLong(meshes[i].first_triangle);
3930                 mesh.num_triangles = LittleLong(meshes[i].num_triangles);
3931
3932                 loadmodel->modelsurfaces_sorted[i] = i;
3933                 surface = loadmodel->data_surfaces + i;
3934                 surface->texture = loadmodel->data_textures + i;
3935                 surface->num_firsttriangle = mesh.first_triangle;
3936                 surface->num_triangles = mesh.num_triangles;
3937                 surface->num_firstvertex = mesh.first_vertex;
3938                 surface->num_vertices = mesh.num_vertexes;
3939
3940                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
3941         }
3942
3943         Mod_FreeSkinFiles(skinfiles);
3944         Mod_MakeSortedSurfaces(loadmodel);
3945
3946         // compute all the mesh information that was not loaded from the file
3947         if (!vnormal)
3948                 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);
3949         if (!vnormal || !vtangent)
3950                 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);
3951         if (!header.ofs_bounds)
3952                 Mod_Alias_CalculateBoundingBox();
3953
3954         // Always make a BIH for the first frame, we can use it where possible.
3955         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3956         if (!loadmodel->surfmesh.isanimated)
3957         {
3958                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3959                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3960                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3961                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3962                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3963         }
3964
3965         if (joint        ) Mem_Free(joint        );joint         = NULL;
3966         if (joint1       ) Mem_Free(joint1       );joint1        = NULL;
3967         if (pose         ) Mem_Free(pose         );pose          = NULL;
3968         if (pose1        ) Mem_Free(pose1        );pose1         = NULL;
3969
3970         // because shaders can do somewhat unexpected things, check for unusual features now
3971         for (i = 0;i < loadmodel->num_textures;i++)
3972         {
3973                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3974                         mod->DrawSky = R_Mod_DrawSky;
3975                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3976                         mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
3977         }
3978 }