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