ca4c88ef97d243565ddf7c1a75c88621fdade440
[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 pose7s = model->data_poses7s + 7 * (frameblend[0].subframe * model->num_bones + i);
98                         float lerp = frameblend[0].lerp,
99                                 tx = pose7s[0], ty = pose7s[1], tz = pose7s[2],
100                                 rx = pose7s[3] * lerp,
101                                 ry = pose7s[4] * lerp,
102                                 rz = pose7s[5] * lerp,
103                                 rw = pose7s[6] * lerp,
104                                 dx = tx*rw + ty*rz - tz*ry,
105                                 dy = -tx*rz + ty*rw + tz*rx,
106                                 dz = tx*ry - ty*rx + tz*rw,
107                                 dw = -tx*rx - ty*ry - tz*rz,
108                                 scale, sx, sy, sz, sw;
109                         for (blends = 1;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
110                         {
111                                 const short * RESTRICT pose7s = model->data_poses7s + 7 * (frameblend[blends].subframe * model->num_bones + i);
112                                 float lerp = frameblend[blends].lerp,
113                                         tx = pose7s[0], ty = pose7s[1], tz = pose7s[2],
114                                         qx = pose7s[3], qy = pose7s[4], qz = pose7s[5], qw = pose7s[6];
115                                 if(rx*qx + ry*qy + rz*qz + rw*qw < 0) lerp = -lerp;
116                                 qx *= lerp;
117                                 qy *= lerp;
118                                 qz *= lerp;
119                                 qw *= lerp;
120                                 rx += qx;
121                                 ry += qy;
122                                 rz += qz;
123                                 rw += qw;
124                                 dx += tx*qw + ty*qz - tz*qy;
125                                 dy += -tx*qz + ty*qw + tz*qx;
126                                 dz += tx*qy - ty*qx + tz*qw;
127                                 dw += -tx*qx - ty*qy - tz*qz;
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)
756 {
757         int i;
758         float segmentmins[3], segmentmaxs[3];
759         msurface_t *surface;
760         float vertex3fbuf[1024*3];
761         float *vertex3f = vertex3fbuf;
762         memset(trace, 0, sizeof(*trace));
763         trace->fraction = 1;
764         trace->hitsupercontentsmask = hitsupercontentsmask;
765         if (model->surfmesh.num_vertices > 1024)
766                 vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
767         segmentmins[0] = min(start[0], end[0]) - 1;
768         segmentmins[1] = min(start[1], end[1]) - 1;
769         segmentmins[2] = min(start[2], end[2]) - 1;
770         segmentmaxs[0] = max(start[0], end[0]) + 1;
771         segmentmaxs[1] = max(start[1], end[1]) + 1;
772         segmentmaxs[2] = max(start[2], end[2]) + 1;
773         model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
774         for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
775                 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);
776         if (vertex3f != vertex3fbuf)
777                 Mem_Free(vertex3f);
778 }
779
780 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)
781 {
782         int i;
783         vec3_t shiftstart, shiftend;
784         float segmentmins[3], segmentmaxs[3];
785         msurface_t *surface;
786         float vertex3fbuf[1024*3];
787         float *vertex3f = vertex3fbuf;
788         colboxbrushf_t thisbrush_start, thisbrush_end;
789         vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
790
791         if (VectorCompare(boxmins, boxmaxs))
792         {
793                 VectorAdd(start, boxmins, shiftstart);
794                 VectorAdd(end, boxmins, shiftend);
795                 Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask);
796                 VectorSubtract(trace->endpos, boxmins, trace->endpos);
797                 return;
798         }
799
800         // box trace, performed as brush trace
801         memset(trace, 0, sizeof(*trace));
802         trace->fraction = 1;
803         trace->hitsupercontentsmask = hitsupercontentsmask;
804         if (model->surfmesh.num_vertices > 1024)
805                 vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
806         segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1;
807         segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1;
808         segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1;
809         segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1;
810         segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1;
811         segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1;
812         VectorAdd(start, boxmins, boxstartmins);
813         VectorAdd(start, boxmaxs, boxstartmaxs);
814         VectorAdd(end, boxmins, boxendmins);
815         VectorAdd(end, boxmaxs, boxendmaxs);
816         Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL);
817         Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL);
818         model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
819         for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
820                 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);
821         if (vertex3f != vertex3fbuf)
822                 Mem_Free(vertex3f);
823 }
824
825 static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap)
826 {
827         int i, j;
828         for (i = 0;i < inverts;i++)
829         {
830                 if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
831                         continue;
832                 j = vertremap[i]; // not onseam
833                 if (j >= 0)
834                         out[j] = v[i];
835                 j = vertremap[i+inverts]; // onseam
836                 if (j >= 0)
837                         out[j] = v[i];
838         }
839 }
840
841 static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *vertremap)
842 {
843         int i, f, pose, groupframes;
844         float interval;
845         daliasframetype_t *pframetype;
846         daliasframe_t *pinframe;
847         daliasgroup_t *group;
848         daliasinterval_t *intervals;
849         animscene_t *scene;
850         pose = 0;
851         scene = loadmodel->animscenes;
852         for (f = 0;f < loadmodel->numframes;f++)
853         {
854                 pframetype = (daliasframetype_t *)datapointer;
855                 datapointer += sizeof(daliasframetype_t);
856                 if (LittleLong (pframetype->type) == ALIAS_SINGLE)
857                 {
858                         // a single frame is still treated as a group
859                         interval = 0.1f;
860                         groupframes = 1;
861                 }
862                 else
863                 {
864                         // read group header
865                         group = (daliasgroup_t *)datapointer;
866                         datapointer += sizeof(daliasgroup_t);
867                         groupframes = LittleLong (group->numframes);
868
869                         // intervals (time per frame)
870                         intervals = (daliasinterval_t *)datapointer;
871                         datapointer += sizeof(daliasinterval_t) * groupframes;
872
873                         interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
874                         if (interval < 0.01f)
875                         {
876                                 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
877                                 interval = 0.1f;
878                         }
879                 }
880
881                 // get scene name from first frame
882                 pinframe = (daliasframe_t *)datapointer;
883
884                 strlcpy(scene->name, pinframe->name, sizeof(scene->name));
885                 scene->firstframe = pose;
886                 scene->framecount = groupframes;
887                 scene->framerate = 1.0f / interval;
888                 scene->loop = true;
889                 scene++;
890
891                 // read frames
892                 for (i = 0;i < groupframes;i++)
893                 {
894                         datapointer += sizeof(daliasframe_t);
895                         Mod_ConvertAliasVerts(inverts, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphmdlvertex + pose * loadmodel->surfmesh.num_vertices, vertremap);
896                         datapointer += sizeof(trivertx_t) * inverts;
897                         pose++;
898                 }
899         }
900 }
901
902 static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *skinframe)
903 {
904         if (cls.state == ca_dedicated)
905                 return;
906         // hack
907         if (!skinframe)
908                 skinframe = R_SkinFrame_LoadMissing();
909         memset(texture, 0, sizeof(*texture));
910         texture->currentframe = texture;
911         //texture->animated = false;
912         texture->numskinframes = 1;
913         texture->skinframerate = 1;
914         texture->skinframes[0] = skinframe;
915         texture->currentskinframe = skinframe;
916         //texture->backgroundnumskinframes = 0;
917         //texture->customblendfunc[0] = 0;
918         //texture->customblendfunc[1] = 0;
919         //texture->surfaceflags = 0;
920         //texture->supercontents = 0;
921         //texture->surfaceparms = 0;
922         //texture->textureflags = 0;
923
924         texture->basematerialflags = MATERIALFLAG_WALL;
925         texture->basealpha = 1.0f;
926         if (texture->currentskinframe->hasalpha)
927                 texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
928         texture->currentmaterialflags = texture->basematerialflags;
929         texture->offsetmapping = OFFSETMAPPING_DEFAULT;
930         texture->offsetscale = 1;
931         texture->offsetbias = 0;
932         texture->specularscalemod = 1;
933         texture->specularpowermod = 1;
934         texture->surfaceflags = 0;
935         texture->supercontents = SUPERCONTENTS_SOLID;
936         if (!(texture->basematerialflags & MATERIALFLAG_BLENDED))
937                 texture->supercontents |= SUPERCONTENTS_OPAQUE;
938         texture->transparentsort = TRANSPARENTSORT_DISTANCE;
939         // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
940         // JUST GREP FOR "specularscalemod = 1".
941 }
942
943 void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
944 {
945         int i;
946         char stripbuf[MAX_QPATH];
947         skinfileitem_t *skinfileitem;
948         if(developer_extra.integer)
949                 Con_DPrintf("Looking up texture for %s (default: %s)\n", meshname, shadername);
950         if (skinfile)
951         {
952                 // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
953                 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
954                 {
955                         memset(skin, 0, sizeof(*skin));
956                         // see if a mesh
957                         for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
958                         {
959                                 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
960                                 if (!strcmp(skinfileitem->name, meshname))
961                                 {
962                                         Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf));
963                                         if(developer_extra.integer)
964                                                 Con_DPrintf("--> got %s from skin file\n", stripbuf);
965                                         Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
966                                         break;
967                                 }
968                         }
969                         if (!skinfileitem)
970                         {
971                                 // don't render unmentioned meshes
972                                 Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
973                                 if(developer_extra.integer)
974                                         Con_DPrintf("--> skipping\n");
975                                 skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW;
976                         }
977                 }
978         }
979         else
980         {
981                 if(developer_extra.integer)
982                         Con_DPrintf("--> using default\n");
983                 Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf));
984                 Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
985         }
986 }
987
988 #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);
989 #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);
990 void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
991 {
992         int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
993         float scales, scalet, interval;
994         msurface_t *surface;
995         unsigned char *data;
996         mdl_t *pinmodel;
997         stvert_t *pinstverts;
998         dtriangle_t *pintriangles;
999         daliasskintype_t *pinskintype;
1000         daliasskingroup_t *pinskingroup;
1001         daliasskininterval_t *pinskinintervals;
1002         daliasframetype_t *pinframetype;
1003         daliasgroup_t *pinframegroup;
1004         unsigned char *datapointer, *startframes, *startskins;
1005         char name[MAX_QPATH];
1006         skinframe_t *tempskinframe;
1007         animscene_t *tempskinscenes;
1008         texture_t *tempaliasskins;
1009         float *vertst;
1010         int *vertonseam, *vertremap;
1011         skinfile_t *skinfiles;
1012         char vabuf[1024];
1013
1014         datapointer = (unsigned char *)buffer;
1015         pinmodel = (mdl_t *)datapointer;
1016         datapointer += sizeof(mdl_t);
1017
1018         version = LittleLong (pinmodel->version);
1019         if (version != ALIAS_VERSION)
1020                 Host_Error ("%s has wrong version number (%i should be %i)",
1021                                  loadmodel->name, version, ALIAS_VERSION);
1022
1023         loadmodel->modeldatatypestring = "MDL";
1024
1025         loadmodel->type = mod_alias;
1026         loadmodel->DrawSky = NULL;
1027         loadmodel->DrawAddWaterPlanes = NULL;
1028         loadmodel->Draw = R_Q1BSP_Draw;
1029         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1030         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1031         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1032         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1033         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1034         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1035         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1036         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1037         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1038         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1039         // FIXME add TraceBrush!
1040         loadmodel->PointSuperContents = NULL;
1041         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1042
1043         loadmodel->num_surfaces = 1;
1044         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1045         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
1046         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1047         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1048         loadmodel->sortedmodelsurfaces[0] = 0;
1049
1050         loadmodel->numskins = LittleLong(pinmodel->numskins);
1051         BOUNDI(loadmodel->numskins,0,65536);
1052         skinwidth = LittleLong (pinmodel->skinwidth);
1053         BOUNDI(skinwidth,0,65536);
1054         skinheight = LittleLong (pinmodel->skinheight);
1055         BOUNDI(skinheight,0,65536);
1056         numverts = LittleLong(pinmodel->numverts);
1057         BOUNDI(numverts,0,65536);
1058         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
1059         BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
1060         loadmodel->numframes = LittleLong(pinmodel->numframes);
1061         BOUNDI(loadmodel->numframes,0,65536);
1062         loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
1063         BOUNDI((int)loadmodel->synctype,0,2);
1064         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1065         i = LittleLong (pinmodel->flags);
1066         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1067
1068         for (i = 0;i < 3;i++)
1069         {
1070                 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
1071                 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
1072         }
1073
1074         startskins = datapointer;
1075         totalskins = 0;
1076         for (i = 0;i < loadmodel->numskins;i++)
1077         {
1078                 pinskintype = (daliasskintype_t *)datapointer;
1079                 datapointer += sizeof(daliasskintype_t);
1080                 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
1081                         groupskins = 1;
1082                 else
1083                 {
1084                         pinskingroup = (daliasskingroup_t *)datapointer;
1085                         datapointer += sizeof(daliasskingroup_t);
1086                         groupskins = LittleLong(pinskingroup->numskins);
1087                         datapointer += sizeof(daliasskininterval_t) * groupskins;
1088                 }
1089
1090                 for (j = 0;j < groupskins;j++)
1091                 {
1092                         datapointer += skinwidth * skinheight;
1093                         totalskins++;
1094                 }
1095         }
1096
1097         pinstverts = (stvert_t *)datapointer;
1098         datapointer += sizeof(stvert_t) * numverts;
1099
1100         pintriangles = (dtriangle_t *)datapointer;
1101         datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
1102
1103         startframes = datapointer;
1104         loadmodel->surfmesh.num_morphframes = 0;
1105         for (i = 0;i < loadmodel->numframes;i++)
1106         {
1107                 pinframetype = (daliasframetype_t *)datapointer;
1108                 datapointer += sizeof(daliasframetype_t);
1109                 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1110                         groupframes = 1;
1111                 else
1112                 {
1113                         pinframegroup = (daliasgroup_t *)datapointer;
1114                         datapointer += sizeof(daliasgroup_t);
1115                         groupframes = LittleLong(pinframegroup->numframes);
1116                         datapointer += sizeof(daliasinterval_t) * groupframes;
1117                 }
1118
1119                 for (j = 0;j < groupframes;j++)
1120                 {
1121                         datapointer += sizeof(daliasframe_t);
1122                         datapointer += sizeof(trivertx_t) * numverts;
1123                         loadmodel->surfmesh.num_morphframes++;
1124                 }
1125         }
1126         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1127
1128         // store texture coordinates into temporary array, they will be stored
1129         // after usage is determined (triangle data)
1130         vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1131         vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1132         vertonseam = vertremap + numverts * 2;
1133
1134         scales = 1.0 / skinwidth;
1135         scalet = 1.0 / skinheight;
1136         for (i = 0;i < numverts;i++)
1137         {
1138                 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1139                 vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales;
1140                 vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet;
1141                 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1142                 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1143         }
1144
1145 // load triangle data
1146         loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1147
1148         // read the triangle elements
1149         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1150                 for (j = 0;j < 3;j++)
1151                         loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1152         // validate (note numverts is used because this is the original data)
1153         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1154         // now butcher the elements according to vertonseam and tri->facesfront
1155         // and then compact the vertex set to remove duplicates
1156         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1157                 if (!LittleLong(pintriangles[i].facesfront)) // backface
1158                         for (j = 0;j < 3;j++)
1159                                 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1160                                         loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1161         // count the usage
1162         // (this uses vertremap to count usage to save some memory)
1163         for (i = 0;i < numverts*2;i++)
1164                 vertremap[i] = 0;
1165         for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1166                 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1167         // build remapping table and compact array
1168         loadmodel->surfmesh.num_vertices = 0;
1169         for (i = 0;i < numverts*2;i++)
1170         {
1171                 if (vertremap[i])
1172                 {
1173                         vertremap[i] = loadmodel->surfmesh.num_vertices;
1174                         vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1175                         vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1176                         loadmodel->surfmesh.num_vertices++;
1177                 }
1178                 else
1179                         vertremap[i] = -1; // not used at all
1180         }
1181         // remap the elements to the new vertex set
1182         for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1183                 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1184         // store the texture coordinates
1185         loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1186         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1187         {
1188                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1189                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1190         }
1191
1192         // generate ushort elements array if possible
1193         if (loadmodel->surfmesh.num_vertices <= 65536)
1194                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1195         if (loadmodel->surfmesh.data_element3s)
1196                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1197                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1198
1199 // load the frames
1200         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1201         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1202         if (r_enableshadowvolumes.integer)
1203         {
1204                 loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
1205         }
1206         Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1207         if (loadmodel->surfmesh.data_neighbor3i)
1208                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1209         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1210         Mod_Alias_MorphMesh_CompileFrames();
1211
1212         Mem_Free(vertst);
1213         Mem_Free(vertremap);
1214
1215         // load the skins
1216         skinfiles = Mod_LoadSkinFiles();
1217         if (skinfiles)
1218         {
1219                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1220                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1221                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1222                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1223                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1224                 Mod_FreeSkinFiles(skinfiles);
1225                 for (i = 0;i < loadmodel->numskins;i++)
1226                 {
1227                         loadmodel->skinscenes[i].firstframe = i;
1228                         loadmodel->skinscenes[i].framecount = 1;
1229                         loadmodel->skinscenes[i].loop = true;
1230                         loadmodel->skinscenes[i].framerate = 10;
1231                 }
1232         }
1233         else
1234         {
1235                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1236                 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1237                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1238                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1239                 totalskins = 0;
1240                 datapointer = startskins;
1241                 for (i = 0;i < loadmodel->numskins;i++)
1242                 {
1243                         pinskintype = (daliasskintype_t *)datapointer;
1244                         datapointer += sizeof(daliasskintype_t);
1245
1246                         if (pinskintype->type == ALIAS_SKIN_SINGLE)
1247                         {
1248                                 groupskins = 1;
1249                                 interval = 0.1f;
1250                         }
1251                         else
1252                         {
1253                                 pinskingroup = (daliasskingroup_t *)datapointer;
1254                                 datapointer += sizeof(daliasskingroup_t);
1255
1256                                 groupskins = LittleLong (pinskingroup->numskins);
1257
1258                                 pinskinintervals = (daliasskininterval_t *)datapointer;
1259                                 datapointer += sizeof(daliasskininterval_t) * groupskins;
1260
1261                                 interval = LittleFloat(pinskinintervals[0].interval);
1262                                 if (interval < 0.01f)
1263                                 {
1264                                         Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1265                                         interval = 0.1f;
1266                                 }
1267                         }
1268
1269                         dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1270                         loadmodel->skinscenes[i].firstframe = totalskins;
1271                         loadmodel->skinscenes[i].framecount = groupskins;
1272                         loadmodel->skinscenes[i].framerate = 1.0f / interval;
1273                         loadmodel->skinscenes[i].loop = true;
1274
1275                         for (j = 0;j < groupskins;j++)
1276                         {
1277                                 if (groupskins > 1)
1278                                         dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1279                                 else
1280                                         dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1281                                 if (!Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS))
1282                                         Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, R_SkinFrame_LoadInternalQuake(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight));
1283                                 datapointer += skinwidth * skinheight;
1284                                 totalskins++;
1285                         }
1286                 }
1287                 // check for skins that don't exist in the model, but do exist as external images
1288                 // (this was added because yummyluv kept pestering me about support for it)
1289                 // TODO: support shaders here?
1290                 while ((tempskinframe = R_SkinFrame_LoadExternal(va(vabuf, sizeof(vabuf), "%s_%i", loadmodel->name, loadmodel->numskins), (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false)))
1291                 {
1292                         // expand the arrays to make room
1293                         tempskinscenes = loadmodel->skinscenes;
1294                         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1295                         memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1296                         Mem_Free(tempskinscenes);
1297
1298                         tempaliasskins = loadmodel->data_textures;
1299                         loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1300                         memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1301                         Mem_Free(tempaliasskins);
1302
1303                         // store the info about the new skin
1304                         Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, tempskinframe);
1305                         strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1306                         loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1307                         loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1308                         loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1309                         loadmodel->skinscenes[loadmodel->numskins].loop = true;
1310
1311                         //increase skin counts
1312                         loadmodel->numskins++;
1313                         totalskins++;
1314
1315                         // fix up the pointers since they are pointing at the old textures array
1316                         // FIXME: this is a hack!
1317                         for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1318                                 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1319                 }
1320         }
1321
1322         surface = loadmodel->data_surfaces;
1323         surface->texture = loadmodel->data_textures;
1324         surface->num_firsttriangle = 0;
1325         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1326         surface->num_firstvertex = 0;
1327         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1328
1329         if(mod_alias_force_animated.string[0])
1330                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1331
1332         if (!loadmodel->surfmesh.isanimated)
1333         {
1334                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1335                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1336                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1337                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1338                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1339                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1340         }
1341
1342         // because shaders can do somewhat unexpected things, check for unusual features now
1343         for (i = 0;i < loadmodel->num_textures;i++)
1344         {
1345                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1346                         mod->DrawSky = R_Q1BSP_DrawSky;
1347                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1348                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1349         }
1350 }
1351
1352 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
1353 {
1354         int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1355         float iskinwidth, iskinheight;
1356         unsigned char *data;
1357         msurface_t *surface;
1358         md2_t *pinmodel;
1359         unsigned char *base, *datapointer;
1360         md2frame_t *pinframe;
1361         char *inskin;
1362         md2triangle_t *intri;
1363         unsigned short *inst;
1364         struct md2verthash_s
1365         {
1366                 struct md2verthash_s *next;
1367                 unsigned short xyz;
1368                 unsigned short st;
1369         }
1370         *hash, **md2verthash, *md2verthashdata;
1371         skinfile_t *skinfiles;
1372
1373         pinmodel = (md2_t *)buffer;
1374         base = (unsigned char *)buffer;
1375
1376         version = LittleLong (pinmodel->version);
1377         if (version != MD2ALIAS_VERSION)
1378                 Host_Error ("%s has wrong version number (%i should be %i)",
1379                         loadmodel->name, version, MD2ALIAS_VERSION);
1380
1381         loadmodel->modeldatatypestring = "MD2";
1382
1383         loadmodel->type = mod_alias;
1384         loadmodel->DrawSky = NULL;
1385         loadmodel->DrawAddWaterPlanes = NULL;
1386         loadmodel->Draw = R_Q1BSP_Draw;
1387         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1388         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1389         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1390         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1391         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1392         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1393         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1394         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1395         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1396         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1397         loadmodel->PointSuperContents = NULL;
1398         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1399
1400         if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1401                 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1402         if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1403                 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1404         if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1405                 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1406         if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1407                 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1408
1409         end = LittleLong(pinmodel->ofs_end);
1410         if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1411                 Host_Error ("%s is not a valid model", loadmodel->name);
1412         if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1413                 Host_Error ("%s is not a valid model", loadmodel->name);
1414         if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1415                 Host_Error ("%s is not a valid model", loadmodel->name);
1416         if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1417                 Host_Error ("%s is not a valid model", loadmodel->name);
1418         if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1419                 Host_Error ("%s is not a valid model", loadmodel->name);
1420
1421         loadmodel->numskins = LittleLong(pinmodel->num_skins);
1422         numxyz = LittleLong(pinmodel->num_xyz);
1423         numst = LittleLong(pinmodel->num_st);
1424         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1425         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1426         loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1427         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1428         skinwidth = LittleLong(pinmodel->skinwidth);
1429         skinheight = LittleLong(pinmodel->skinheight);
1430         iskinwidth = 1.0f / skinwidth;
1431         iskinheight = 1.0f / skinheight;
1432
1433         loadmodel->num_surfaces = 1;
1434         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1435         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->numframes * sizeof(animscene_t) + loadmodel->numframes * sizeof(float[6]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + (r_enableshadowvolumes.integer ? loadmodel->surfmesh.num_triangles * sizeof(int[3]) : 0));
1436         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1437         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1438         loadmodel->sortedmodelsurfaces[0] = 0;
1439         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1440         loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1441         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1442         if (r_enableshadowvolumes.integer)
1443         {
1444                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1445         }
1446
1447         loadmodel->synctype = ST_RAND;
1448
1449         // load the skins
1450         inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1451         skinfiles = Mod_LoadSkinFiles();
1452         if (skinfiles)
1453         {
1454                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1455                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1456                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1457                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1458                 Mod_FreeSkinFiles(skinfiles);
1459         }
1460         else if (loadmodel->numskins)
1461         {
1462                 // skins found (most likely not a player model)
1463                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1464                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1465                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1466                 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1467                         Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
1468         }
1469         else
1470         {
1471                 // no skins (most likely a player model)
1472                 loadmodel->numskins = 1;
1473                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1474                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1475                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1476                 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL);
1477         }
1478
1479         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1480         for (i = 0;i < loadmodel->numskins;i++)
1481         {
1482                 loadmodel->skinscenes[i].firstframe = i;
1483                 loadmodel->skinscenes[i].framecount = 1;
1484                 loadmodel->skinscenes[i].loop = true;
1485                 loadmodel->skinscenes[i].framerate = 10;
1486         }
1487
1488         // load the triangles and stvert data
1489         inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1490         intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1491         md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1492         md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1493         // swap the triangle list
1494         loadmodel->surfmesh.num_vertices = 0;
1495         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1496         {
1497                 for (j = 0;j < 3;j++)
1498                 {
1499                         xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1500                         st = (unsigned short) LittleShort (intri[i].index_st[j]);
1501                         if (xyz >= numxyz)
1502                         {
1503                                 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1504                                 xyz = 0;
1505                         }
1506                         if (st >= numst)
1507                         {
1508                                 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1509                                 st = 0;
1510                         }
1511                         hashindex = (xyz * 256 + st) & 65535;
1512                         for (hash = md2verthash[hashindex];hash;hash = hash->next)
1513                                 if (hash->xyz == xyz && hash->st == st)
1514                                         break;
1515                         if (hash == NULL)
1516                         {
1517                                 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1518                                 hash->xyz = xyz;
1519                                 hash->st = st;
1520                                 hash->next = md2verthash[hashindex];
1521                                 md2verthash[hashindex] = hash;
1522                         }
1523                         loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1524                 }
1525         }
1526
1527         vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1528         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));
1529         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1530         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1531         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1532         {
1533                 int sts, stt;
1534                 hash = md2verthashdata + i;
1535                 vertremap[i] = hash->xyz;
1536                 sts = LittleShort(inst[hash->st*2+0]);
1537                 stt = LittleShort(inst[hash->st*2+1]);
1538                 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1539                 {
1540                         Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1541                         sts = 0;
1542                         stt = 0;
1543                 }
1544                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1545                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1546         }
1547
1548         Mem_Free(md2verthash);
1549         Mem_Free(md2verthashdata);
1550
1551         // generate ushort elements array if possible
1552         if (loadmodel->surfmesh.num_vertices <= 65536)
1553                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1554         if (loadmodel->surfmesh.data_element3s)
1555                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1556                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1557
1558         // load the frames
1559         datapointer = (base + LittleLong(pinmodel->ofs_frames));
1560         for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1561         {
1562                 int k;
1563                 trivertx_t *v;
1564                 trivertx_t *out;
1565                 pinframe = (md2frame_t *)datapointer;
1566                 datapointer += sizeof(md2frame_t);
1567                 // store the frame scale/translate into the appropriate array
1568                 for (j = 0;j < 3;j++)
1569                 {
1570                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1571                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1572                 }
1573                 // convert the vertices
1574                 v = (trivertx_t *)datapointer;
1575                 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1576                 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1577                         out[k] = v[vertremap[k]];
1578                 datapointer += numxyz * sizeof(trivertx_t);
1579
1580                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1581                 loadmodel->animscenes[i].firstframe = i;
1582                 loadmodel->animscenes[i].framecount = 1;
1583                 loadmodel->animscenes[i].framerate = 10;
1584                 loadmodel->animscenes[i].loop = true;
1585         }
1586
1587         Mem_Free(vertremap);
1588
1589         if (loadmodel->surfmesh.data_neighbor3i)
1590                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1591         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1592         Mod_Alias_MorphMesh_CompileFrames();
1593         if(mod_alias_force_animated.string[0])
1594                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1595
1596         surface = loadmodel->data_surfaces;
1597         surface->texture = loadmodel->data_textures;
1598         surface->num_firsttriangle = 0;
1599         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1600         surface->num_firstvertex = 0;
1601         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1602
1603         if (!loadmodel->surfmesh.isanimated)
1604         {
1605                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1606                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1607                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1608                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1609                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1610                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1611         }
1612
1613         // because shaders can do somewhat unexpected things, check for unusual features now
1614         for (i = 0;i < loadmodel->num_textures;i++)
1615         {
1616                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1617                         mod->DrawSky = R_Q1BSP_DrawSky;
1618                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1619                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1620         }
1621 }
1622
1623 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
1624 {
1625         int i, j, k, version, meshvertices, meshtriangles;
1626         unsigned char *data;
1627         msurface_t *surface;
1628         md3modelheader_t *pinmodel;
1629         md3frameinfo_t *pinframe;
1630         md3mesh_t *pinmesh;
1631         md3tag_t *pintag;
1632         skinfile_t *skinfiles;
1633
1634         pinmodel = (md3modelheader_t *)buffer;
1635
1636         if (memcmp(pinmodel->identifier, "IDP3", 4))
1637                 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1638         version = LittleLong (pinmodel->version);
1639         if (version != MD3VERSION)
1640                 Host_Error ("%s has wrong version number (%i should be %i)",
1641                         loadmodel->name, version, MD3VERSION);
1642
1643         skinfiles = Mod_LoadSkinFiles();
1644         if (loadmodel->numskins < 1)
1645                 loadmodel->numskins = 1;
1646
1647         loadmodel->modeldatatypestring = "MD3";
1648
1649         loadmodel->type = mod_alias;
1650         loadmodel->DrawSky = NULL;
1651         loadmodel->DrawAddWaterPlanes = NULL;
1652         loadmodel->Draw = R_Q1BSP_Draw;
1653         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1654         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1655         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1656         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1657         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1658         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1659         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1660         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1661         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1662         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1663         loadmodel->PointSuperContents = NULL;
1664         loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1665         loadmodel->synctype = ST_RAND;
1666         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1667         i = LittleLong (pinmodel->flags);
1668         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1669
1670         // set up some global info about the model
1671         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1672         loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1673
1674         // make skinscenes for the skins (no groups)
1675         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1676         for (i = 0;i < loadmodel->numskins;i++)
1677         {
1678                 loadmodel->skinscenes[i].firstframe = i;
1679                 loadmodel->skinscenes[i].framecount = 1;
1680                 loadmodel->skinscenes[i].loop = true;
1681                 loadmodel->skinscenes[i].framerate = 10;
1682         }
1683
1684         // load frameinfo
1685         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1686         for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1687         {
1688                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1689                 loadmodel->animscenes[i].firstframe = i;
1690                 loadmodel->animscenes[i].framecount = 1;
1691                 loadmodel->animscenes[i].framerate = 10;
1692                 loadmodel->animscenes[i].loop = true;
1693         }
1694
1695         // load tags
1696         loadmodel->num_tagframes = loadmodel->numframes;
1697         loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1698         loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1699         for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1700         {
1701                 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1702                 for (j = 0;j < 9;j++)
1703                         loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1704                 for (j = 0;j < 3;j++)
1705                         loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1706                 //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);
1707         }
1708
1709         // load meshes
1710         meshvertices = 0;
1711         meshtriangles = 0;
1712         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)))
1713         {
1714                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1715                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1716                 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1717                         Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1718                 meshvertices += LittleLong(pinmesh->num_vertices);
1719                 meshtriangles += LittleLong(pinmesh->num_triangles);
1720         }
1721
1722         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1723         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1724         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1725         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * sizeof(float[2]) + meshvertices * loadmodel->numframes * sizeof(md3vertex_t));
1726         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1727         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1728         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1729         loadmodel->surfmesh.num_vertices = meshvertices;
1730         loadmodel->surfmesh.num_triangles = meshtriangles;
1731         loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1732         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1733         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1734         if (r_enableshadowvolumes.integer)
1735         {
1736                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1737         }
1738         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1739         loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1740         if (meshvertices <= 65536)
1741         {
1742                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1743         }
1744
1745         meshvertices = 0;
1746         meshtriangles = 0;
1747         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)))
1748         {
1749                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1750                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1751                 loadmodel->sortedmodelsurfaces[i] = i;
1752                 surface = loadmodel->data_surfaces + i;
1753                 surface->texture = loadmodel->data_textures + i;
1754                 surface->num_firsttriangle = meshtriangles;
1755                 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1756                 surface->num_firstvertex = meshvertices;
1757                 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1758                 meshvertices += surface->num_vertices;
1759                 meshtriangles += surface->num_triangles;
1760
1761                 for (j = 0;j < surface->num_triangles * 3;j++)
1762                         loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1763                 for (j = 0;j < surface->num_vertices;j++)
1764                 {
1765                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1766                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1767                 }
1768                 for (j = 0;j < loadmodel->numframes;j++)
1769                 {
1770                         const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1771                         md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1772                         for (k = 0;k < surface->num_vertices;k++, in++, out++)
1773                         {
1774                                 out->origin[0] = LittleShort(in->origin[0]);
1775                                 out->origin[1] = LittleShort(in->origin[1]);
1776                                 out->origin[2] = LittleShort(in->origin[2]);
1777                                 out->pitch = in->pitch;
1778                                 out->yaw = in->yaw;
1779                         }
1780                 }
1781
1782                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1783
1784                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1785         }
1786         if (loadmodel->surfmesh.data_element3s)
1787                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1788                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1789         if (loadmodel->surfmesh.data_neighbor3i)
1790                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1791         Mod_Alias_MorphMesh_CompileFrames();
1792         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1793         Mod_FreeSkinFiles(skinfiles);
1794         Mod_MakeSortedSurfaces(loadmodel);
1795         if(mod_alias_force_animated.string[0])
1796                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1797
1798         if (!loadmodel->surfmesh.isanimated)
1799         {
1800                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1801                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1802                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1803                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1804                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1805                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1806         }
1807
1808         // because shaders can do somewhat unexpected things, check for unusual features now
1809         for (i = 0;i < loadmodel->num_textures;i++)
1810         {
1811                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1812                         mod->DrawSky = R_Q1BSP_DrawSky;
1813                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1814                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1815         }
1816 }
1817
1818 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1819 {
1820         zymtype1header_t *pinmodel, *pheader;
1821         unsigned char *pbase;
1822         int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1823         float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1824         zymvertex_t *verts, *vertdata;
1825         zymscene_t *scene;
1826         zymbone_t *bone;
1827         char *shadername;
1828         skinfile_t *skinfiles;
1829         unsigned char *data;
1830         msurface_t *surface;
1831
1832         pinmodel = (zymtype1header_t *)buffer;
1833         pbase = (unsigned char *)buffer;
1834         if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1835                 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1836         if (BigLong(pinmodel->type) != 1)
1837                 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1838
1839         loadmodel->modeldatatypestring = "ZYM";
1840
1841         loadmodel->type = mod_alias;
1842         loadmodel->synctype = ST_RAND;
1843
1844         // byteswap header
1845         pheader = pinmodel;
1846         pheader->type = BigLong(pinmodel->type);
1847         pheader->filesize = BigLong(pinmodel->filesize);
1848         pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1849         pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1850         pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1851         pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1852         pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1853         pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1854         pheader->radius = BigFloat(pinmodel->radius);
1855         pheader->numverts = BigLong(pinmodel->numverts);
1856         pheader->numtris = BigLong(pinmodel->numtris);
1857         pheader->numshaders = BigLong(pinmodel->numshaders);
1858         pheader->numbones = BigLong(pinmodel->numbones);
1859         pheader->numscenes = BigLong(pinmodel->numscenes);
1860         pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1861         pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1862         pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1863         pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1864         pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1865         pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1866         pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1867         pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1868         pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1869         pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1870         pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1871         pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1872         pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1873         pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1874         pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1875         pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1876         pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1877         pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1878
1879         if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1880         {
1881                 Con_Printf("%s has no geometry\n", loadmodel->name);
1882                 return;
1883         }
1884         if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1885         {
1886                 Con_Printf("%s has no animations\n", loadmodel->name);
1887                 return;
1888         }
1889
1890         loadmodel->DrawSky = NULL;
1891         loadmodel->DrawAddWaterPlanes = NULL;
1892         loadmodel->Draw = R_Q1BSP_Draw;
1893         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1894         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1895         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1896         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1897         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1898         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1899         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1900         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1901         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1902         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1903         loadmodel->PointSuperContents = NULL;
1904         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1905
1906         loadmodel->numframes = pheader->numscenes;
1907         loadmodel->num_surfaces = pheader->numshaders;
1908
1909         skinfiles = Mod_LoadSkinFiles();
1910         if (loadmodel->numskins < 1)
1911                 loadmodel->numskins = 1;
1912
1913         // make skinscenes for the skins (no groups)
1914         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1915         for (i = 0;i < loadmodel->numskins;i++)
1916         {
1917                 loadmodel->skinscenes[i].firstframe = i;
1918                 loadmodel->skinscenes[i].framecount = 1;
1919                 loadmodel->skinscenes[i].loop = true;
1920                 loadmodel->skinscenes[i].framerate = 10;
1921         }
1922
1923         // model bbox
1924         // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
1925         modelradius = pheader->radius;
1926         for (i = 0;i < 3;i++)
1927         {
1928                 loadmodel->normalmins[i] = pheader->mins[i];
1929                 loadmodel->normalmaxs[i] = pheader->maxs[i];
1930                 loadmodel->rotatedmins[i] = -modelradius;
1931                 loadmodel->rotatedmaxs[i] = modelradius;
1932         }
1933         corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1934         corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1935         loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1936         if (loadmodel->yawmaxs[0] > modelradius)
1937                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1938         loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1939         loadmodel->yawmins[2] = loadmodel->normalmins[2];
1940         loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1941         loadmodel->radius = modelradius;
1942         loadmodel->radius2 = modelradius * modelradius;
1943
1944         // go through the lumps, swapping things
1945
1946         //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1947         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1948         scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1949         numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1950         for (i = 0;i < pheader->numscenes;i++)
1951         {
1952                 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1953                 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1954                 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1955                 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1956                 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1957                 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1958                         Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1959                 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1960                         Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1961                 if (loadmodel->animscenes[i].framerate < 0)
1962                         Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1963                 scene++;
1964         }
1965
1966         //zymlump_t lump_bones; // zymbone_t bone[numbones];
1967         loadmodel->num_bones = pheader->numbones;
1968         loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1969         bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1970         for (i = 0;i < pheader->numbones;i++)
1971         {
1972                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1973                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1974                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1975                 if (loadmodel->data_bones[i].parent >= i)
1976                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1977         }
1978
1979         //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1980         vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1981         bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1982         for (i = 0;i < pheader->numverts;i++)
1983         {
1984                 vertbonecounts[i] = BigLong(bonecount[i]);
1985                 if (vertbonecounts[i] != 1)
1986                         Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1987         }
1988
1989         loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1990
1991         meshvertices = pheader->numverts;
1992         meshtriangles = pheader->numtris;
1993
1994         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1995         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1996         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1997         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * (sizeof(float[14]) + sizeof(unsigned short) + sizeof(unsigned char[2][4])) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]));
1998         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1999         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2000         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2001         loadmodel->surfmesh.num_vertices = meshvertices;
2002         loadmodel->surfmesh.num_triangles = meshtriangles;
2003         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2004         if (r_enableshadowvolumes.integer)
2005         {
2006                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2007         }
2008         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2009         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2010         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2011         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2012         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2013         loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2014         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2015         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2016         loadmodel->surfmesh.num_blends = 0;
2017         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2018         if (loadmodel->surfmesh.num_vertices <= 65536)
2019         {
2020                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2021         }
2022         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2023         loadmodel->surfmesh.data_blendweights = NULL;
2024
2025         //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
2026         poses = (float *) (pheader->lump_poses.start + pbase);
2027         // figure out scale of model from root bone, for compatibility with old zmodel versions
2028         tempvec[0] = BigFloat(poses[0]);
2029         tempvec[1] = BigFloat(poses[1]);
2030         tempvec[2] = BigFloat(poses[2]);
2031         modelscale = VectorLength(tempvec);
2032         biggestorigin = 0;
2033         for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
2034         {
2035                 f = fabs(BigFloat(poses[i]));
2036                 biggestorigin = max(biggestorigin, f);
2037         }
2038         loadmodel->num_posescale = biggestorigin / 32767.0f;
2039         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2040         for (i = 0;i < numposes;i++)
2041         {
2042                 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
2043                 for (j = 0;j < loadmodel->num_bones;j++)
2044                 {
2045                         float pose[12];
2046                         matrix4x4_t posematrix;
2047                         for (k = 0;k < 12;k++)
2048                                 pose[k] = BigFloat(frameposes[j*12+k]);
2049                         //if (j < loadmodel->num_bones)
2050                         //      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));
2051                         // scale child bones to match the root scale
2052                         if (loadmodel->data_bones[j].parent >= 0)
2053                         {
2054                                 pose[3] *= modelscale;
2055                                 pose[7] *= modelscale;
2056                                 pose[11] *= modelscale;
2057                         }
2058                         // normalize rotation matrix
2059                         VectorNormalize(pose + 0);
2060                         VectorNormalize(pose + 4);
2061                         VectorNormalize(pose + 8);
2062                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2063                         Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2064                 }
2065         }
2066
2067         //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2068         verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2069         vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2070         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2071         // (converting from weight-blending skeletal animation to
2072         //  deformation-based skeletal animation)
2073         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2074         for (i = 0;i < loadmodel->num_bones;i++)
2075         {
2076                 float m[12];
2077                 for (k = 0;k < 12;k++)
2078                         m[k] = BigFloat(poses[i*12+k]);
2079                 if (loadmodel->data_bones[i].parent >= 0)
2080                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2081                 else
2082                         for (k = 0;k < 12;k++)
2083                                 bonepose[12*i+k] = m[k];
2084         }
2085         for (j = 0;j < pheader->numverts;j++)
2086         {
2087                 // this format really should have had a per vertexweight weight value...
2088                 // but since it does not, the weighting is completely ignored and
2089                 // only one weight is allowed per vertex
2090                 int boneindex = BigLong(vertdata[j].bonenum);
2091                 const float *m = bonepose + 12 * boneindex;
2092                 float relativeorigin[3];
2093                 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2094                 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2095                 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2096                 // transform the vertex bone weight into the base mesh
2097                 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2098                 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2099                 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2100                 // store the weight as the primary weight on this vertex
2101                 loadmodel->surfmesh.blends[j] = boneindex;
2102                 loadmodel->surfmesh.data_skeletalindex4ub[j*4  ] = boneindex;
2103                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2104                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2105                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2106                 loadmodel->surfmesh.data_skeletalweight4ub[j*4  ] = 255;
2107                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2108                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2109                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2110         }
2111         Z_Free(bonepose);
2112         // normals and tangents are calculated after elements are loaded
2113
2114         //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2115         outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2116         intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2117         for (i = 0;i < pheader->numverts;i++)
2118         {
2119                 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2120                 // flip T coordinate for OpenGL
2121                 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2122         }
2123
2124         //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2125         //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2126         //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2127
2128         //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2129         //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)
2130         // byteswap, validate, and swap winding order of tris
2131         count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2132         if (pheader->lump_render.length != count)
2133                 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2134         renderlist = (int *) (pheader->lump_render.start + pbase);
2135         renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2136         meshtriangles = 0;
2137         for (i = 0;i < loadmodel->num_surfaces;i++)
2138         {
2139                 int firstvertex, lastvertex;
2140                 if (renderlist >= renderlistend)
2141                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2142                 count = BigLong(*renderlist);renderlist++;
2143                 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2144                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2145
2146                 loadmodel->sortedmodelsurfaces[i] = i;
2147                 surface = loadmodel->data_surfaces + i;
2148                 surface->texture = loadmodel->data_textures + i;
2149                 surface->num_firsttriangle = meshtriangles;
2150                 surface->num_triangles = count;
2151                 meshtriangles += surface->num_triangles;
2152
2153                 // load the elements
2154                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2155                 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2156                 {
2157                         outelements[j*3+2] = BigLong(renderlist[0]);
2158                         outelements[j*3+1] = BigLong(renderlist[1]);
2159                         outelements[j*3+0] = BigLong(renderlist[2]);
2160                 }
2161                 // validate the elements and find the used vertex range
2162                 firstvertex = meshvertices;
2163                 lastvertex = 0;
2164                 for (j = 0;j < surface->num_triangles * 3;j++)
2165                 {
2166                         if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2167                                 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2168                         firstvertex = min(firstvertex, outelements[j]);
2169                         lastvertex = max(lastvertex, outelements[j]);
2170                 }
2171                 surface->num_firstvertex = firstvertex;
2172                 surface->num_vertices = lastvertex + 1 - firstvertex;
2173
2174                 // since zym models do not have named sections, reuse their shader
2175                 // name as the section name
2176                 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2177                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2178         }
2179         Mod_FreeSkinFiles(skinfiles);
2180         Mem_Free(vertbonecounts);
2181         Mem_Free(verts);
2182         Mod_MakeSortedSurfaces(loadmodel);
2183
2184         // compute all the mesh information that was not loaded from the file
2185         if (loadmodel->surfmesh.data_element3s)
2186                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2187                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2188         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2189         Mod_BuildBaseBonePoses();
2190         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);
2191         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);
2192         if (loadmodel->surfmesh.data_neighbor3i)
2193                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2194         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2195         if(mod_alias_force_animated.string[0])
2196                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2197
2198         if (!loadmodel->surfmesh.isanimated)
2199         {
2200                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2201                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2202                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2203                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2204                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2205                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2206         }
2207
2208         // because shaders can do somewhat unexpected things, check for unusual features now
2209         for (i = 0;i < loadmodel->num_textures;i++)
2210         {
2211                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2212                         mod->DrawSky = R_Q1BSP_DrawSky;
2213                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2214                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2215         }
2216 }
2217
2218 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2219 {
2220         dpmheader_t *pheader;
2221         dpmframe_t *frames;
2222         dpmbone_t *bone;
2223         dpmmesh_t *dpmmesh;
2224         unsigned char *pbase;
2225         int i, j, k, meshvertices, meshtriangles;
2226         skinfile_t *skinfiles;
2227         unsigned char *data;
2228         float *bonepose;
2229         float biggestorigin, tempvec[3], modelscale;
2230         float f;
2231         float *poses;
2232
2233         pheader = (dpmheader_t *)buffer;
2234         pbase = (unsigned char *)buffer;
2235         if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2236                 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2237         if (BigLong(pheader->type) != 2)
2238                 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2239
2240         loadmodel->modeldatatypestring = "DPM";
2241
2242         loadmodel->type = mod_alias;
2243         loadmodel->synctype = ST_RAND;
2244
2245         // byteswap header
2246         pheader->type = BigLong(pheader->type);
2247         pheader->filesize = BigLong(pheader->filesize);
2248         pheader->mins[0] = BigFloat(pheader->mins[0]);
2249         pheader->mins[1] = BigFloat(pheader->mins[1]);
2250         pheader->mins[2] = BigFloat(pheader->mins[2]);
2251         pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2252         pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2253         pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2254         pheader->yawradius = BigFloat(pheader->yawradius);
2255         pheader->allradius = BigFloat(pheader->allradius);
2256         pheader->num_bones = BigLong(pheader->num_bones);
2257         pheader->num_meshs = BigLong(pheader->num_meshs);
2258         pheader->num_frames = BigLong(pheader->num_frames);
2259         pheader->ofs_bones = BigLong(pheader->ofs_bones);
2260         pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2261         pheader->ofs_frames = BigLong(pheader->ofs_frames);
2262
2263         if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2264         {
2265                 Con_Printf("%s has no geometry\n", loadmodel->name);
2266                 return;
2267         }
2268         if (pheader->num_frames < 1)
2269         {
2270                 Con_Printf("%s has no frames\n", loadmodel->name);
2271                 return;
2272         }
2273
2274         loadmodel->DrawSky = NULL;
2275         loadmodel->DrawAddWaterPlanes = NULL;
2276         loadmodel->Draw = R_Q1BSP_Draw;
2277         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2278         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2279         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2280         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2281         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2282         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2283         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2284         loadmodel->DrawLight = R_Q1BSP_DrawLight;
2285         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2286         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2287         loadmodel->PointSuperContents = NULL;
2288         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2289
2290         // model bbox
2291         // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2292         for (i = 0;i < 3;i++)
2293         {
2294                 loadmodel->normalmins[i] = pheader->mins[i];
2295                 loadmodel->normalmaxs[i] = pheader->maxs[i];
2296                 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2297                 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2298                 loadmodel->rotatedmins[i] = -pheader->allradius;
2299                 loadmodel->rotatedmaxs[i] = pheader->allradius;
2300         }
2301         loadmodel->radius = pheader->allradius;
2302         loadmodel->radius2 = pheader->allradius * pheader->allradius;
2303
2304         // load external .skin files if present
2305         skinfiles = Mod_LoadSkinFiles();
2306         if (loadmodel->numskins < 1)
2307                 loadmodel->numskins = 1;
2308
2309         meshvertices = 0;
2310         meshtriangles = 0;
2311
2312         // gather combined statistics from the meshes
2313         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2314         for (i = 0;i < (int)pheader->num_meshs;i++)
2315         {
2316                 int numverts = BigLong(dpmmesh->num_verts);
2317                 meshvertices += numverts;
2318                 meshtriangles += BigLong(dpmmesh->num_tris);
2319                 dpmmesh++;
2320         }
2321
2322         loadmodel->numframes = pheader->num_frames;
2323         loadmodel->num_bones = pheader->num_bones;
2324         loadmodel->num_poses = loadmodel->numframes;
2325         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
2326         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2327         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2328         // do most allocations as one merged chunk
2329         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + meshvertices * (sizeof(float[14]) + sizeof(unsigned short) + sizeof(unsigned char[2][4])) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t));
2330         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2331         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2332         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2333         loadmodel->surfmesh.num_vertices = meshvertices;
2334         loadmodel->surfmesh.num_triangles = meshtriangles;
2335         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2336         if (r_enableshadowvolumes.integer)
2337         {
2338                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2339         }
2340         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2341         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2342         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2343         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2344         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2345         loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2346         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2347         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2348         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2349         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2350         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2351         loadmodel->surfmesh.num_blends = 0;
2352         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2353         if (meshvertices <= 65536)
2354         {
2355                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2356         }
2357         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2358         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2359
2360         for (i = 0;i < loadmodel->numskins;i++)
2361         {
2362                 loadmodel->skinscenes[i].firstframe = i;
2363                 loadmodel->skinscenes[i].framecount = 1;
2364                 loadmodel->skinscenes[i].loop = true;
2365                 loadmodel->skinscenes[i].framerate = 10;
2366         }
2367
2368         // load the bone info
2369         bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2370         for (i = 0;i < loadmodel->num_bones;i++)
2371         {
2372                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2373                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2374                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2375                 if (loadmodel->data_bones[i].parent >= i)
2376                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2377         }
2378
2379         // load the frames
2380         frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2381         // figure out scale of model from root bone, for compatibility with old dpmodel versions
2382         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2383         tempvec[0] = BigFloat(poses[0]);
2384         tempvec[1] = BigFloat(poses[1]);
2385         tempvec[2] = BigFloat(poses[2]);
2386         modelscale = VectorLength(tempvec);
2387         biggestorigin = 0;
2388         for (i = 0;i < loadmodel->numframes;i++)
2389         {
2390                 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2391                 loadmodel->animscenes[i].firstframe = i;
2392                 loadmodel->animscenes[i].framecount = 1;
2393                 loadmodel->animscenes[i].loop = true;
2394                 loadmodel->animscenes[i].framerate = 10;
2395                 // load the bone poses for this frame
2396                 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2397                 for (j = 0;j < loadmodel->num_bones*12;j++)
2398                 {
2399                         f = fabs(BigFloat(poses[j]));
2400                         biggestorigin = max(biggestorigin, f);
2401                 }
2402                 // stuff not processed here: mins, maxs, yawradius, allradius
2403         }
2404         loadmodel->num_posescale = biggestorigin / 32767.0f;
2405         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2406         for (i = 0;i < loadmodel->numframes;i++)
2407         {
2408                 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2409                 for (j = 0;j < loadmodel->num_bones;j++)
2410                 {
2411                         float pose[12];
2412                         matrix4x4_t posematrix;
2413                         for (k = 0;k < 12;k++)
2414                                 pose[k] = BigFloat(frameposes[j*12+k]);
2415                         // scale child bones to match the root scale
2416                         if (loadmodel->data_bones[j].parent >= 0)
2417                         {
2418                                 pose[3] *= modelscale;
2419                                 pose[7] *= modelscale;
2420                                 pose[11] *= modelscale;
2421                         }
2422                         // normalize rotation matrix
2423                         VectorNormalize(pose + 0);
2424                         VectorNormalize(pose + 4);
2425                         VectorNormalize(pose + 8);
2426                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2427                         Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2428                 }
2429         }
2430
2431         // load the meshes now
2432         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2433         meshvertices = 0;
2434         meshtriangles = 0;
2435         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2436         // (converting from weight-blending skeletal animation to
2437         //  deformation-based skeletal animation)
2438         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2439         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2440         for (i = 0;i < loadmodel->num_bones;i++)
2441         {
2442                 float m[12];
2443                 for (k = 0;k < 12;k++)
2444                         m[k] = BigFloat(poses[i*12+k]);
2445                 if (loadmodel->data_bones[i].parent >= 0)
2446                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2447                 else
2448                         for (k = 0;k < 12;k++)
2449                                 bonepose[12*i+k] = m[k];
2450         }
2451         for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2452         {
2453                 const int *inelements;
2454                 int *outelements;
2455                 const float *intexcoord;
2456                 msurface_t *surface;
2457
2458                 loadmodel->sortedmodelsurfaces[i] = i;
2459                 surface = loadmodel->data_surfaces + i;
2460                 surface->texture = loadmodel->data_textures + i;
2461                 surface->num_firsttriangle = meshtriangles;
2462                 surface->num_triangles = BigLong(dpmmesh->num_tris);
2463                 surface->num_firstvertex = meshvertices;
2464                 surface->num_vertices = BigLong(dpmmesh->num_verts);
2465                 meshvertices += surface->num_vertices;
2466                 meshtriangles += surface->num_triangles;
2467
2468                 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2469                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2470                 for (j = 0;j < surface->num_triangles;j++)
2471                 {
2472                         // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2473                         outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
2474                         outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
2475                         outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
2476                         inelements += 3;
2477                         outelements += 3;
2478                 }
2479
2480                 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2481                 for (j = 0;j < surface->num_vertices*2;j++)
2482                         loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2483
2484                 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2485                 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2486                 {
2487                         int weightindex[4] = { 0, 0, 0, 0 };
2488                         float weightinfluence[4] = { 0, 0, 0, 0 };
2489                         int l;
2490                         int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2491                         data += sizeof(dpmvertex_t);
2492                         for (k = 0;k < numweights;k++)
2493                         {
2494                                 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2495                                 int boneindex = BigLong(vert->bonenum);
2496                                 const float *m = bonepose + 12 * boneindex;
2497                                 float influence = BigFloat(vert->influence);
2498                                 float relativeorigin[3], relativenormal[3];
2499                                 relativeorigin[0] = BigFloat(vert->origin[0]);
2500                                 relativeorigin[1] = BigFloat(vert->origin[1]);
2501                                 relativeorigin[2] = BigFloat(vert->origin[2]);
2502                                 relativenormal[0] = BigFloat(vert->normal[0]);
2503                                 relativenormal[1] = BigFloat(vert->normal[1]);
2504                                 relativenormal[2] = BigFloat(vert->normal[2]);
2505                                 // blend the vertex bone weights into the base mesh
2506                                 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2507                                 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2508                                 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2509                                 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2510                                 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2511                                 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2512                                 if (!k)
2513                                 {
2514                                         // store the first (and often only) weight
2515                                         weightinfluence[0] = influence;
2516                                         weightindex[0] = boneindex;
2517                                 }
2518                                 else
2519                                 {
2520                                         // sort the new weight into this vertex's weight table
2521                                         // (which only accepts up to 4 bones per vertex)
2522                                         for (l = 0;l < 4;l++)
2523                                         {
2524                                                 if (weightinfluence[l] < influence)
2525                                                 {
2526                                                         // move weaker influence weights out of the way first
2527                                                         int l2;
2528                                                         for (l2 = 3;l2 > l;l2--)
2529                                                         {
2530                                                                 weightinfluence[l2] = weightinfluence[l2-1];
2531                                                                 weightindex[l2] = weightindex[l2-1];
2532                                                         }
2533                                                         // store the new weight
2534                                                         weightinfluence[l] = influence;
2535                                                         weightindex[l] = boneindex;
2536                                                         break;
2537                                                 }
2538                                         }
2539                                 }
2540                                 data += sizeof(dpmbonevert_t);
2541                         }
2542                         loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2543                         loadmodel->surfmesh.data_skeletalindex4ub[j*4  ] = weightindex[0];
2544                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2545                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2546                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2547                         loadmodel->surfmesh.data_skeletalweight4ub[j*4  ] = (unsigned char)(weightinfluence[0]*255.0f);
2548                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2549                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2550                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2551                 }
2552
2553                 // since dpm models do not have named sections, reuse their shader name as the section name
2554                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2555
2556                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2557         }
2558         if (loadmodel->surfmesh.num_blends < meshvertices)
2559                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2560         Z_Free(bonepose);
2561         Mod_FreeSkinFiles(skinfiles);
2562         Mod_MakeSortedSurfaces(loadmodel);
2563
2564         // compute all the mesh information that was not loaded from the file
2565         if (loadmodel->surfmesh.data_element3s)
2566                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2567                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2568         Mod_BuildBaseBonePoses();
2569         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);
2570         if (loadmodel->surfmesh.data_neighbor3i)
2571                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2572         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2573         if(mod_alias_force_animated.string[0])
2574                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2575
2576         if (!loadmodel->surfmesh.isanimated)
2577         {
2578                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2579                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2580                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2581                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2582                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2583                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2584         }
2585
2586         // because shaders can do somewhat unexpected things, check for unusual features now
2587         for (i = 0;i < loadmodel->num_textures;i++)
2588         {
2589                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2590                         mod->DrawSky = R_Q1BSP_DrawSky;
2591                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2592                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2593         }
2594 }
2595
2596 // no idea why PSK/PSA files contain weird quaternions but they do...
2597 #define PSKQUATNEGATIONS
2598 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2599 {
2600         int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2601         int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2602         fs_offset_t filesize;
2603         pskpnts_t *pnts;
2604         pskvtxw_t *vtxw;
2605         pskface_t *faces;
2606         pskmatt_t *matts;
2607         pskboneinfo_t *bones;
2608         pskrawweights_t *rawweights;
2609         //pskboneinfo_t *animbones;
2610         pskaniminfo_t *anims;
2611         pskanimkeys_t *animkeys;
2612         void *animfilebuffer, *animbuffer, *animbufferend;
2613         unsigned char *data;
2614         pskchunk_t *pchunk;
2615         skinfile_t *skinfiles;
2616         char animname[MAX_QPATH];
2617         size_t size;
2618         float biggestorigin;
2619
2620         pchunk = (pskchunk_t *)buffer;
2621         if (strcmp(pchunk->id, "ACTRHEAD"))
2622                 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2623
2624         loadmodel->modeldatatypestring = "PSK";
2625
2626         loadmodel->type = mod_alias;
2627         loadmodel->DrawSky = NULL;
2628         loadmodel->DrawAddWaterPlanes = NULL;
2629         loadmodel->Draw = R_Q1BSP_Draw;
2630         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2631         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2632         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2633         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2634         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2635         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2636         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2637         loadmodel->DrawLight = R_Q1BSP_DrawLight;
2638         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2639         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2640         loadmodel->PointSuperContents = NULL;
2641         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2642         loadmodel->synctype = ST_RAND;
2643
2644         FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2645         strlcat(animname, ".psa", sizeof(animname));
2646         animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2647         animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2648         if (!animbuffer)
2649                 animbufferend = animbuffer;
2650
2651         numpnts = 0;
2652         pnts = NULL;
2653         numvtxw = 0;
2654         vtxw = NULL;
2655         numfaces = 0;
2656         faces = NULL;
2657         nummatts = 0;
2658         matts = NULL;
2659         numbones = 0;
2660         bones = NULL;
2661         numrawweights = 0;
2662         rawweights = NULL;
2663         numanims = 0;
2664         anims = NULL;
2665         numanimkeys = 0;
2666         animkeys = NULL;
2667
2668         while (buffer < bufferend)
2669         {
2670                 pchunk = (pskchunk_t *)buffer;
2671                 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2672                 version = LittleLong(pchunk->version);
2673                 recordsize = LittleLong(pchunk->recordsize);
2674                 numrecords = LittleLong(pchunk->numrecords);
2675                 if (developer_extra.integer)
2676                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2677                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2678                         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);
2679                 if (!strcmp(pchunk->id, "ACTRHEAD"))
2680                 {
2681                         // nothing to do
2682                 }
2683                 else if (!strcmp(pchunk->id, "PNTS0000"))
2684                 {
2685                         pskpnts_t *p;
2686                         if (recordsize != sizeof(*p))
2687                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2688                         // byteswap in place and keep the pointer
2689                         numpnts = numrecords;
2690                         pnts = (pskpnts_t *)buffer;
2691                         for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2692                         {
2693                                 p->origin[0] = LittleFloat(p->origin[0]);
2694                                 p->origin[1] = LittleFloat(p->origin[1]);
2695                                 p->origin[2] = LittleFloat(p->origin[2]);
2696                         }
2697                         buffer = p;
2698                 }
2699                 else if (!strcmp(pchunk->id, "VTXW0000"))
2700                 {
2701                         pskvtxw_t *p;
2702                         if (recordsize != sizeof(*p))
2703                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2704                         // byteswap in place and keep the pointer
2705                         numvtxw = numrecords;
2706                         vtxw = (pskvtxw_t *)buffer;
2707                         for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2708                         {
2709                                 p->pntsindex = LittleShort(p->pntsindex);
2710                                 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2711                                 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2712                                 if (p->pntsindex >= numpnts)
2713                                 {
2714                                         Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2715                                         p->pntsindex = 0;
2716                                 }
2717                         }
2718                         buffer = p;
2719                 }
2720                 else if (!strcmp(pchunk->id, "FACE0000"))
2721                 {
2722                         pskface_t *p;
2723                         if (recordsize != sizeof(*p))
2724                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2725                         // byteswap in place and keep the pointer
2726                         numfaces = numrecords;
2727                         faces = (pskface_t *)buffer;
2728                         for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2729                         {
2730                                 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2731                                 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2732                                 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2733                                 p->group = LittleLong(p->group);
2734                                 if (p->vtxwindex[0] >= numvtxw)
2735                                 {
2736                                         Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2737                                         p->vtxwindex[0] = 0;
2738                                 }
2739                                 if (p->vtxwindex[1] >= numvtxw)
2740                                 {
2741                                         Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2742                                         p->vtxwindex[1] = 0;
2743                                 }
2744                                 if (p->vtxwindex[2] >= numvtxw)
2745                                 {
2746                                         Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2747                                         p->vtxwindex[2] = 0;
2748                                 }
2749                         }
2750                         buffer = p;
2751                 }
2752                 else if (!strcmp(pchunk->id, "MATT0000"))
2753                 {
2754                         pskmatt_t *p;
2755                         if (recordsize != sizeof(*p))
2756                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2757                         // byteswap in place and keep the pointer
2758                         nummatts = numrecords;
2759                         matts = (pskmatt_t *)buffer;
2760                         for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2761                         {
2762                                 // nothing to do
2763                         }
2764                         buffer = p;
2765                 }
2766                 else if (!strcmp(pchunk->id, "REFSKELT"))
2767                 {
2768                         pskboneinfo_t *p;
2769                         if (recordsize != sizeof(*p))
2770                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2771                         // byteswap in place and keep the pointer
2772                         numbones = numrecords;
2773                         bones = (pskboneinfo_t *)buffer;
2774                         for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2775                         {
2776                                 p->numchildren = LittleLong(p->numchildren);
2777                                 p->parent = LittleLong(p->parent);
2778                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2779                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2780                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2781                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2782                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2783                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2784                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2785                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2786                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2787                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2788                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2789 #ifdef PSKQUATNEGATIONS
2790                                 if (index)
2791                                 {
2792                                         p->basepose.quat[0] *= -1;
2793                                         p->basepose.quat[1] *= -1;
2794                                         p->basepose.quat[2] *= -1;
2795                                 }
2796                                 else
2797                                 {
2798                                         p->basepose.quat[0] *=  1;
2799                                         p->basepose.quat[1] *= -1;
2800                                         p->basepose.quat[2] *=  1;
2801                                 }
2802 #endif
2803                                 if (p->parent < 0 || p->parent >= numbones)
2804                                 {
2805                                         Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2806                                         p->parent = 0;
2807                                 }
2808                         }
2809                         buffer = p;
2810                 }
2811                 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2812                 {
2813                         pskrawweights_t *p;
2814                         if (recordsize != sizeof(*p))
2815                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2816                         // byteswap in place and keep the pointer
2817                         numrawweights = numrecords;
2818                         rawweights = (pskrawweights_t *)buffer;
2819                         for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2820                         {
2821                                 p->weight = LittleFloat(p->weight);
2822                                 p->pntsindex = LittleLong(p->pntsindex);
2823                                 p->boneindex = LittleLong(p->boneindex);
2824                                 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2825                                 {
2826                                         Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2827                                         p->pntsindex = 0;
2828                                 }
2829                                 if (p->boneindex < 0 || p->boneindex >= numbones)
2830                                 {
2831                                         Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2832                                         p->boneindex = 0;
2833                                 }
2834                         }
2835                         buffer = p;
2836                 }
2837         }
2838
2839         while (animbuffer < animbufferend)
2840         {
2841                 pchunk = (pskchunk_t *)animbuffer;
2842                 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2843                 version = LittleLong(pchunk->version);
2844                 recordsize = LittleLong(pchunk->recordsize);
2845                 numrecords = LittleLong(pchunk->numrecords);
2846                 if (developer_extra.integer)
2847                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2848                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2849                         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);
2850                 if (!strcmp(pchunk->id, "ANIMHEAD"))
2851                 {
2852                         // nothing to do
2853                 }
2854                 else if (!strcmp(pchunk->id, "BONENAMES"))
2855                 {
2856                         pskboneinfo_t *p;
2857                         if (recordsize != sizeof(*p))
2858                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2859                         // byteswap in place and keep the pointer
2860                         numanimbones = numrecords;
2861                         //animbones = (pskboneinfo_t *)animbuffer;
2862                         // NOTE: supposedly psa does not need to match the psk model, the
2863                         // bones missing from the psa would simply use their base
2864                         // positions from the psk, but this is hard for me to implement
2865                         // and people can easily make animations that match.
2866                         if (numanimbones != numbones)
2867                                 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2868                         for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2869                         {
2870                                 p->numchildren = LittleLong(p->numchildren);
2871                                 p->parent = LittleLong(p->parent);
2872                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2873                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2874                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2875                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2876                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2877                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2878                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2879                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2880                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2881                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2882                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2883 #ifdef PSKQUATNEGATIONS
2884                                 if (index)
2885                                 {
2886                                         p->basepose.quat[0] *= -1;
2887                                         p->basepose.quat[1] *= -1;
2888                                         p->basepose.quat[2] *= -1;
2889                                 }
2890                                 else
2891                                 {
2892                                         p->basepose.quat[0] *=  1;
2893                                         p->basepose.quat[1] *= -1;
2894                                         p->basepose.quat[2] *=  1;
2895                                 }
2896 #endif
2897                                 if (p->parent < 0 || p->parent >= numanimbones)
2898                                 {
2899                                         Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2900                                         p->parent = 0;
2901                                 }
2902                                 // check that bones are the same as in the base
2903                                 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2904                                         Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2905                         }
2906                         animbuffer = p;
2907                 }
2908                 else if (!strcmp(pchunk->id, "ANIMINFO"))
2909                 {
2910                         pskaniminfo_t *p;
2911                         if (recordsize != sizeof(*p))
2912                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2913                         // byteswap in place and keep the pointer
2914                         numanims = numrecords;
2915                         anims = (pskaniminfo_t *)animbuffer;
2916                         for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2917                         {
2918                                 p->numbones = LittleLong(p->numbones);
2919                                 p->playtime = LittleFloat(p->playtime);
2920                                 p->fps = LittleFloat(p->fps);
2921                                 p->firstframe = LittleLong(p->firstframe);
2922                                 p->numframes = LittleLong(p->numframes);
2923                                 if (p->numbones != numbones)
2924                                         Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2925                         }
2926                         animbuffer = p;
2927                 }
2928                 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2929                 {
2930                         pskanimkeys_t *p;
2931                         if (recordsize != sizeof(*p))
2932                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2933                         numanimkeys = numrecords;
2934                         animkeys = (pskanimkeys_t *)animbuffer;
2935                         for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2936                         {
2937                                 p->origin[0] = LittleFloat(p->origin[0]);
2938                                 p->origin[1] = LittleFloat(p->origin[1]);
2939                                 p->origin[2] = LittleFloat(p->origin[2]);
2940                                 p->quat[0] = LittleFloat(p->quat[0]);
2941                                 p->quat[1] = LittleFloat(p->quat[1]);
2942                                 p->quat[2] = LittleFloat(p->quat[2]);
2943                                 p->quat[3] = LittleFloat(p->quat[3]);
2944                                 p->frametime = LittleFloat(p->frametime);
2945 #ifdef PSKQUATNEGATIONS
2946                                 if (index % numbones)
2947                                 {
2948                                         p->quat[0] *= -1;
2949                                         p->quat[1] *= -1;
2950                                         p->quat[2] *= -1;
2951                                 }
2952                                 else
2953                                 {
2954                                         p->quat[0] *=  1;
2955                                         p->quat[1] *= -1;
2956                                         p->quat[2] *=  1;
2957                                 }
2958 #endif
2959                         }
2960                         animbuffer = p;
2961                         // TODO: allocate bonepose stuff
2962                 }
2963                 else
2964                         Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2965         }
2966
2967         if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
2968                 Host_Error("%s: missing required chunks", loadmodel->name);
2969
2970         if (numanims)
2971         {
2972                 loadmodel->numframes = 0;
2973                 for (index = 0;index < numanims;index++)
2974                         loadmodel->numframes += anims[index].numframes;
2975                 if (numanimkeys != numbones * loadmodel->numframes)
2976                         Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2977         }
2978         else
2979                 loadmodel->numframes = loadmodel->num_poses = 1;
2980
2981         meshvertices = numvtxw;
2982         meshtriangles = numfaces;
2983
2984         // load external .skin files if present
2985         skinfiles = Mod_LoadSkinFiles();
2986         if (loadmodel->numskins < 1)
2987                 loadmodel->numskins = 1;
2988         loadmodel->num_bones = numbones;
2989         loadmodel->num_poses = loadmodel->numframes;
2990         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2991         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2992         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2993         loadmodel->surfmesh.num_vertices = meshvertices;
2994         loadmodel->surfmesh.num_triangles = meshtriangles;
2995         // do most allocations as one merged chunk
2996         size = loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + (r_enableshadowvolumes.integer ? loadmodel->surfmesh.num_triangles * sizeof(int[3]) : 0)  + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned short) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t) + ((loadmodel->surfmesh.num_vertices <= 65536) ? (loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0);
2997         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2998         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2999         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3000         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3001         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
3002         if (r_enableshadowvolumes.integer)
3003         {
3004                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
3005         }
3006         loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3007         loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3008         loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3009         loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3010         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3011         loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3012         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3013         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3014         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3015         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
3016         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
3017         loadmodel->surfmesh.num_blends = 0;
3018         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
3019         if (loadmodel->surfmesh.num_vertices <= 65536)
3020         {
3021                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
3022         }
3023         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
3024         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
3025
3026         for (i = 0;i < loadmodel->numskins;i++)
3027         {
3028                 loadmodel->skinscenes[i].firstframe = i;
3029                 loadmodel->skinscenes[i].framecount = 1;
3030                 loadmodel->skinscenes[i].loop = true;
3031                 loadmodel->skinscenes[i].framerate = 10;
3032         }
3033
3034         // create surfaces
3035         for (index = 0, i = 0;index < nummatts;index++)
3036         {
3037                 // since psk models do not have named sections, reuse their shader name as the section name
3038                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
3039                 loadmodel->sortedmodelsurfaces[index] = index;
3040                 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
3041                 loadmodel->data_surfaces[index].num_firstvertex = 0;
3042                 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
3043         }
3044
3045         // copy over the vertex locations and texcoords
3046         for (index = 0;index < numvtxw;index++)
3047         {
3048                 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
3049                 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
3050                 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
3051                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
3052                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
3053         }
3054
3055         // loading the faces is complicated because we need to sort them into surfaces by mattindex
3056         for (index = 0;index < numfaces;index++)
3057                 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
3058         for (index = 0, i = 0;index < nummatts;index++)
3059         {
3060                 loadmodel->data_surfaces[index].num_firsttriangle = i;
3061                 i += loadmodel->data_surfaces[index].num_triangles;
3062                 loadmodel->data_surfaces[index].num_triangles = 0;
3063         }
3064         for (index = 0;index < numfaces;index++)
3065         {
3066                 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
3067                 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
3068                 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
3069                 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
3070         }
3071
3072         // copy over the bones
3073         for (index = 0;index < numbones;index++)
3074         {
3075                 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
3076                 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
3077                 if (loadmodel->data_bones[index].parent >= index)
3078                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
3079         }
3080
3081         // convert the basepose data
3082         if (loadmodel->num_bones)
3083         {
3084                 int boneindex;
3085                 matrix4x4_t *basebonepose;
3086                 float *outinvmatrix = loadmodel->data_baseboneposeinverse;
3087                 matrix4x4_t bonematrix;
3088                 matrix4x4_t tempbonematrix;
3089                 basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
3090                 for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
3091                 {
3092                         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]);
3093                         if (loadmodel->data_bones[boneindex].parent >= 0)
3094                         {
3095                                 tempbonematrix = bonematrix;
3096                                 Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
3097                         }
3098                         basebonepose[boneindex] = bonematrix;
3099                         Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
3100                         Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
3101                 }
3102                 Mem_Free(basebonepose);
3103         }
3104
3105         // sort the psk point weights into the vertex weight tables
3106         // (which only accept up to 4 bones per vertex)
3107         for (index = 0;index < numvtxw;index++)
3108         {
3109                 int weightindex[4] = { 0, 0, 0, 0 };
3110                 float weightinfluence[4] = { 0, 0, 0, 0 };
3111                 int l;
3112                 for (j = 0;j < numrawweights;j++)
3113                 {
3114                         if (rawweights[j].pntsindex == vtxw[index].pntsindex)
3115                         {
3116                                 int boneindex = rawweights[j].boneindex;
3117                                 float influence = rawweights[j].weight;
3118                                 for (l = 0;l < 4;l++)
3119                                 {
3120                                         if (weightinfluence[l] < influence)
3121                                         {
3122                                                 // move lower influence weights out of the way first
3123                                                 int l2;
3124                                                 for (l2 = 3;l2 > l;l2--)
3125                                                 {
3126                                                         weightinfluence[l2] = weightinfluence[l2-1];
3127                                                         weightindex[l2] = weightindex[l2-1];
3128                                                 }
3129                                                 // store the new weight
3130                                                 weightinfluence[l] = influence;
3131                                                 weightindex[l] = boneindex;
3132                                                 break;
3133                                         }
3134                                 }
3135                         }
3136                 }
3137                 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3138                 loadmodel->surfmesh.data_skeletalindex4ub[index*4  ] = weightindex[0];
3139                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1];
3140                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2];
3141                 loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3];
3142                 loadmodel->surfmesh.data_skeletalweight4ub[index*4  ] = (unsigned char)(weightinfluence[0]*255.0f);
3143                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
3144                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
3145                 loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
3146         }
3147         if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3148                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3149
3150         // set up the animscenes based on the anims
3151         if (numanims)
3152         {
3153                 for (index = 0, i = 0;index < numanims;index++)
3154                 {
3155                         for (j = 0;j < anims[index].numframes;j++, i++)
3156                         {
3157                                 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3158                                 loadmodel->animscenes[i].firstframe = i;
3159                                 loadmodel->animscenes[i].framecount = 1;
3160                                 loadmodel->animscenes[i].loop = true;
3161                                 loadmodel->animscenes[i].framerate = anims[index].fps;
3162                         }
3163                 }
3164                 // calculate the scaling value for bone origins so they can be compressed to short
3165                 biggestorigin = 0;
3166                 for (index = 0;index < numanimkeys;index++)
3167                 {
3168                         pskanimkeys_t *k = animkeys + index;
3169                         biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3170                         biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3171                         biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3172                 }
3173                 loadmodel->num_posescale = biggestorigin / 32767.0f;
3174                 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3175         
3176                 // load the poses from the animkeys
3177                 for (index = 0;index < numanimkeys;index++)
3178                 {
3179                         pskanimkeys_t *k = animkeys + index;
3180                         float quat[4];
3181                         Vector4Copy(k->quat, quat);
3182                         if (quat[3] > 0)
3183                                 Vector4Negate(quat, quat);
3184                         Vector4Normalize2(quat, quat);
3185                         // compress poses to the short[7] format for longterm storage
3186                         loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale;
3187                         loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale;
3188                         loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale;
3189                         loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3190                         loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3191                         loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3192                         loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3193                 }
3194         }
3195         else
3196         {
3197                 strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name));
3198                 loadmodel->animscenes[0].firstframe = 0;
3199                 loadmodel->animscenes[0].framecount = 1;
3200                 loadmodel->animscenes[0].loop = true;
3201                 loadmodel->animscenes[0].framerate = 10;
3202
3203                 // calculate the scaling value for bone origins so they can be compressed to short
3204                 biggestorigin = 0;
3205                 for (index = 0;index < numbones;index++)
3206                 {
3207                         pskboneinfo_t *p = bones + index;
3208                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0]));
3209                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1]));
3210                         biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2]));
3211                 }
3212                 loadmodel->num_posescale = biggestorigin / 32767.0f;
3213                 loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3214         
3215                 // load the basepose as a frame
3216                 for (index = 0;index < numbones;index++)
3217                 {
3218                         pskboneinfo_t *p = bones + index;
3219                         float quat[4];
3220                         Vector4Copy(p->basepose.quat, quat);
3221                         if (quat[3] > 0)
3222                                 Vector4Negate(quat, quat);
3223                         Vector4Normalize2(quat, quat);
3224                         // compress poses to the short[7] format for longterm storage
3225                         loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
3226                         loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
3227                         loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
3228                         loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f;
3229                         loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f;
3230                         loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f;
3231                         loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f;
3232                 }
3233         }
3234
3235         Mod_FreeSkinFiles(skinfiles);
3236         if (animfilebuffer)
3237                 Mem_Free(animfilebuffer);
3238         Mod_MakeSortedSurfaces(loadmodel);
3239
3240         // compute all the mesh information that was not loaded from the file
3241         // TODO: honor smoothing groups somehow?
3242         if (loadmodel->surfmesh.data_element3s)
3243                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3244                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3245         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3246         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);
3247         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);
3248         if (loadmodel->surfmesh.data_neighbor3i)
3249                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
3250         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
3251         if(mod_alias_force_animated.string[0])
3252                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
3253
3254         if (!loadmodel->surfmesh.isanimated)
3255         {
3256                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3257                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3258                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
3259                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3260                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3261                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3262         }
3263
3264         // because shaders can do somewhat unexpected things, check for unusual features now
3265         for (i = 0;i < loadmodel->num_textures;i++)
3266         {
3267                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
3268                         mod->DrawSky = R_Q1BSP_DrawSky;
3269                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
3270                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
3271         }
3272 }
3273
3274 void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
3275 {
3276         unsigned char *data;
3277         const char *text;
3278         const unsigned char *pbase, *pend;
3279         iqmheader_t header;
3280         skinfile_t *skinfiles;
3281         int i, j, k, meshvertices, meshtriangles;
3282         float biggestorigin;
3283         const unsigned int *inelements;
3284         int *outelements;
3285         const int *inneighbors;
3286         int *outneighbors;
3287         float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor;
3288         // this pointers into the file data are read only through Little* functions so they can be unaligned memory
3289         const float *vnormal = NULL;
3290         const float *vposition = NULL;
3291         const float *vtangent = NULL;
3292         const float *vtexcoord = NULL;
3293         const float *vcolor4f = NULL;
3294         const unsigned char *vblendindexes = NULL;
3295         const unsigned char *vblendweights = NULL;
3296   &nb