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