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