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