]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - model_alias.c
Remove model->surfmesh.shadowmesh which was a vertex-welded version of the regular...
[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                         loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1729                 for (j = 0;j < surface->num_vertices;j++)
1730                 {
1731                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1732                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1733                 }
1734                 for (j = 0;j < loadmodel->numframes;j++)
1735                 {
1736                         const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1737                         md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1738                         for (k = 0;k < surface->num_vertices;k++, in++, out++)
1739                         {
1740                                 out->origin[0] = LittleShort(in->origin[0]);
1741                                 out->origin[1] = LittleShort(in->origin[1]);
1742                                 out->origin[2] = LittleShort(in->origin[2]);
1743                                 out->pitch = in->pitch;
1744                                 out->yaw = in->yaw;
1745                         }
1746                 }
1747
1748                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1749
1750                 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__);
1751         }
1752         if (loadmodel->surfmesh.data_element3s)
1753                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1754                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1755         Mod_Alias_MorphMesh_CompileFrames();
1756         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1757         Mod_FreeSkinFiles(skinfiles);
1758         Mod_MakeSortedSurfaces(loadmodel);
1759         if(mod_alias_force_animated.string[0])
1760                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1761
1762         // Always make a BIH for the first frame, we can use it where possible.
1763         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1764         if (!loadmodel->surfmesh.isanimated)
1765         {
1766                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1767                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1768                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1769                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1770                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1771         }
1772
1773         // because shaders can do somewhat unexpected things, check for unusual features now
1774         for (i = 0;i < loadmodel->num_textures;i++)
1775         {
1776                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1777                         mod->DrawSky = R_Q1BSP_DrawSky;
1778                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1779                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1780         }
1781 }
1782
1783 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1784 {
1785         zymtype1header_t *pinmodel, *pheader;
1786         unsigned char *pbase;
1787         int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1788         float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1789         zymvertex_t *verts, *vertdata;
1790         zymscene_t *scene;
1791         zymbone_t *bone;
1792         char *shadername;
1793         skinfile_t *skinfiles;
1794         unsigned char *data;
1795         msurface_t *surface;
1796
1797         pinmodel = (zymtype1header_t *)buffer;
1798         pbase = (unsigned char *)buffer;
1799         if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1800                 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1801         if (BigLong(pinmodel->type) != 1)
1802                 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1803
1804         loadmodel->modeldatatypestring = "ZYM";
1805
1806         loadmodel->type = mod_alias;
1807         loadmodel->synctype = ST_RAND;
1808
1809         // byteswap header
1810         pheader = pinmodel;
1811         pheader->type = BigLong(pinmodel->type);
1812         pheader->filesize = BigLong(pinmodel->filesize);
1813         pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1814         pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1815         pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1816         pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1817         pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1818         pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1819         pheader->radius = BigFloat(pinmodel->radius);
1820         pheader->numverts = BigLong(pinmodel->numverts);
1821         pheader->numtris = BigLong(pinmodel->numtris);
1822         pheader->numshaders = BigLong(pinmodel->numshaders);
1823         pheader->numbones = BigLong(pinmodel->numbones);
1824         pheader->numscenes = BigLong(pinmodel->numscenes);
1825         pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1826         pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1827         pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1828         pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1829         pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1830         pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1831         pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1832         pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1833         pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1834         pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1835         pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1836         pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1837         pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1838         pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1839         pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1840         pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1841         pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1842         pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1843
1844         if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1845         {
1846                 Con_Printf("%s has no geometry\n", loadmodel->name);
1847                 return;
1848         }
1849         if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1850         {
1851                 Con_Printf("%s has no animations\n", loadmodel->name);
1852                 return;
1853         }
1854
1855         loadmodel->DrawSky = NULL;
1856         loadmodel->DrawAddWaterPlanes = NULL;
1857         loadmodel->Draw = R_Q1BSP_Draw;
1858         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1859         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1860         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1861         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1862         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1863         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1864         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1865         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1866         loadmodel->PointSuperContents = NULL;
1867         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1868
1869         loadmodel->numframes = pheader->numscenes;
1870         loadmodel->num_surfaces = pheader->numshaders;
1871
1872         skinfiles = Mod_LoadSkinFiles();
1873         if (loadmodel->numskins < 1)
1874                 loadmodel->numskins = 1;
1875
1876         // make skinscenes for the skins (no groups)
1877         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1878         for (i = 0;i < loadmodel->numskins;i++)
1879         {
1880                 loadmodel->skinscenes[i].firstframe = i;
1881                 loadmodel->skinscenes[i].framecount = 1;
1882                 loadmodel->skinscenes[i].loop = true;
1883                 loadmodel->skinscenes[i].framerate = 10;
1884         }
1885
1886         // model bbox
1887         // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
1888         modelradius = pheader->radius;
1889         for (i = 0;i < 3;i++)
1890         {
1891                 loadmodel->normalmins[i] = pheader->mins[i];
1892                 loadmodel->normalmaxs[i] = pheader->maxs[i];
1893                 loadmodel->rotatedmins[i] = -modelradius;
1894                 loadmodel->rotatedmaxs[i] = modelradius;
1895         }
1896         corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1897         corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1898         loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1899         if (loadmodel->yawmaxs[0] > modelradius)
1900                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1901         loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1902         loadmodel->yawmins[2] = loadmodel->normalmins[2];
1903         loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1904         loadmodel->radius = modelradius;
1905         loadmodel->radius2 = modelradius * modelradius;
1906
1907         // go through the lumps, swapping things
1908
1909         //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1910         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1911         scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1912         numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1913         for (i = 0;i < pheader->numscenes;i++)
1914         {
1915                 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1916                 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1917                 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1918                 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1919                 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1920                 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1921                         Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1922                 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1923                         Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1924                 if (loadmodel->animscenes[i].framerate < 0)
1925                         Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1926                 scene++;
1927         }
1928
1929         //zymlump_t lump_bones; // zymbone_t bone[numbones];
1930         loadmodel->num_bones = pheader->numbones;
1931         loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1932         bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1933         for (i = 0;i < pheader->numbones;i++)
1934         {
1935                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1936                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1937                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1938                 if (loadmodel->data_bones[i].parent >= i)
1939                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1940         }
1941
1942         //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1943         vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1944         bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1945         for (i = 0;i < pheader->numverts;i++)
1946         {
1947                 vertbonecounts[i] = BigLong(bonecount[i]);
1948                 if (vertbonecounts[i] != 1)
1949                         Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1950         }
1951
1952         loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1953
1954         meshvertices = pheader->numverts;
1955         meshtriangles = pheader->numtris;
1956
1957         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1958         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1959         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1960         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]));
1961         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1962         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1963         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1964         loadmodel->surfmesh.num_vertices = meshvertices;
1965         loadmodel->surfmesh.num_triangles = meshtriangles;
1966         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1967         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1968         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1969         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1970         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1971         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1972         loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
1973         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
1974         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1975         loadmodel->surfmesh.num_blends = 0;
1976         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
1977         if (loadmodel->surfmesh.num_vertices <= 65536)
1978         {
1979                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
1980         }
1981         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
1982         loadmodel->surfmesh.data_blendweights = NULL;
1983
1984         //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1985         poses = (float *) (pheader->lump_poses.start + pbase);
1986         // figure out scale of model from root bone, for compatibility with old zmodel versions
1987         tempvec[0] = BigFloat(poses[0]);
1988         tempvec[1] = BigFloat(poses[1]);
1989         tempvec[2] = BigFloat(poses[2]);
1990         modelscale = VectorLength(tempvec);
1991         biggestorigin = 0;
1992         for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
1993         {
1994                 f = fabs(BigFloat(poses[i]));
1995                 biggestorigin = max(biggestorigin, f);
1996         }
1997         loadmodel->num_posescale = biggestorigin / 32767.0f;
1998         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
1999         for (i = 0;i < numposes;i++)
2000         {
2001                 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
2002                 for (j = 0;j < loadmodel->num_bones;j++)
2003                 {
2004                         float pose[12];
2005                         matrix4x4_t posematrix;
2006                         for (k = 0;k < 12;k++)
2007                                 pose[k] = BigFloat(frameposes[j*12+k]);
2008                         //if (j < loadmodel->num_bones)
2009                         //      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));
2010                         // scale child bones to match the root scale
2011                         if (loadmodel->data_bones[j].parent >= 0)
2012                         {
2013                                 pose[3] *= modelscale;
2014                                 pose[7] *= modelscale;
2015                                 pose[11] *= modelscale;
2016                         }
2017                         // normalize rotation matrix
2018                         VectorNormalize(pose + 0);
2019                         VectorNormalize(pose + 4);
2020                         VectorNormalize(pose + 8);
2021                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2022                         Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2023                 }
2024         }
2025
2026         //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2027         verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2028         vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2029         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2030         // (converting from weight-blending skeletal animation to
2031         //  deformation-based skeletal animation)
2032         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2033         for (i = 0;i < loadmodel->num_bones;i++)
2034         {
2035                 float m[12];
2036                 for (k = 0;k < 12;k++)
2037                         m[k] = BigFloat(poses[i*12+k]);
2038                 if (loadmodel->data_bones[i].parent >= 0)
2039                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2040                 else
2041                         for (k = 0;k < 12;k++)
2042                                 bonepose[12*i+k] = m[k];
2043         }
2044         for (j = 0;j < pheader->numverts;j++)
2045         {
2046                 // this format really should have had a per vertexweight weight value...
2047                 // but since it does not, the weighting is completely ignored and
2048                 // only one weight is allowed per vertex
2049                 int boneindex = BigLong(vertdata[j].bonenum);
2050                 const float *m = bonepose + 12 * boneindex;
2051                 float relativeorigin[3];
2052                 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2053                 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2054                 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2055                 // transform the vertex bone weight into the base mesh
2056                 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2057                 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2058                 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2059                 // store the weight as the primary weight on this vertex
2060                 loadmodel->surfmesh.blends[j] = boneindex;
2061                 loadmodel->surfmesh.data_skeletalindex4ub[j*4  ] = boneindex;
2062                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2063                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2064                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2065                 loadmodel->surfmesh.data_skeletalweight4ub[j*4  ] = 255;
2066                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2067                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2068                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2069         }
2070         Z_Free(bonepose);
2071         // normals and tangents are calculated after elements are loaded
2072
2073         //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2074         outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2075         intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2076         for (i = 0;i < pheader->numverts;i++)
2077         {
2078                 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2079                 // flip T coordinate for OpenGL
2080                 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2081         }
2082
2083         //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2084         //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2085         //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2086
2087         //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2088         //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)
2089         // byteswap, validate, and swap winding order of tris
2090         count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2091         if (pheader->lump_render.length != count)
2092                 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2093         renderlist = (int *) (pheader->lump_render.start + pbase);
2094         renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2095         meshtriangles = 0;
2096         for (i = 0;i < loadmodel->num_surfaces;i++)
2097         {
2098                 int firstvertex, lastvertex;
2099                 if (renderlist >= renderlistend)
2100                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2101                 count = BigLong(*renderlist);renderlist++;
2102                 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2103                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2104
2105                 loadmodel->sortedmodelsurfaces[i] = i;
2106                 surface = loadmodel->data_surfaces + i;
2107                 surface->texture = loadmodel->data_textures + i;
2108                 surface->num_firsttriangle = meshtriangles;
2109                 surface->num_triangles = count;
2110                 meshtriangles += surface->num_triangles;
2111
2112                 // load the elements
2113                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2114                 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2115                 {
2116                         outelements[j*3+2] = BigLong(renderlist[0]);
2117                         outelements[j*3+1] = BigLong(renderlist[1]);
2118                         outelements[j*3+0] = BigLong(renderlist[2]);
2119                 }
2120                 // validate the elements and find the used vertex range
2121                 firstvertex = meshvertices;
2122                 lastvertex = 0;
2123                 for (j = 0;j < surface->num_triangles * 3;j++)
2124                 {
2125                         if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2126                                 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2127                         firstvertex = min(firstvertex, outelements[j]);
2128                         lastvertex = max(lastvertex, outelements[j]);
2129                 }
2130                 surface->num_firstvertex = firstvertex;
2131                 surface->num_vertices = lastvertex + 1 - firstvertex;
2132
2133                 // since zym models do not have named sections, reuse their shader
2134                 // name as the section name
2135                 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2136                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2137         }
2138         Mod_FreeSkinFiles(skinfiles);
2139         Mem_Free(vertbonecounts);
2140         Mem_Free(verts);
2141         Mod_MakeSortedSurfaces(loadmodel);
2142
2143         // compute all the mesh information that was not loaded from the file
2144         if (loadmodel->surfmesh.data_element3s)
2145                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2146                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2147         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2148         Mod_BuildBaseBonePoses();
2149         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);
2150         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);
2151         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2152         if(mod_alias_force_animated.string[0])
2153                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2154
2155         // Always make a BIH for the first frame, we can use it where possible.
2156         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2157         if (!loadmodel->surfmesh.isanimated)
2158         {
2159                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2160                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2161                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2162                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2163                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2164         }
2165
2166         // because shaders can do somewhat unexpected things, check for unusual features now
2167         for (i = 0;i < loadmodel->num_textures;i++)
2168         {
2169                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2170                         mod->DrawSky = R_Q1BSP_DrawSky;
2171                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2172                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2173         }
2174 }
2175
2176 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2177 {
2178         dpmheader_t *pheader;
2179         dpmframe_t *frames;
2180         dpmbone_t *bone;
2181         dpmmesh_t *dpmmesh;
2182         unsigned char *pbase;
2183         int i, j, k, meshvertices, meshtriangles;
2184         skinfile_t *skinfiles;
2185         unsigned char *data;
2186         float *bonepose;
2187         float biggestorigin, tempvec[3], modelscale;
2188         float f;
2189         float *poses;
2190
2191         pheader = (dpmheader_t *)buffer;
2192         pbase = (unsigned char *)buffer;
2193         if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2194                 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2195         if (BigLong(pheader->type) != 2)
2196                 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2197
2198         loadmodel->modeldatatypestring = "DPM";
2199
2200         loadmodel->type = mod_alias;
2201         loadmodel->synctype = ST_RAND;
2202
2203         // byteswap header
2204         pheader->type = BigLong(pheader->type);
2205         pheader->filesize = BigLong(pheader->filesize);
2206         pheader->mins[0] = BigFloat(pheader->mins[0]);
2207         pheader->mins[1] = BigFloat(pheader->mins[1]);
2208         pheader->mins[2] = BigFloat(pheader->mins[2]);
2209         pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2210         pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2211         pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2212         pheader->yawradius = BigFloat(pheader->yawradius);
2213         pheader->allradius = BigFloat(pheader->allradius);
2214         pheader->num_bones = BigLong(pheader->num_bones);
2215         pheader->num_meshs = BigLong(pheader->num_meshs);
2216         pheader->num_frames = BigLong(pheader->num_frames);
2217         pheader->ofs_bones = BigLong(pheader->ofs_bones);
2218         pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2219         pheader->ofs_frames = BigLong(pheader->ofs_frames);
2220
2221         if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2222         {
2223                 Con_Printf("%s has no geometry\n", loadmodel->name);
2224                 return;
2225         }
2226         if (pheader->num_frames < 1)
2227         {
2228                 Con_Printf("%s has no frames\n", loadmodel->name);
2229                 return;
2230         }
2231
2232         loadmodel->DrawSky = NULL;
2233         loadmodel->DrawAddWaterPlanes = NULL;
2234         loadmodel->Draw = R_Q1BSP_Draw;
2235         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2236         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2237         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2238         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2239         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2240         loadmodel->DrawLight = R_Q1BSP_DrawLight;
2241         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2242         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2243         loadmodel->PointSuperContents = NULL;
2244         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2245
2246         // model bbox
2247         // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2248         for (i = 0;i < 3;i++)
2249         {
2250                 loadmodel->normalmins[i] = pheader->mins[i];
2251                 loadmodel->normalmaxs[i] = pheader->maxs[i];
2252                 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2253                 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2254                 loadmodel->rotatedmins[i] = -pheader->allradius;
2255                 loadmodel->rotatedmaxs[i] = pheader->allradius;
2256         }
2257         loadmodel->radius = pheader->allradius;
2258         loadmodel->radius2 = pheader->allradius * pheader->allradius;
2259
2260         // load external .skin files if present
2261         skinfiles = Mod_LoadSkinFiles();
2262         if (loadmodel->numskins < 1)
2263                 loadmodel->numskins = 1;
2264
2265         meshvertices = 0;
2266         meshtriangles = 0;
2267
2268         // gather combined statistics from the meshes
2269         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2270         for (i = 0;i < (int)pheader->num_meshs;i++)
2271         {
2272                 int numverts = BigLong(dpmmesh->num_verts);
2273                 meshvertices += numverts;
2274                 meshtriangles += BigLong(dpmmesh->num_tris);
2275                 dpmmesh++;
2276         }
2277
2278         loadmodel->numframes = pheader->num_frames;
2279         loadmodel->num_bones = pheader->num_bones;
2280         loadmodel->num_poses = loadmodel->numframes;
2281         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
2282         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2283         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2284         // do most allocations as one merged chunk
2285         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));
2286         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2287         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2288         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2289         loadmodel->surfmesh.num_vertices = meshvertices;
2290         loadmodel->surfmesh.num_triangles = meshtriangles;
2291         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2292         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2293         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2294         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2295         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2296         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2297         loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2298         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2299         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2300         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2301         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2302         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2303         loadmodel->surfmesh.num_blends = 0;
2304         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2305         if (meshvertices <= 65536)
2306         {
2307                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2308         }
2309         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2310         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2311
2312         for (i = 0;i < loadmodel->numskins;i++)
2313         {
2314                 loadmodel->skinscenes[i].firstframe = i;
2315                 loadmodel->skinscenes[i].framecount = 1;
2316                 loadmodel->skinscenes[i].loop = true;
2317                 loadmodel->skinscenes[i].framerate = 10;
2318         }
2319
2320         // load the bone info
2321         bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2322         for (i = 0;i < loadmodel->num_bones;i++)
2323         {
2324                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2325                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2326                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2327                 if (loadmodel->data_bones[i].parent >= i)
2328                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2329         }
2330
2331         // load the frames
2332         frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2333         // figure out scale of model from root bone, for compatibility with old dpmodel versions
2334         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2335         tempvec[0] = BigFloat(poses[0]);
2336         tempvec[1] = BigFloat(poses[1]);
2337         tempvec[2] = BigFloat(poses[2]);
2338         modelscale = VectorLength(tempvec);
2339         biggestorigin = 0;
2340         for (i = 0;i < loadmodel->numframes;i++)
2341         {
2342                 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2343                 loadmodel->animscenes[i].firstframe = i;
2344                 loadmodel->animscenes[i].framecount = 1;
2345                 loadmodel->animscenes[i].loop = true;
2346                 loadmodel->animscenes[i].framerate = 10;
2347                 // load the bone poses for this frame
2348                 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2349                 for (j = 0;j < loadmodel->num_bones*12;j++)
2350                 {
2351                         f = fabs(BigFloat(poses[j]));
2352                         biggestorigin = max(biggestorigin, f);
2353                 }
2354                 // stuff not processed here: mins, maxs, yawradius, allradius
2355         }
2356         loadmodel->num_posescale = biggestorigin / 32767.0f;
2357         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2358         for (i = 0;i < loadmodel->numframes;i++)
2359         {
2360                 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2361                 for (j = 0;j < loadmodel->num_bones;j++)
2362                 {
2363                         float pose[12];
2364                         matrix4x4_t posematrix;
2365                         for (k = 0;k < 12;k++)
2366                                 pose[k] = BigFloat(frameposes[j*12+k]);
2367                         // scale child bones to match the root scale
2368                         if (loadmodel->data_bones[j].parent >= 0)
2369                         {
2370                                 pose[3] *= modelscale;
2371                                 pose[7] *= modelscale;
2372                                 pose[11] *= modelscale;
2373                         }
2374                         // normalize rotation matrix
2375                         VectorNormalize(pose + 0);
2376                         VectorNormalize(pose + 4);
2377                         VectorNormalize(pose + 8);
2378                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2379                         Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2380                 }
2381         }
2382
2383         // load the meshes now
2384         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2385         meshvertices = 0;
2386         meshtriangles = 0;
2387         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2388         // (converting from weight-blending skeletal animation to
2389         //  deformation-based skeletal animation)
2390         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2391         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2392         for (i = 0;i < loadmodel->num_bones;i++)
2393         {
2394                 float m[12];
2395                 for (k = 0;k < 12;k++)
2396                         m[k] = BigFloat(poses[i*12+k]);
2397                 if (loadmodel->data_bones[i].parent >= 0)
2398                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2399                 else
2400                         for (k = 0;k < 12;k++)
2401                                 bonepose[12*i+k] = m[k];
2402         }
2403         for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2404         {
2405                 const int *inelements;
2406                 int *outelements;
2407                 const float *intexcoord;
2408                 msurface_t *surface;
2409
2410                 loadmodel->sortedmodelsurfaces[i] = i;
2411                 surface = loadmodel->data_surfaces + i;
2412                 surface->texture = loadmodel->data_textures + i;
2413                 surface->num_firsttriangle = meshtriangles;
2414                 surface->num_triangles = BigLong(dpmmesh->num_tris);
2415                 surface->num_firstvertex = meshvertices;
2416                 surface->num_vertices = BigLong(dpmmesh->num_verts);
2417                 meshvertices += surface->num_vertices;
2418                 meshtriangles += surface->num_triangles;
2419
2420                 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2421                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2422                 for (j = 0;j < surface->num_triangles;j++)
2423                 {
2424                         // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2425                         outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
2426                         outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
2427                         outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
2428                         inelements += 3;
2429                         outelements += 3;
2430                 }
2431
2432                 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2433                 for (j = 0;j < surface->num_vertices*2;j++)
2434                         loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2435
2436                 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2437                 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2438                 {
2439                         int weightindex[4] = { 0, 0, 0, 0 };
2440                         float weightinfluence[4] = { 0, 0, 0, 0 };
2441                         int l;
2442                         int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2443                         data += sizeof(dpmvertex_t);
2444                         for (k = 0;k < numweights;k++)
2445                         {
2446                                 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2447                                 int boneindex = BigLong(vert->bonenum);
2448                                 const float *m = bonepose + 12 * boneindex;
2449                                 float influence = BigFloat(vert->influence);
2450                                 float relativeorigin[3], relativenormal[3];
2451                                 relativeorigin[0] = BigFloat(vert->origin[0]);
2452                                 relativeorigin[1] = BigFloat(vert->origin[1]);
2453                                 relativeorigin[2] = BigFloat(vert->origin[2]);
2454                                 relativenormal[0] = BigFloat(vert->normal[0]);
2455                                 relativenormal[1] = BigFloat(vert->normal[1]);
2456                                 relativenormal[2] = BigFloat(vert->normal[2]);
2457                                 // blend the vertex bone weights into the base mesh
2458                                 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2459                                 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2460                                 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2461                                 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2462                                 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2463                                 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2464                                 if (!k)
2465                                 {
2466                                         // store the first (and often only) weight
2467                                         weightinfluence[0] = influence;
2468                                         weightindex[0] = boneindex;
2469                                 }
2470                                 else
2471                                 {
2472                                         // sort the new weight into this vertex's weight table
2473                                         // (which only accepts up to 4 bones per vertex)
2474                                         for (l = 0;l < 4;l++)
2475                                         {
2476                                                 if (weightinfluence[l] < influence)
2477                                                 {
2478                                                         // move weaker influence weights out of the way first
2479                                                         int l2;
2480                                                         for (l2 = 3;l2 > l;l2--)
2481                                                         {
2482                                                                 weightinfluence[l2] = weightinfluence[l2-1];
2483                                                                 weightindex[l2] = weightindex[l2-1];
2484                                                         }
2485                                                         // store the new weight
2486                                                         weightinfluence[l] = influence;
2487                                                         weightindex[l] = boneindex;
2488                                                         break;
2489                                                 }
2490                                         }
2491                                 }
2492                                 data += sizeof(dpmbonevert_t);
2493                         }
2494                         loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2495                         loadmodel->surfmesh.data_skeletalindex4ub[j*4  ] = weightindex[0];
2496                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2497                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2498                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2499                         loadmodel->surfmesh.data_skeletalweight4ub[j*4  ] = (unsigned char)(weightinfluence[0]*255.0f);
2500                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2501                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2502                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2503                 }
2504
2505                 // since dpm models do not have named sections, reuse their shader name as the section name
2506                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2507
2508                 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__);
2509         }
2510         if (loadmodel->surfmesh.num_blends < meshvertices)
2511                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2512         Z_Free(bonepose);
2513         Mod_FreeSkinFiles(skinfiles);
2514         Mod_MakeSortedSurfaces(loadmodel);
2515
2516         // compute all the mesh information that was not loaded from the file
2517         if (loadmodel->surfmesh.data_element3s)
2518                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2519                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2520         Mod_BuildBaseBonePoses();
2521         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);
2522         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2523         if(mod_alias_force_animated.string[0])
2524                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2525
2526         // Always make a BIH for the first frame, we can use it where possible.
2527         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2528         if (!loadmodel->surfmesh.isanimated)
2529         {
2530                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2531                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2532                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2533                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2534                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2535         }
2536
2537         // because shaders can do somewhat unexpected things, check for unusual features now
2538         for (i = 0;i < loadmodel->num_textures;i++)
2539         {
2540                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2541                         mod->DrawSky = R_Q1BSP_DrawSky;
2542                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2543                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2544         }
2545 }
2546
2547 // no idea why PSK/PSA files contain weird quaternions but they do...
2548 #define PSKQUATNEGATIONS
2549 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2550 {
2551         int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2552         int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2553         fs_offset_t filesize;
2554         pskpnts_t *pnts;
2555         pskvtxw_t *vtxw;
2556         pskface_t *faces;
2557         pskmatt_t *matts;
2558         pskboneinfo_t *bones;
2559         pskrawweights_t *rawweights;
2560         //pskboneinfo_t *animbones;
2561         pskaniminfo_t *anims;
2562         pskanimkeys_t *animkeys;
2563         void *animfilebuffer, *animbuffer, *animbufferend;
2564         unsigned char *data;
2565         pskchunk_t *pchunk;
2566         skinfile_t *skinfiles;
2567         char animname[MAX_QPATH];
2568         size_t size;
2569         float biggestorigin;
2570
2571         pchunk = (pskchunk_t *)buffer;
2572         if (strcmp(pchunk->id, "ACTRHEAD"))
2573                 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2574
2575         loadmodel->modeldatatypestring = "PSK";
2576
2577         loadmodel->type = mod_alias;
2578         loadmodel->DrawSky = NULL;
2579         loadmodel->DrawAddWaterPlanes = NULL;
2580         loadmodel->Draw = R_Q1BSP_Draw;
2581         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2582         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2583         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2584         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2585         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2586         loadmodel->DrawLight = R_Q1BSP_DrawLight;
2587         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2588         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2589         loadmodel->PointSuperContents = NULL;
2590         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2591         loadmodel->synctype = ST_RAND;
2592
2593         FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2594         strlcat(animname, ".psa", sizeof(animname));
2595         animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2596         animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2597         if (!animbuffer)
2598                 animbufferend = animbuffer;
2599
2600         numpnts = 0;
2601         pnts = NULL;
2602         numvtxw = 0;
2603         vtxw = NULL;
2604         numfaces = 0;
2605         faces = NULL;
2606         nummatts = 0;
2607         matts = NULL;
2608         numbones = 0;
2609         bones = NULL;
2610         numrawweights = 0;
2611         rawweights = NULL;
2612         numanims = 0;
2613         anims = NULL;
2614         numanimkeys = 0;
2615         animkeys = NULL;
2616
2617         while (buffer < bufferend)
2618         {
2619                 pchunk = (pskchunk_t *)buffer;
2620                 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2621                 version = LittleLong(pchunk->version);
2622                 recordsize = LittleLong(pchunk->recordsize);
2623                 numrecords = LittleLong(pchunk->numrecords);
2624                 if (developer_extra.integer)
2625                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2626                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2627                         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);
2628                 if (!strcmp(pchunk->id, "ACTRHEAD"))
2629                 {
2630                         // nothing to do
2631                 }
2632                 else if (!strcmp(pchunk->id, "PNTS0000"))
2633                 {
2634                         pskpnts_t *p;
2635                         if (recordsize != sizeof(*p))
2636                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2637                         // byteswap in place and keep the pointer
2638                         numpnts = numrecords;
2639                         pnts = (pskpnts_t *)buffer;
2640                         for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2641                         {
2642                                 p->origin[0] = LittleFloat(p->origin[0]);
2643                                 p->origin[1] = LittleFloat(p->origin[1]);
2644                                 p->origin[2] = LittleFloat(p->origin[2]);
2645                         }
2646                         buffer = p;
2647                 }
2648                 else if (!strcmp(pchunk->id, "VTXW0000"))
2649                 {
2650                         pskvtxw_t *p;
2651                         if (recordsize != sizeof(*p))
2652                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2653                         // byteswap in place and keep the pointer
2654                         numvtxw = numrecords;
2655                         vtxw = (pskvtxw_t *)buffer;
2656                         for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2657                         {
2658                                 p->pntsindex = LittleShort(p->pntsindex);
2659                                 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2660                                 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2661                                 if (p->pntsindex >= numpnts)
2662                                 {
2663                                         Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2664                                         p->pntsindex = 0;
2665                                 }
2666                         }
2667                         buffer = p;
2668                 }
2669                 else if (!strcmp(pchunk->id, "FACE0000"))
2670                 {
2671                         pskface_t *p;
2672                         if (recordsize != sizeof(*p))
2673                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2674                         // byteswap in place and keep the pointer
2675                         numfaces = numrecords;
2676                         faces = (pskface_t *)buffer;
2677                         for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2678                         {
2679                                 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2680                                 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2681                                 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2682                                 p->group = LittleLong(p->group);
2683                                 if (p->vtxwindex[0] >= numvtxw)
2684                                 {
2685                                         Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2686                                         p->vtxwindex[0] = 0;
2687                                 }
2688                                 if (p->vtxwindex[1] >= numvtxw)
2689                                 {
2690                                         Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2691                                         p->vtxwindex[1] = 0;
2692                                 }
2693                                 if (p->vtxwindex[2] >= numvtxw)
2694                                 {
2695                                         Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2696                                         p->vtxwindex[2] = 0;
2697                                 }
2698                         }
2699                         buffer = p;
2700                 }
2701                 else if (!strcmp(pchunk->id, "MATT0000"))
2702                 {
2703                         pskmatt_t *p;
2704                         if (recordsize != sizeof(*p))
2705                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2706                         // byteswap in place and keep the pointer
2707                         nummatts = numrecords;
2708                         matts = (pskmatt_t *)buffer;
2709                         for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2710                         {
2711                                 // nothing to do
2712                         }
2713                         buffer = p;
2714                 }
2715                 else if (!strcmp(pchunk->id, "REFSKELT"))
2716                 {
2717                         pskboneinfo_t *p;
2718                         if (recordsize != sizeof(*p))
2719                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2720                         // byteswap in place and keep the pointer
2721                         numbones = numrecords;
2722                         bones = (pskboneinfo_t *)buffer;
2723                         for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2724                         {
2725                                 p->numchildren = LittleLong(p->numchildren);
2726                                 p->parent = LittleLong(p->parent);
2727                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2728                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2729                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2730                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2731                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2732                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2733                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2734                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2735                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2736                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2737                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2738 #ifdef PSKQUATNEGATIONS
2739                                 if (index)
2740                                 {
2741                                         p->basepose.quat[0] *= -1;
2742                                         p->basepose.quat[1] *= -1;
2743                                         p->basepose.quat[2] *= -1;
2744                                 }
2745                                 else
2746                                 {
2747                                         p->basepose.quat[0] *=  1;
2748                                         p->basepose.quat[1] *= -1;
2749                                         p->basepose.quat[2] *=  1;
2750                                 }
2751 #endif
2752                                 if (p->parent < 0 || p->parent >= numbones)
2753                                 {
2754                                         Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2755                                         p->parent = 0;
2756                                 }
2757                         }
2758                         buffer = p;
2759                 }
2760                 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2761                 {
2762                         pskrawweights_t *p;
2763                         if (recordsize != sizeof(*p))
2764                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2765                         // byteswap in place and keep the pointer
2766                         numrawweights = numrecords;
2767                         rawweights = (pskrawweights_t *)buffer;
2768                         for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2769                         {
2770                                 p->weight = LittleFloat(p->weight);
2771                                 p->pntsindex = LittleLong(p->pntsindex);
2772                                 p->boneindex = LittleLong(p->boneindex);
2773                                 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2774                                 {
2775                                         Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2776                                         p->pntsindex = 0;
2777                                 }
2778                                 if (p->boneindex < 0 || p->boneindex >= numbones)
2779                                 {
2780                                         Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2781                                         p->boneindex = 0;
2782                                 }
2783                         }
2784                         buffer = p;
2785                 }
2786         }
2787
2788         while (animbuffer < animbufferend)
2789         {
2790                 pchunk = (pskchunk_t *)animbuffer;
2791                 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2792                 version = LittleLong(pchunk->version);
2793                 recordsize = LittleLong(pchunk->recordsize);
2794                 numrecords = LittleLong(pchunk->numrecords);
2795                 if (developer_extra.integer)
2796                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2797                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2798                         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);
2799                 if (!strcmp(pchunk->id, "ANIMHEAD"))
2800                 {
2801                         // nothing to do
2802                 }
2803                 else if (!strcmp(pchunk->id, "BONENAMES"))
2804                 {
2805                         pskboneinfo_t *p;
2806                         if (recordsize != sizeof(*p))
2807                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2808                         // byteswap in place and keep the pointer
2809                         numanimbones = numrecords;
2810                         //animbones = (pskboneinfo_t *)animbuffer;
2811                         // NOTE: supposedly psa does not need to match the psk model, the
2812                         // bones missing from the psa would simply use their base
2813                         // positions from the psk, but this is hard for me to implement
2814                         // and people can easily make animations that match.
2815                         if (numanimbones != numbones)
2816                                 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2817                         for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2818                         {
2819                                 p->numchildren = LittleLong(p->numchildren);
2820                                 p->parent = LittleLong(p->parent);
2821                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2822                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2823                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2824                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2825                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2826                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2827                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2828                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2829                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2830                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2831                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2832 #ifdef PSKQUATNEGATIONS
2833                                 if (index)
2834                                 {
2835                                         p->basepose.quat[0] *= -1;
2836                                         p->basepose.quat[1] *= -1;
2837                                         p->basepose.quat[2] *= -1;
2838                                 }
2839                                 else
2840                                 {
2841                                         p->basepose.quat[0] *=  1;
2842                                         p->basepose.quat[1] *= -1;
2843                                         p->basepose.quat[2] *=  1;
2844                                 }
2845 #endif
2846                                 if (p->parent < 0 || p->parent >= numanimbones)
2847                                 {
2848                                         Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2849                                         p->parent = 0;
2850                                 }
2851                                 // check that bones are the same as in the base
2852                                 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2853                                         Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2854                         }
2855                         animbuffer = p;
2856                 }
2857                 else if (!strcmp(pchunk->id, "ANIMINFO"))
2858                 {
2859                         pskaniminfo_t *p;
2860                         if (recordsize != sizeof(*p))
2861                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2862                         // byteswap in place and keep the pointer
2863                         numanims = numrecords;
2864                         anims = (pskaniminfo_t *)animbuffer;
2865                         for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2866                         {
2867                                 p->numbones = LittleLong(p->numbones);
2868                                 p->playtime = LittleFloat(p->playtime);
2869                                 p->fps = LittleFloat(p->fps);
2870                                 p->firstframe = LittleLong(p->firstframe);
2871                                 p->numframes = LittleLong(p->numframes);
2872                                 if (p->numbones != numbones)
2873                                         Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2874                         }
2875                         animbuffer = p;
2876                 }
2877                 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2878                 {
2879                         pskanimkeys_t *p;
2880                         if (recordsize != sizeof(*p))
2881                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2882                         numanimkeys = numrecords;
2883                         animkeys = (pskanimkeys_t *)animbuffer;
2884                         for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2885                         {
2886                                 p->origin[0] = LittleFloat(p->origin[0]);
2887                                 p->origin[1] = LittleFloat(p->origin[1]);
2888                                 p->origin[2] = LittleFloat(p->origin[2]);
2889                                 p->quat[0] = LittleFloat(p->quat[0]);
2890                                 p->quat[1] = LittleFloat(p->quat[1]);
2891                                 p->quat[2] = LittleFloat(p->quat[2]);
2892                                 p->quat[3] = LittleFloat(p->quat[3]);
2893                                 p->frametime = LittleFloat(p->frametime);
2894 #ifdef PSKQUATNEGATIONS
2895                                 if (index % numbones)
2896                                 {
2897                                         p->quat[0] *= -1;
2898                                         p->quat[1] *= -1;
2899                                         p->quat[2] *= -1;
2900                                 }
2901                                 else
2902                                 {
2903                                         p->quat[0] *=  1;
2904                                         p->quat[1] *= -1;
2905                                         p->quat[2] *=  1;
2906                                 }
2907 #endif
2908                         }
2909                         animbuffer = p;
2910                         // TODO: allocate bonepose stuff
2911                 }
2912                 else
2913                         Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2914         }
2915
2916         if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2917                 Host_Error("%s: missing required chunks", loadmodel->name);
2918
2919         if (numanims)
2920         {
2921                 loadmodel->numframes = 0;
2922                 for (index = 0;index < numanims;index++)
2923                         loadmodel->numframes += anims[index].numframes;
2924                 if (numanimkeys != numbones * loadmodel->numframes)
2925                         Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2926         }
2927         else
2928                 loadmodel->numframes = loadmodel->num_poses = 1;
2929
2930         meshvertices = numvtxw;
2931         meshtriangles = numfaces;
2932
2933         // load external .skin files if present
2934         skinfiles = Mod_LoadSkinFiles();
2935         if (loadmodel->numskins < 1)
2936                 loadmodel->numskins = 1;
2937         loadmodel->num_bones = numbones;
2938         loadmodel->num_poses = loadmodel->numframes;
2939         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2940         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2941         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2942         loadmodel->surfmesh.num_vertices = meshvertices;
2943         loadmodel->surfmesh.num_triangles = meshtriangles;
2944         // do most allocations as one merged chunk
2945         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);
2946         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2947         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2948         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2949         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2950         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2951         loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2952         loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2953         loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2954         loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2955         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2956         loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2957         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2958         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2959         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2960         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2961         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2962         loadmodel->surfmesh.num_blends = 0;
2963         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2964         if (loadmodel->surfmesh.num_vertices <= 65536)
2965         {
2966                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2967         }
2968         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2969         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
2970
2971         for (i = 0;i < loadmodel->numskins;i++)
2972         {
2973                 loadmodel->skinscenes[i].firstframe = i;
2974                 loadmodel->skinscenes[i].framecount = 1;
2975                 loadmodel->skinscenes[i].loop = true;
2976                 loadmodel->skinscenes[i].framerate = 10;
2977         }
2978
2979         // create surfaces
2980         for (index = 0, i = 0;index < nummatts;index++)
2981         {
2982                 // since psk models do not have named sections, reuse their shader name as the section name
2983                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2984                 loadmodel->sortedmodelsurfaces[index] = index;
2985                 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2986                 loadmodel->data_surfaces[index].num_firstvertex = 0;
2987                 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2988         }
2989
2990         // copy over the vertex locations and texcoords
2991         for (index = 0;index < numvtxw;index++)
2992         {
2993                 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
2994                 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
2995                 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
2996                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
2997                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
2998         }
2999
3000         // loading the faces is complicated because we need to sort them into surfaces by mattindex
3001         for (index = 0;index < numfaces;index++)
3002                 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
3003         for (index = 0, i = 0;index < nummatts;index++)
3004         {
3005                 loadmodel->data_surfaces[index].num_firsttriangle = i;
3006                 i += loadmodel->data_surfaces[index].num_triangles;
3007                 loadmodel->data_surfaces[index].num_triangles = 0;
3008         }
3009         for (index = 0;index < numfaces;index++)
3010         {
3011                 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
3012                 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
3013                 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
3014                 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
3015         }
3016
3017         // copy over the bones
3018         for (index = 0;index < numbones;index++)
3019         {
3020                 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
3021                 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
3022                 if (loadmodel->data_bones[index].parent >= index)
3023                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
3024         }
3025
3026         // convert the basepose data
3027         if (loadmodel->num_bones)
3028         {
3029                 int boneindex;
3030                 matrix4x4_t *basebonepose;
3031                 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
3032                 matrix4x4_t bonematrix;
3033                 matrix4x4_t tempbonematrix;
3034                 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
3035                 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
3036                 {
3037                         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]);
3038                         if (loadmodel->data_bones[boneindex].parent >= 0)
3039                         {
3040                                 tempbonematrix = bonematrix;
3041                                 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3042                         }
3043                         basebonepose[boneindex] = bonematrix;
3044                         Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3045                         Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3046                 }
3047                 Mem_Free(basebonepose);
3048         }
3049
3050         // sort the psk point weights into the vertex weight tables
3051         // (which only accept up to 4 bones per vertex)
3052         for (index = 0;index < numvtxw;index++)
3053         {
3054                 int weightindex[4] = { 0, 0, 0, 0 };
3055                 float weightinfluence[4] = { 0, 0, 0, 0 };
3056                 int l;
3057                 for (j = 0;j < numrawweights;j++)
3058                 {
3059                         if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3060                         {
3061                                 int boneindex = rawweights[j].boneindex;
3062                                 float influence = rawweights[j].weight;
3063                                 for (l = 0;l < 4;l++)
3064                                 {
3065                                         if (weightinfluence[l] < influence)
3066                                         {
3067                                                 // move lower influence weights out of the way first
3068                                                 int l2;
3069                                                 for (l2 = 3;l2 > l;l2--)
3070                                                 {
3071                                                         weightinfluence[l2] = weightinfluence[l2-1];
3072                                                         weightindex[l2] = weightindex[l2-1];
3073                                                 }
3074                                                 // store the new weight
3075                                                 weightinfluence[l] = influence;
3076                                                 weightindex[l] = boneindex;
3077                                                 break;
3078                                         }
3079                                 }
3080                         }
3081                 }
3082                 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3083                 loadmodel->surfmesh.data_skeletalindex4ub[index*4  ] = weightindex[0];
3084                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3085                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3086                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3087                 loadmodel->surfmesh.data_skeletalweight4ub[index*4  ] = (unsigned char)(weightinfluence[0]*255.0f);
3088                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3089                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3090                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3091         }
3092         if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3093                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3094
3095         // set up the animscenes based on the anims
3096         if (numanims)
3097         {
3098                 for (index = 0, i = 0;index < numanims;index++)
3099                 {
3100                         for (j = 0;j < anims[index].numframes;j++, i++)
3101                         {
3102                                 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3103                                 loadmodel->animscenes[i].firstframe = i;
3104                                 loadmodel->animscenes[i].framecount = 1;
3105                                 loadmodel->animscenes[i].loop = true;
3106                                 loadmodel->animscenes[i].framerate = anims[index].fps;
3107                         }
3108                 }
3109                 // calculate the scaling value for bone origins so they can be compressed to short
3110                 biggestorigin = 0;
3111                 for (index = 0;index < numanimkeys;index++)
3112                 {
3113                         pskanimkeys_t *k = animkeys + index;
3114                         biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3115                         biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3116                         biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3117                 }
3118                 loadmodel->num_posescale = biggestorigin / 32767.0f;
3119                 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3120         
3121                 // load the poses from the animkeys
3122                 for (index = 0;index < numanimkeys;index++)
3123                 {
3124                         pskanimkeys_t *k = animkeys + index;
3125                         float quat[4];
3126                         Vector4Copy(k->quat, quat);
3127                         if (quat[3] > 0)
3128                                 Vector4Negate(quat, quat);
3129                         Vector4Normalize2(quat, quat);
3130                         // compress poses to the short[7] format for longterm storage
3131                         loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3132                         loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3133                         loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3134                         loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3135                         loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3136                         loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3137                         loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3138                 }
3139         }
3140         else
3141         {
3142                 strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3143                 loadmodel->animscenes[0].firstframe = 0;
3144                 loadmodel->animscenes[0].framecount = 1;
3145                 loadmodel->animscenes[0].loop = true;
3146                 loadmodel->animscenes[0].framerate = 10;
3147
3148                 // calculate the scaling value for bone origins so they can be compressed to short
3149                 biggestorigin = 0;
3150                 for (index = 0;index < numbones;index++)
3151                 {
3152                         pskboneinfo_t *p = bones + index;
3153                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3154                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3155                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3156                 }
3157                 loadmodel->num_posescale = biggestorigin / 32767.0f;
3158                 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3159         
3160                 // load the basepose as a frame
3161                 for (index = 0;index < numbones;index++)
3162                 {
3163                         pskboneinfo_t *p = bones + index;
3164                         float quat[4];
3165                         Vector4Copy(p->basepose.quat, quat);
3166                         if (quat[3] > 0)
3167                                 Vector4Negate(quat, quat);
3168                         Vector4Normalize2(quat, quat);
3169                         // compress poses to the short[7] format for longterm storage
3170                         loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3171                         loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3172                         loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3173                         loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3174                         loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3175                         loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3176                         loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3177                 }
3178         }
3179
3180         Mod_FreeSkinFiles(skinfiles);
3181         if (animfilebuffer)
3182                 Mem_Free(animfilebuffer);
3183         Mod_MakeSortedSurfaces(loadmodel);
3184
3185         // compute all the mesh information that was not loaded from the file
3186         // TODO: honor smoothing groups somehow?
3187         if (loadmodel->surfmesh.data_element3s)
3188                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3189                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3190         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3191         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);
3192         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);
3193         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3194         if(mod_alias_force_animated.string[0])
3195                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3196
3197         // Always make a BIH for the first frame, we can use it where possible.
3198         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3199         if (!loadmodel->surfmesh.isanimated)
3200         {
3201                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3202                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3203                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3204                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3205                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3206         }
3207
3208         // because shaders can do somewhat unexpected things, check for unusual features now
3209         for (i = 0;i < loadmodel->num_textures;i++)
3210         {
3211                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3212                         mod->DrawSky = R_Q1BSP_DrawSky;
3213                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3214                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
3215         }
3216 }
3217
3218 void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
3219 {
3220         unsigned char *data;
3221         const char *text;
3222         const unsigned char *pbase, *pend;
3223         iqmheader_t header;
3224         skinfile_t *skinfiles;
3225         int i, j, k, meshvertices, meshtriangles;
3226         float biggestorigin;
3227         const unsigned int *inelements;
3228         int *outelements;
3229         float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3230         // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3231         const float *vnormal = NULL;
3232         const float *vposition = NULL;
3233         const float *vtangent = NULL;
3234         const float *vtexcoord = NULL;
3235         const float *vcolor4f = NULL;
3236         const unsigned char *vblendindexes = NULL;
3237         const unsigned char *vblendweights = NULL;
3238         const unsigned char *vcolor4ub = NULL;
3239         const unsigned short *framedata = NULL;
3240         // temporary memory allocations (because the data in the file may be misaligned)
3241         iqmanim_t *anims = NULL;
3242         iqmbounds_t *bounds = NULL;
3243         iqmjoint1_t *joint1 = NULL;
3244         iqmjoint_t *joint = NULL;
3245         iqmmesh_t *meshes = NULL;
3246         iqmpose1_t *pose1 = NULL;
3247         iqmpose_t *pose = NULL;
3248         iqmvertexarray_t *vas = NULL;
3249
3250         pbase = (unsigned char *)buffer;
3251         pend = (unsigned char *)bufferend;
3252
3253         if (pbase + sizeof(iqmheader_t) > pend)
3254                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase));
3255
3256         // copy struct (otherwise it may be misaligned)
3257         // LordHavoc: okay it's definitely not misaligned here, but for consistency...
3258         memcpy(&header, pbase, sizeof(iqmheader_t));
3259
3260         if (memcmp(header.id, "INTERQUAKEMODEL", 16))
3261                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3262         if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
3263                 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
3264
3265         loadmodel->modeldatatypestring = "IQM";
3266
3267         loadmodel->type = mod_alias;
3268         loadmodel->synctype = ST_RAND;
3269
3270         // byteswap header
3271         header.version = LittleLong(header.version);
3272         header.filesize = LittleLong(header.filesize);
3273         header.flags = LittleLong(header.flags);
3274         header.num_text = LittleLong(header.num_text);
3275         header.ofs_text = LittleLong(header.ofs_text);
3276         header.num_meshes = LittleLong(header.num_meshes);
3277         header.ofs_meshes = LittleLong(header.ofs_meshes);
3278         header.num_vertexarrays = LittleLong(header.num_vertexarrays);
3279         header.num_vertexes = LittleLong(header.num_vertexes);
3280         header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays);
3281         header.num_triangles = LittleLong(header.num_triangles);
3282         header.ofs_triangles = LittleLong(header.ofs_triangles);
3283         header.ofs_neighbors = LittleLong(header.ofs_neighbors);
3284         header.num_joints = LittleLong(header.num_joints);
3285         header.ofs_joints = LittleLong(header.ofs_joints);
3286         header.num_poses = LittleLong(header.num_poses);
3287         header.ofs_poses = LittleLong(header.ofs_poses);
3288         header.num_anims = LittleLong(header.num_anims);
3289         header.ofs_anims = LittleLong(header.ofs_anims);
3290         header.num_frames = LittleLong(header.num_frames);
3291         header.num_framechannels = LittleLong(header.num_framechannels);
3292         header.ofs_frames = LittleLong(header.ofs_frames);
3293         header.ofs_bounds = LittleLong(header.ofs_bounds);
3294         header.num_comment = LittleLong(header.num_comment);
3295         header.ofs_comment = LittleLong(header.ofs_comment);
3296         header.num_extensions = LittleLong(header.num_extensions);
3297         header.ofs_extensions = LittleLong(header.ofs_extensions);
3298
3299         if (header.version == 1)
3300         {
3301                 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend ||
3302                         pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend)
3303                 {
3304                         Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3305                         return;
3306                 }
3307         }
3308         else
3309         {
3310                 if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
3311                         pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
3312                 {
3313                         Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3314                         return;
3315                 }
3316         }
3317         if (pbase + header.ofs_text + header.num_text > pend ||
3318                 pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
3319                 pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3320                 pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
3321                 (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
3322                 pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
3323                 pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
3324                 (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
3325                 pbase + header.ofs_comment + header.num_comment > pend)
3326         {
3327                 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3328                 return;
3329         }
3330
3331         // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others)
3332         if (header.num_vertexarrays)
3333                 vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays);
3334         if (header.num_anims)
3335                 anims = (iqmanim_t *)(pbase + header.ofs_anims);
3336         if (header.ofs_bounds)
3337                 bounds = (iqmbounds_t *)(pbase + header.ofs_bounds);
3338         if (header.num_meshes)
3339                 meshes = (iqmmesh_t *)(pbase + header.ofs_meshes);
3340
3341         for (i = 0;i < (int)header.num_vertexarrays;i++)
3342         {
3343                 iqmvertexarray_t va;
3344                 size_t vsize;
3345                 va.type = LittleLong(vas[i].type);
3346                 va.flags = LittleLong(vas[i].flags);
3347                 va.format = LittleLong(vas[i].format);
3348                 va.size = LittleLong(vas[i].size);
3349                 va.offset = LittleLong(vas[i].offset);
3350                 vsize = header.num_vertexes*va.size;
3351                 switch (va.format)
3352                 { 
3353                 case IQM_FLOAT: vsize *= sizeof(float); break;
3354                 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3355                 default: continue;
3356                 }
3357                 if (pbase + va.offset + vsize > pend)
3358                         continue;
3359                 // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned
3360                 switch (va.type)
3361                 {
3362                 case IQM_POSITION:
3363                         if (va.format == IQM_FLOAT && va.size == 3)
3364                                 vposition = (const float *)(pbase + va.offset);
3365                         break;
3366                 case IQM_TEXCOORD:
3367                         if (va.format == IQM_FLOAT && va.size == 2)
3368                                 vtexcoord = (const float *)(pbase + va.offset);
3369                         break;
3370                 case IQM_NORMAL:
3371                         if (va.format == IQM_FLOAT && va.size == 3)
3372                                 vnormal = (const float *)(pbase + va.offset);
3373                         break;
3374                 case IQM_TANGENT:
3375                         if (va.format == IQM_FLOAT && va.size == 4)
3376                                 vtangent = (const float *)(pbase + va.offset);
3377                         break;
3378                 case IQM_BLENDINDEXES:
3379                         if (va.format == IQM_UBYTE && va.size == 4)
3380                                 vblendindexes = (const unsigned char *)(pbase + va.offset);
3381                         break;
3382                 case IQM_BLENDWEIGHTS:
3383                         if (va.format == IQM_UBYTE && va.size == 4)
3384                                 vblendweights = (const unsigned char *)(pbase + va.offset);
3385                         break;
3386                 case IQM_COLOR:
3387                         if (va.format == IQM_FLOAT && va.size == 4)
3388                                 vcolor4f = (const float *)(pbase + va.offset);
3389                         if (va.format == IQM_UBYTE && va.size == 4)
3390                                 vcolor4ub = (const unsigned char *)(pbase + va.offset);
3391                         break;
3392                 }
3393         }
3394         if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights))))
3395         {
3396                 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3397                 return;
3398         }
3399
3400         text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
3401
3402         loadmodel->DrawSky = NULL;
3403         loadmodel->DrawAddWaterPlanes = NULL;
3404         loadmodel->Draw = R_Q1BSP_Draw;
3405         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
3406         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
3407         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
3408         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
3409         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
3410         loadmodel->DrawLight = R_Q1BSP_DrawLight;
3411         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3412         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3413         loadmodel->PointSuperContents = NULL;
3414         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3415
3416         // load external .skin files if present
3417         skinfiles = Mod_LoadSkinFiles();
3418         if (loadmodel->numskins < 1)
3419                 loadmodel->numskins = 1;
3420
3421         loadmodel->numframes = max(header.num_anims, 1);
3422         loadmodel->num_bones = header.num_joints;
3423         loadmodel->num_poses = max(header.num_frames, 1);
3424         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header.num_meshes;
3425         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3426         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3427
3428         meshvertices = header.num_vertexes;
3429         meshtriangles = header.num_triangles;
3430
3431         // do most allocations as one merged chunk
3432         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));
3433         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3434         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3435         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3436         loadmodel->surfmesh.num_vertices = meshvertices;
3437         loadmodel->surfmesh.num_triangles = meshtriangles;
3438         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3439         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3440         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3441         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3442         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3443         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3444         if (vcolor4f || vcolor4ub)
3445         {
3446                 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]);
3447         }
3448         if (vblendindexes && vblendweights)
3449         {
3450                 loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3451                 loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
3452         }
3453         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3454         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3455         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3456         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3457         if (vblendindexes && vblendweights)
3458         {
3459                 loadmodel->surfmesh.num_blends = 0;
3460                 loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3461         }
3462         if (meshvertices <= 65536)
3463         {
3464                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
3465         }
3466         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3467         if (vblendindexes && vblendweights)
3468                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
3469
3470         for (i = 0;i < loadmodel->numskins;i++)
3471         {
3472                 loadmodel->skinscenes[i].firstframe = i;
3473                 loadmodel->skinscenes[i].framecount = 1;
3474                 loadmodel->skinscenes[i].loop = true;
3475                 loadmodel->skinscenes[i].framerate = 10;
3476         }
3477
3478         // load the bone info
3479         if (header.version == 1)
3480         {
3481                 iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints);
3482                 if (loadmodel->num_bones)
3483                         joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t));
3484                 for (i = 0;i < loadmodel->num_bones;i++)
3485                 {
3486                         matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3487                         joint1[i].name = LittleLong(injoint1[i].name);
3488                         joint1[i].parent = LittleLong(injoint1[i].parent);
3489                         for (j = 0;j < 3;j++)
3490                         {
3491                                 joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
3492                                 joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
3493                                 joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
3494                         }
3495                         strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
3496                         loadmodel->data_bones[i].parent = joint1[i].parent;
3497                         if (loadmodel->data_bones[i].parent >= i)
3498                                 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3499                         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]);
3500                         Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3501                         if (loadmodel->data_bones[i].parent >= 0)
3502                         {
3503                                 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3504                                 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3505                                 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3506                         }
3507                         else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3508                 }
3509         }
3510         else
3511         {
3512                 iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
3513                 if (header.num_joints)
3514                         joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
3515                 for (i = 0;i < loadmodel->num_bones;i++)
3516                 {
3517                         matrix4x4_t relbase, relinvbase, pinvbase, invbase;
3518                         joint[i].name = LittleLong(injoint[i].name);
3519                         joint[i].parent = LittleLong(injoint[i].parent);
3520                         for (j = 0;j < 3;j++)
3521                         {
3522                                 joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
3523                                 joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
3524                                 joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
3525                         }
3526                         joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
3527                         strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
3528                         loadmodel->data_bones[i].parent = joint[i].parent;
3529                         if (loadmodel->data_bones[i].parent >= i)
3530                                 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
3531                         if (joint[i].rotation[3] > 0)
3532                                 Vector4Negate(joint[i].rotation, joint[i].rotation);
3533                         Vector4Normalize2(joint[i].rotation, joint[i].rotation);
3534                         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]);
3535                         Matrix4x4_Invert_Simple(&relinvbase, &relbase);
3536                         if (loadmodel->data_bones[i].parent >= 0)
3537                         {
3538                                 Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
3539                                 Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
3540                                 Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
3541                         }       
3542                         else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
3543                 }
3544         }
3545
3546         // set up the animscenes based on the anims
3547         for (i = 0;i < (int)header.num_anims;i++)
3548         {
3549                 iqmanim_t anim;
3550                 anim.name = LittleLong(anims[i].name);
3551                 anim.first_frame = LittleLong(anims[i].first_frame);
3552                 anim.num_frames = LittleLong(anims[i].num_frames);
3553                 anim.framerate = LittleFloat(anims[i].framerate);
3554                 anim.flags = LittleLong(anims[i].flags);
3555                 strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name));
3556                 loadmodel->animscenes[i].firstframe = anim.first_frame;
3557                 loadmodel->animscenes[i].framecount = anim.num_frames;
3558                 loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0);
3559                 loadmodel->animscenes[i].framerate = anim.framerate;
3560         }
3561         if (header.num_anims <= 0)
3562         {
3563                 strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name));
3564                 loadmodel->animscenes[0].firstframe = 0;
3565                 loadmodel->animscenes[0].framecount = 1;
3566                 loadmodel->animscenes[0].loop = true;
3567                 loadmodel->animscenes[0].framerate = 10;
3568         }
3569
3570         loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
3571         if(mod_alias_force_animated.string[0])
3572                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3573
3574         biggestorigin = 0;
3575         if (header.version == 1)
3576         {
3577                 iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
3578                 if (header.num_poses)
3579                         pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
3580                 for (i = 0;i < (int)header.num_poses;i++)
3581                 {
3582                         float f;
3583                         pose1[i].parent = LittleLong(inpose1[i].parent);
3584                         pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
3585                         for (j = 0;j < 9;j++)
3586                         {
3587                                 pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
3588                                 pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
3589                         }
3590                         f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3591                         f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3592                         f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3593                         f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3594                         f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3595                         f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3596                 }
3597                 if (header.num_frames <= 0)
3598                 {
3599                         for (i = 0;i < loadmodel->num_bones;i++)
3600                         {
3601                                 float f;
3602                                 f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
3603                                 f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
3604                                 f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
3605                         }
3606                 }
3607         }
3608         else
3609         {
3610                 iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
3611                 if (header.num_poses)
3612                         pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
3613                 for (i = 0;i < (int)header.num_poses;i++)
3614                 {
3615                         float f;
3616                         pose[i].parent = LittleLong(inpose[i].parent);
3617                         pose[i].channelmask = LittleLong(inpose[i].channelmask);
3618                         for (j = 0;j < 10;j++)
3619                         {
3620                                 pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
3621                                 pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
3622                         }
3623                         f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
3624                         f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
3625                         f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
3626                         f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
3627                         f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
3628                         f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
3629                 }
3630                 if (header.num_frames <= 0)
3631                 {
3632                         for (i = 0;i < loadmodel->num_bones;i++)
3633                         {
3634                                 float f;
3635                                 f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
3636                                 f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
3637                                 f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
3638                         }
3639                 }
3640         }
3641         loadmodel->num_posescale = biggestorigin / 32767.0f;
3642         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3643
3644         // load the pose data
3645         // this unaligned memory access is safe (LittleShort reads as bytes)
3646         framedata = (const unsigned short *)(pbase + header.ofs_frames);
3647         if (header.version == 1)
3648         {
3649                 for (i = 0, k = 0;i < (int)header.num_frames;i++)
3650                 {
3651                         for (j = 0;j < (int)header.num_poses;j++, k++)
3652                         {
3653                                 float qx, qy, qz, qw;
3654                                 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));
3655                                 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));
3656                                 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));
3657                                 qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0);
3658                                 qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0);
3659                                 qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0);
3660                                 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3661                                 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3662                                 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx;
3663                                 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy;
3664                                 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz;
3665                                 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw;
3666                                 // skip scale data for now
3667                                 if(pose1[j].channelmask&64) framedata++;
3668                                 if(pose1[j].channelmask&128) framedata++;
3669                                 if(pose1[j].channelmask&256) framedata++;
3670                         }
3671                 }
3672                 if (header.num_frames <= 0)
3673                 {
3674                         for (i = 0;i < loadmodel->num_bones;i++)
3675                         {
3676                                 float qx, qy, qz, qw;
3677                                 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
3678                                 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
3679                                 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
3680                                 qx = joint1[i].rotation[0];
3681                                 qy = joint1[i].rotation[1];
3682                                 qz = joint1[i].rotation[2];
3683                                 qw = 1.0f - (qx*qx + qy*qy + qz*qz);
3684                                 qw = qw > 0.0f ? -sqrt(qw) : 0.0f;
3685                                 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx;
3686                                 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy;
3687                                 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz;
3688                                 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw;
3689                         }
3690                 }
3691         }
3692         else
3693         {
3694                 for (i = 0, k = 0;i < (int)header.num_frames;i++)       
3695                 {
3696                         for (j = 0;j < (int)header.num_poses;j++, k++)
3697                         {
3698                                 float rot[4];
3699                                 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));
3700                                 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));
3701                                 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));
3702                                 rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
3703                                 rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
3704                                 rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
3705                                 rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
3706                                 if (rot[3] > 0)
3707                                         Vector4Negate(rot, rot);
3708                                 Vector4Normalize2(rot, rot);
3709                                 loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0];
3710                                 loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1];
3711                                 loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2];
3712                                 loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3];
3713                                 // skip scale data for now
3714                                 if(pose[j].channelmask&128) framedata++;
3715                                 if(pose[j].channelmask&256) framedata++;
3716                                 if(pose[j].channelmask&512) framedata++;
3717                         }
3718                 }
3719                 if (header.num_frames <= 0)
3720                 {
3721                         for (i = 0;i < loadmodel->num_bones;i++)
3722                         {
3723                                 loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
3724                                 loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
3725                                 loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
3726                                 loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0];
3727                                 loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1];
3728                                 loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2];
3729                                 loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3];
3730                         }
3731                 }
3732         }
3733
3734         // load bounding box data
3735         if (header.ofs_bounds)
3736         {
3737                 float xyradius = 0, radius = 0;
3738                 VectorClear(loadmodel->normalmins);
3739                 VectorClear(loadmodel->normalmaxs);
3740                 for (i = 0; i < (int)header.num_frames;i++)
3741                 {
3742                         iqmbounds_t bound;
3743                         bound.mins[0] = LittleFloat(bounds[i].mins[0]);
3744                         bound.mins[1] = LittleFloat(bounds[i].mins[1]);
3745                         bound.mins[2] = LittleFloat(bounds[i].mins[2]);
3746                         bound.maxs[0] = LittleFloat(bounds[i].maxs[0]);                 
3747                         bound.maxs[1] = LittleFloat(bounds[i].maxs[1]); 
3748                         bound.maxs[2] = LittleFloat(bounds[i].maxs[2]); 
3749                         bound.xyradius = LittleFloat(bounds[i].xyradius);
3750                         bound.radius = LittleFloat(bounds[i].radius);
3751                         if (!i)
3752                         {
3753                                 VectorCopy(bound.mins, loadmodel->normalmins);
3754                                 VectorCopy(bound.maxs, loadmodel->normalmaxs);
3755                         }
3756                         else
3757                         {
3758                                 if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0];
3759                                 if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1];
3760                                 if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2];
3761                                 if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0];
3762                                 if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1];
3763                                 if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2];
3764                         }
3765                         if (bound.xyradius > xyradius)
3766                                 xyradius = bound.xyradius;
3767                         if (bound.radius > radius)
3768                                 radius = bound.radius;
3769                 }
3770                 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius;
3771                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius;
3772                 loadmodel->yawmins[2] = loadmodel->normalmins[2];
3773                 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
3774                 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
3775                 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
3776                 loadmodel->radius = radius;
3777                 loadmodel->radius2 = radius * radius;
3778         }
3779
3780         // load triangle data
3781         // this unaligned memory access is safe (LittleLong reads as bytes)
3782         inelements = (const unsigned int *)(pbase + header.ofs_triangles);
3783         outelements = loadmodel->surfmesh.data_element3i;
3784         for (i = 0;i < (int)header.num_triangles;i++)
3785         {
3786                 outelements[0] = LittleLong(inelements[0]);
3787                 outelements[1] = LittleLong(inelements[1]);
3788                 outelements[2] = LittleLong(inelements[2]);
3789                 outelements += 3;
3790                 inelements += 3;
3791         }
3792         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
3793
3794         // load vertex data
3795         // this unaligned memory access is safe (LittleFloat reads as bytes)
3796         outvertex = loadmodel->surfmesh.data_vertex3f;
3797         for (i = 0;i < (int)header.num_vertexes;i++)
3798         {
3799                 outvertex[0] = LittleFloat(vposition[0]);
3800                 outvertex[1] = LittleFloat(vposition[1]);
3801                 outvertex[2] = LittleFloat(vposition[2]);
3802                 vposition += 3;
3803                 outvertex += 3;
3804         }
3805
3806         outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
3807         // this unaligned memory access is safe (LittleFloat reads as bytes)
3808         for (i = 0;i < (int)header.num_vertexes;i++)
3809         {
3810                 outtexcoord[0] = LittleFloat(vtexcoord[0]);
3811                 outtexcoord[1] = LittleFloat(vtexcoord[1]);
3812                 vtexcoord += 2;
3813                 outtexcoord += 2;
3814         }
3815
3816         // this unaligned memory access is safe (LittleFloat reads as bytes)
3817         if(vnormal)
3818         {
3819                 outnormal = loadmodel->surfmesh.data_normal3f;
3820                 for (i = 0;i < (int)header.num_vertexes;i++)
3821                 {
3822                         outnormal[0] = LittleFloat(vnormal[0]);
3823                         outnormal[1] = LittleFloat(vnormal[1]);
3824                         outnormal[2] = LittleFloat(vnormal[2]);
3825                         vnormal += 3;
3826                         outnormal += 3;
3827                 }
3828         }
3829
3830         // this unaligned memory access is safe (LittleFloat reads as bytes)
3831         if(vnormal && vtangent)
3832         {
3833                 outnormal = loadmodel->surfmesh.data_normal3f;
3834                 outsvector = loadmodel->surfmesh.data_svector3f;
3835                 outtvector = loadmodel->surfmesh.data_tvector3f;
3836                 for (i = 0;i < (int)header.num_vertexes;i++)
3837                 {
3838                         outsvector[0] = LittleFloat(vtangent[0]);
3839                         outsvector[1] = LittleFloat(vtangent[1]);
3840                         outsvector[2] = LittleFloat(vtangent[2]);
3841                         if(LittleFloat(vtangent[3]) < 0)
3842                                 CrossProduct(outsvector, outnormal, outtvector);
3843                         else
3844                                 CrossProduct(outnormal, outsvector, outtvector);
3845                         vtangent += 4;
3846                         outnormal += 3;
3847                         outsvector += 3;
3848                         outtvector += 3;
3849                 }
3850         }
3851
3852         // this unaligned memory access is safe (all bytes)
3853         if (vblendindexes && vblendweights)
3854         {
3855                 for (i = 0; i < (int)header.num_vertexes;i++)
3856                 {
3857                         blendweights_t weights;
3858                         memcpy(weights.index, vblendindexes + i*4, 4);
3859                         memcpy(weights.influence, vblendweights + i*4, 4);
3860                         loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights);
3861                         loadmodel->surfmesh.data_skeletalindex4ub[i*4  ] = weights.index[0];
3862                         loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1];
3863                         loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2];
3864                         loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3];
3865                         loadmodel->surfmesh.data_skeletalweight4ub[i*4  ] = weights.influence[0];
3866                         loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1];
3867                         loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2];
3868                         loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3];
3869                 }
3870         }
3871
3872         if (vcolor4f)
3873         {
3874                 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3875                 // this unaligned memory access is safe (LittleFloat reads as bytes)
3876                 for (i = 0;i < (int)header.num_vertexes;i++)
3877                 {
3878                         outcolor[0] = LittleFloat(vcolor4f[0]);
3879                         outcolor[1] = LittleFloat(vcolor4f[1]);
3880                         outcolor[2] = LittleFloat(vcolor4f[2]);
3881                         outcolor[3] = LittleFloat(vcolor4f[3]);
3882                         vcolor4f += 4;
3883                         outcolor += 4;
3884                 }
3885         }
3886         else if (vcolor4ub)
3887         {
3888                 outcolor = loadmodel->surfmesh.data_lightmapcolor4f;
3889                 // this unaligned memory access is safe (all bytes)
3890                 for (i = 0;i < (int)header.num_vertexes;i++)
3891                 {
3892                         outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f);
3893                         outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f);
3894                         outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f);
3895                         outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f);
3896                         vcolor4ub += 4;
3897                         outcolor += 4;
3898                 }
3899         }
3900
3901         // load meshes
3902         for (i = 0;i < (int)header.num_meshes;i++)
3903         {
3904                 iqmmesh_t mesh;
3905                 msurface_t *surface;
3906
3907                 mesh.name = LittleLong(meshes[i].name);
3908                 mesh.material = LittleLong(meshes[i].material);
3909                 mesh.first_vertex = LittleLong(meshes[i].first_vertex);
3910                 mesh.num_vertexes = LittleLong(meshes[i].num_vertexes);
3911                 mesh.first_triangle = LittleLong(meshes[i].first_triangle);
3912                 mesh.num_triangles = LittleLong(meshes[i].num_triangles);
3913
3914                 loadmodel->sortedmodelsurfaces[i] = i;
3915                 surface = loadmodel->data_surfaces + i;
3916                 surface->texture = loadmodel->data_textures + i;
3917                 surface->num_firsttriangle = mesh.first_triangle;
3918                 surface->num_triangles = mesh.num_triangles;
3919                 surface->num_firstvertex = mesh.first_vertex;
3920                 surface->num_vertices = mesh.num_vertexes;
3921
3922                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
3923         }
3924
3925         Mod_FreeSkinFiles(skinfiles);
3926         Mod_MakeSortedSurfaces(loadmodel);
3927
3928         // compute all the mesh information that was not loaded from the file
3929         if (loadmodel->surfmesh.data_element3s)
3930                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3931                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3932         if (!vnormal)
3933                 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);
3934         if (!vnormal || !vtangent)
3935                 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);
3936         if (!header.ofs_bounds)
3937                 Mod_Alias_CalculateBoundingBox();
3938
3939         // Always make a BIH for the first frame, we can use it where possible.
3940         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3941         if (!loadmodel->surfmesh.isanimated)
3942         {
3943                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3944                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3945                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3946                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3947                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3948         }
3949
3950         if (joint        ) Mem_Free(joint        );joint         = NULL;
3951         if (joint1       ) Mem_Free(joint1       );joint1        = NULL;
3952         if (pose         ) Mem_Free(pose         );pose          = NULL;
3953         if (pose1        ) Mem_Free(pose1        );pose1         = NULL;
3954
3955         // because shaders can do somewhat unexpected things, check for unusual features now
3956         for (i = 0;i < loadmodel->num_textures;i++)
3957         {
3958                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3959                         mod->DrawSky = R_Q1BSP_DrawSky;
3960                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3961                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
3962         }
3963 }