CSQC polygonbegin functionality now uses the CL_MeshEntities system, this finally...
[xonotic/darkplaces.git] / model_alias.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21 #include "quakedef.h"
22 #include "image.h"
23 #include "r_shadow.h"
24 #include "mod_skeletal_animatevertices_generic.h"
25 #ifdef SSE_POSSIBLE
26 #include "mod_skeletal_animatevertices_sse.h"
27 #endif
28
29 #ifdef SSE_POSSIBLE
30 static qboolean r_skeletal_use_sse_defined = false;
31 cvar_t r_skeletal_use_sse = {0, "r_skeletal_use_sse", "1", "use SSE for skeletal model animation"};
32 #endif
33 cvar_t r_skeletal_debugbone = {0, "r_skeletal_debugbone", "-1", "development cvar for testing skeletal model code"};
34 cvar_t r_skeletal_debugbonecomponent = {0, "r_skeletal_debugbonecomponent", "3", "development cvar for testing skeletal model code"};
35 cvar_t r_skeletal_debugbonevalue = {0, "r_skeletal_debugbonevalue", "100", "development cvar for testing skeletal model code"};
36 cvar_t r_skeletal_debugtranslatex = {0, "r_skeletal_debugtranslatex", "1", "development cvar for testing skeletal model code"};
37 cvar_t r_skeletal_debugtranslatey = {0, "r_skeletal_debugtranslatey", "1", "development cvar for testing skeletal model code"};
38 cvar_t r_skeletal_debugtranslatez = {0, "r_skeletal_debugtranslatez", "1", "development cvar for testing skeletal model code"};
39 cvar_t mod_alias_supporttagscale = {0, "mod_alias_supporttagscale", "1", "support scaling factors in bone/tag attachment matrices as supported by MD3"};
40 cvar_t mod_alias_force_animated = {0, "mod_alias_force_animated", "", "if set to an non-empty string, overrides the is-animated flag of any alias models (for benchmarking)"};
41
42 float mod_md3_sin[320];
43
44 static size_t Mod_Skeletal_AnimateVertices_maxbonepose = 0;
45 static void *Mod_Skeletal_AnimateVertices_bonepose = NULL;
46 void Mod_Skeletal_FreeBuffers(void)
47 {
48         if(Mod_Skeletal_AnimateVertices_bonepose)
49                 Mem_Free(Mod_Skeletal_AnimateVertices_bonepose);
50         Mod_Skeletal_AnimateVertices_maxbonepose = 0;
51         Mod_Skeletal_AnimateVertices_bonepose = NULL;
52 }
53 void *Mod_Skeletal_AnimateVertices_AllocBuffers(size_t nbytes)
54 {
55         if(Mod_Skeletal_AnimateVertices_maxbonepose < nbytes)
56         {
57                 if(Mod_Skeletal_AnimateVertices_bonepose)
58                         Mem_Free(Mod_Skeletal_AnimateVertices_bonepose);
59                 Mod_Skeletal_AnimateVertices_bonepose = Z_Malloc(nbytes);
60                 Mod_Skeletal_AnimateVertices_maxbonepose = nbytes;
61         }
62         return Mod_Skeletal_AnimateVertices_bonepose;
63 }
64
65 void Mod_Skeletal_BuildTransforms(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT bonepose, float * RESTRICT boneposerelative)
66 {
67         int i, blends;
68         float m[12];
69
70         if (!bonepose)
71                 bonepose = (float * RESTRICT) Mod_Skeletal_AnimateVertices_AllocBuffers(sizeof(float[12]) * model->num_bones);
72                 
73         if (skeleton && !skeleton->relativetransforms)
74                 skeleton = NULL;
75
76         // interpolate matrices
77         if (skeleton)
78         {
79                 for (i = 0;i < model->num_bones;i++)
80                 {
81                         Matrix4x4_ToArray12FloatD3D(&skeleton->relativetransforms[i], m);
82                         if (model->data_bones[i].parent >= 0)
83                                 R_ConcatTransforms(bonepose + model->data_bones[i].parent * 12, m, bonepose + i * 12);
84                         else
85                                 memcpy(bonepose + i * 12, m, sizeof(m));
86
87                         // create a relative deformation matrix to describe displacement
88                         // from the base mesh, which is used by the actual weighting
89                         R_ConcatTransforms(bonepose + i * 12, model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12);
90                 }
91         }
92         else
93         {
94                 for (i = 0;i < model->num_bones;i++)
95                 {
96                         // blend by transform each quaternion/translation into a dual-quaternion first, then blending
97                         const short * RESTRICT firstpose7s = model->data_poses7s + 7 * (frameblend[0].subframe * model->num_bones + i);
98                         float firstlerp = frameblend[0].lerp,
99                                 firsttx = firstpose7s[0], firstty = firstpose7s[1], firsttz = firstpose7s[2],
100                                 rx = firstpose7s[3] * firstlerp,
101                                 ry = firstpose7s[4] * firstlerp,
102                                 rz = firstpose7s[5] * firstlerp,
103                                 rw = firstpose7s[6] * firstlerp,
104                                 dx = firsttx*rw + firstty*rz - firsttz*ry,
105                                 dy = -firsttx*rz + firstty*rw + firsttz*rx,
106                                 dz = firsttx*ry - firstty*rx + firsttz*rw,
107                                 dw = -firsttx*rx - firstty*ry - firsttz*rz,
108                                 scale, sx, sy, sz, sw;
109                         for (blends = 1;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
110                         {
111                                 const short * RESTRICT blendpose7s = model->data_poses7s + 7 * (frameblend[blends].subframe * model->num_bones + i);
112                                 float blendlerp = frameblend[blends].lerp,
113                                         blendtx = blendpose7s[0], blendty = blendpose7s[1], blendtz = blendpose7s[2],
114                                         qx = blendpose7s[3], qy = blendpose7s[4], qz = blendpose7s[5], qw = blendpose7s[6];
115                                 if(rx*qx + ry*qy + rz*qz + rw*qw < 0) blendlerp = -blendlerp;
116                                 qx *= blendlerp;
117                                 qy *= blendlerp;
118                                 qz *= blendlerp;
119                                 qw *= blendlerp;
120                                 rx += qx;
121                                 ry += qy;
122                                 rz += qz;
123                                 rw += qw;
124                                 dx += blendtx*qw + blendty*qz - blendtz*qy;
125                                 dy += -blendtx*qz + blendty*qw + blendtz*qx;
126                                 dz += blendtx*qy - blendty*qx + blendtz*qw;
127                                 dw += -blendtx*qx - blendty*qy - blendtz*qz;
128                         }
129                         // generate a matrix from the dual-quaternion, implicitly normalizing it in the process
130                         scale = 1.0f / (rx*rx + ry*ry + rz*rz + rw*rw);
131                         sx = rx * scale;
132                         sy = ry * scale;
133                         sz = rz * scale;
134                         sw = rw * scale;
135                         m[0] = sw*rw + sx*rx - sy*ry - sz*rz;
136                         m[1] = 2*(sx*ry - sw*rz);
137                         m[2] = 2*(sx*rz + sw*ry);
138                         m[3] = model->num_posescale*(dx*sw - dy*sz + dz*sy - dw*sx);
139                         m[4] = 2*(sx*ry + sw*rz);
140                         m[5] = sw*rw + sy*ry - sx*rx - sz*rz;
141                         m[6] = 2*(sy*rz - sw*rx);
142                         m[7] = model->num_posescale*(dx*sz + dy*sw - dz*sx - dw*sy);
143                         m[8] = 2*(sx*rz - sw*ry);
144                         m[9] = 2*(sy*rz + sw*rx);
145                         m[10] = sw*rw + sz*rz - sx*rx - sy*ry;
146                         m[11] = model->num_posescale*(dy*sx + dz*sw - dx*sy - dw*sz);
147                         if (i == r_skeletal_debugbone.integer)
148                                 m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value;
149                         m[3] *= r_skeletal_debugtranslatex.value;
150                         m[7] *= r_skeletal_debugtranslatey.value;
151                         m[11] *= r_skeletal_debugtranslatez.value;
152                         if (model->data_bones[i].parent >= 0)
153                                 R_ConcatTransforms(bonepose + model->data_bones[i].parent * 12, m, bonepose + i * 12);
154                         else
155                                 memcpy(bonepose + i * 12, m, sizeof(m));
156                         // create a relative deformation matrix to describe displacement
157                         // from the base mesh, which is used by the actual weighting
158                         R_ConcatTransforms(bonepose + i * 12, model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12);
159                 }
160         }
161 }
162
163 static void Mod_Skeletal_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
164 {
165
166         if (!model->surfmesh.num_vertices)
167                 return;
168
169         if (!model->num_bones)
170         {
171                 if (vertex3f) memcpy(vertex3f, model->surfmesh.data_vertex3f, model->surfmesh.num_vertices*sizeof(float[3]));
172                 if (normal3f) memcpy(normal3f, model->surfmesh.data_normal3f, model->surfmesh.num_vertices*sizeof(float[3]));
173                 if (svector3f) memcpy(svector3f, model->surfmesh.data_svector3f, model->surfmesh.num_vertices*sizeof(float[3]));
174                 if (tvector3f) memcpy(tvector3f, model->surfmesh.data_tvector3f, model->surfmesh.num_vertices*sizeof(float[3]));
175                 return;
176         }
177
178 #ifdef SSE_POSSIBLE
179         if(r_skeletal_use_sse_defined)
180                 if(r_skeletal_use_sse.integer)
181                 {
182                         Mod_Skeletal_AnimateVertices_SSE(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f);
183                         return;
184                 }
185 #endif
186         Mod_Skeletal_AnimateVertices_Generic(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f);
187 }
188
189 void Mod_AliasInit (void)
190 {
191         int i;
192         Cvar_RegisterVariable(&r_skeletal_debugbone);
193         Cvar_RegisterVariable(&r_skeletal_debugbonecomponent);
194         Cvar_RegisterVariable(&r_skeletal_debugbonevalue);
195         Cvar_RegisterVariable(&r_skeletal_debugtranslatex);
196         Cvar_RegisterVariable(&r_skeletal_debugtranslatey);
197         Cvar_RegisterVariable(&r_skeletal_debugtranslatez);
198         Cvar_RegisterVariable(&mod_alias_supporttagscale);
199         Cvar_RegisterVariable(&mod_alias_force_animated);
200         for (i = 0;i < 320;i++)
201                 mod_md3_sin[i] = sin(i * M_PI * 2.0f / 256.0);
202 #ifdef SSE_POSSIBLE
203         if(Sys_HaveSSE())
204         {
205                 Con_Printf("Skeletal animation uses SSE code path\n");
206                 r_skeletal_use_sse_defined = true;
207                 Cvar_RegisterVariable(&r_skeletal_use_sse);
208         }
209         else
210                 Con_Printf("Skeletal animation uses generic code path (SSE disabled or not detected)\n");
211 #else
212         Con_Printf("Skeletal animation uses generic code path (SSE not compiled in)\n");
213 #endif
214 }
215
216 static int Mod_Skeletal_AddBlend(dp_model_t *model, const blendweights_t *newweights)
217 {
218         int i;
219         blendweights_t *weights;
220         if(!newweights->influence[1])
221                 return newweights->index[0];
222         weights = model->surfmesh.data_blendweights;
223         for (i = 0;i < model->surfmesh.num_blends;i++, weights++)
224         {
225                 if (!memcmp(weights, newweights, sizeof(blendweights_t)))
226                         return model->num_bones + i;
227         }
228         model->surfmesh.num_blends++;
229         memcpy(weights, newweights, sizeof(blendweights_t));
230         return model->num_bones + i;
231 }
232
233 static int Mod_Skeletal_CompressBlend(dp_model_t *model, const int *newindex, const float *newinfluence)
234 {
235         int i, total;
236         float scale;
237         blendweights_t newweights;
238         if(!newinfluence[1])
239                 return newindex[0];
240         scale = 0;
241         for (i = 0;i < 4;i++)
242                 scale += newinfluence[i];
243         scale = 255.0f / scale;
244         total = 0;
245         for (i = 0;i < 4;i++)
246         {
247                 newweights.index[i] = newindex[i];
248                 newweights.influence[i] = (unsigned char)(newinfluence[i] * scale);
249                 total += newweights.influence[i];
250         }       
251         while (total > 255)
252         {
253                 for (i = 0;i < 4;i++)
254                 {
255                         if(newweights.influence[i] > 0 && total > 255) 
256                         { 
257                                 newweights.influence[i]--;
258                                 total--; 
259                         }
260                 }
261         }
262         while (total < 255)
263         {
264                 for (i = 0; i < 4;i++)
265                 {
266                         if(newweights.influence[i] < 255 && total < 255) 
267                         { 
268                                 newweights.influence[i]++; 
269                                 total++; 
270                         }
271                 }
272         }
273         return Mod_Skeletal_AddBlend(model, &newweights);
274 }
275
276 static void Mod_MD3_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
277 {
278         // vertex morph
279         int i, numblends, blendnum;
280         int numverts = model->surfmesh.num_vertices;
281         numblends = 0;
282         for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
283         {
284                 //VectorMA(translate, model->surfmesh.num_morphmdlframetranslate, frameblend[blendnum].lerp, translate);
285                 if (frameblend[blendnum].lerp > 0)
286                         numblends = blendnum + 1;
287         }
288         // special case for the first blend because it avoids some adds and the need to memset the arrays first
289         for (blendnum = 0;blendnum < numblends;blendnum++)
290         {
291                 const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].subframe;
292                 if (vertex3f)
293                 {
294                         float scale = frameblend[blendnum].lerp * (1.0f / 64.0f);
295                         if (blendnum == 0)
296                         {
297                                 for (i = 0;i < numverts;i++)
298                                 {
299                                         vertex3f[i * 3 + 0] = verts[i].origin[0] * scale;
300                                         vertex3f[i * 3 + 1] = verts[i].origin[1] * scale;
301                                         vertex3f[i * 3 + 2] = verts[i].origin[2] * scale;
302                                 }
303                         }
304                         else
305                         {
306                                 for (i = 0;i < numverts;i++)
307                                 {
308                                         vertex3f[i * 3 + 0] += verts[i].origin[0] * scale;
309                                         vertex3f[i * 3 + 1] += verts[i].origin[1] * scale;
310                                         vertex3f[i * 3 + 2] += verts[i].origin[2] * scale;
311                                 }
312                         }
313                 }
314                 // the yaw and pitch stored in md3 models are 8bit quantized angles
315                 // (0-255), and as such a lookup table is very well suited to
316                 // decoding them, and since cosine is equivalent to sine with an
317                 // extra 45 degree rotation, this uses one lookup table for both
318                 // sine and cosine with a +64 bias to get cosine.
319                 if (normal3f)
320                 {
321                         float lerp = frameblend[blendnum].lerp;
322                         if (blendnum == 0)
323                         {
324                                 for (i = 0;i < numverts;i++)
325                                 {
326                                         normal3f[i * 3 + 0] = mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch     ] * lerp;
327                                         normal3f[i * 3 + 1] = mod_md3_sin[verts[i].yaw     ] * mod_md3_sin[verts[i].pitch     ] * lerp;
328                                         normal3f[i * 3 + 2] =                                  mod_md3_sin[verts[i].pitch + 64] * lerp;
329                                 }
330                         }
331                         else
332                         {
333                                 for (i = 0;i < numverts;i++)
334                                 {
335                                         normal3f[i * 3 + 0] += mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch     ] * lerp;
336                                         normal3f[i * 3 + 1] += mod_md3_sin[verts[i].yaw     ] * mod_md3_sin[verts[i].pitch     ] * lerp;
337                                         normal3f[i * 3 + 2] +=                                  mod_md3_sin[verts[i].pitch + 64] * lerp;
338                                 }
339                         }
340                 }
341                 if (svector3f)
342                 {
343                         const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
344                         float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
345                         if (blendnum == 0)
346                         {
347                                 for (i = 0;i < numverts;i++, texvecvert++)
348                                 {
349                                         VectorScale(texvecvert->svec, f, svector3f + i*3);
350                                         VectorScale(texvecvert->tvec, f, tvector3f + i*3);
351                                 }
352                         }
353                         else
354                         {
355                                 for (i = 0;i < numverts;i++, texvecvert++)
356                                 {
357                                         VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
358                                         VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
359                                 }
360                         }
361                 }
362         }
363 }
364 static void Mod_MDL_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
365 {
366         // vertex morph
367         int i, numblends, blendnum;
368         int numverts = model->surfmesh.num_vertices;
369         float translate[3];
370         VectorClear(translate);
371         numblends = 0;
372         // blend the frame translates to avoid redundantly doing so on each vertex
373         // (a bit of a brain twister but it works)
374         for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
375         {
376                 if (model->surfmesh.data_morphmd2framesize6f)
377                         VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6 + 3, translate);
378                 else
379                         VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.num_morphmdlframetranslate, translate);
380                 if (frameblend[blendnum].lerp > 0)
381                         numblends = blendnum + 1;
382         }
383         // special case for the first blend because it avoids some adds and the need to memset the arrays first
384         for (blendnum = 0;blendnum < numblends;blendnum++)
385         {
386                 const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].subframe;
387                 if (vertex3f)
388                 {
389                         float scale[3];
390                         if (model->surfmesh.data_morphmd2framesize6f)
391                                 VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6, frameblend[blendnum].lerp, scale);
392                         else
393                                 VectorScale(model->surfmesh.num_morphmdlframescale, frameblend[blendnum].lerp, scale);
394                         if (blendnum == 0)
395                         {
396                                 for (i = 0;i < numverts;i++)
397                                 {
398                                         vertex3f[i * 3 + 0] = translate[0] + verts[i].v[0] * scale[0];
399                                         vertex3f[i * 3 + 1] = translate[1] + verts[i].v[1] * scale[1];
400                                         vertex3f[i * 3 + 2] = translate[2] + verts[i].v[2] * scale[2];
401                                 }
402                         }
403                         else
404                         {
405                                 for (i = 0;i < numverts;i++)
406                                 {
407                                         vertex3f[i * 3 + 0] += verts[i].v[0] * scale[0];
408                                         vertex3f[i * 3 + 1] += verts[i].v[1] * scale[1];
409                                         vertex3f[i * 3 + 2] += verts[i].v[2] * scale[2];
410                                 }
411                         }
412                 }
413                 // the vertex normals in mdl models are an index into a table of
414                 // 162 unique values, this very crude quantization reduces the
415                 // vertex normal to only one byte, which saves a lot of space but
416                 // also makes lighting pretty coarse
417                 if (normal3f)
418                 {
419                         float lerp = frameblend[blendnum].lerp;
420                         if (blendnum == 0)
421                         {
422                                 for (i = 0;i < numverts;i++)
423                                 {
424                                         const float *vn = m_bytenormals[verts[i].lightnormalindex];
425                                         VectorScale(vn, lerp, normal3f + i*3);
426                                 }
427                         }
428                         else
429                         {
430                                 for (i = 0;i < numverts;i++)
431                                 {
432                                         const float *vn = m_bytenormals[verts[i].lightnormalindex];
433                                         VectorMA(normal3f + i*3, lerp, vn, normal3f + i*3);
434                                 }
435                         }
436                 }
437                 if (svector3f)
438                 {
439                         const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
440                         float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
441                         if (blendnum == 0)
442                         {
443                                 for (i = 0;i < numverts;i++, texvecvert++)
444                                 {
445                                         VectorScale(texvecvert->svec, f, svector3f + i*3);
446                                         VectorScale(texvecvert->tvec, f, tvector3f + i*3);
447                                 }
448                         }
449                         else
450                         {
451                                 for (i = 0;i < numverts;i++, texvecvert++)
452                                 {
453                                         VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
454                                         VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
455                                 }
456                         }
457                 }
458         }
459 }
460
461 int Mod_Alias_GetTagMatrix(const dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, matrix4x4_t *outmatrix)
462 {
463         matrix4x4_t temp;
464         matrix4x4_t parentbonematrix;
465         matrix4x4_t tempbonematrix;
466         matrix4x4_t bonematrix;
467         matrix4x4_t blendmatrix;
468         int blendindex;
469         int parenttagindex;
470         int k;
471         float lerp;
472         const float *input;
473         float blendtag[12];
474         *outmatrix = identitymatrix;
475         if (skeleton && skeleton->relativetransforms)
476         {
477                 if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
478                         return 4;
479                 *outmatrix = skeleton->relativetransforms[tagindex];
480                 while ((tagindex = model->data_bones[tagindex].parent) >= 0)
481                 {
482                         temp = *outmatrix;
483                         Matrix4x4_Concat(outmatrix, &skeleton->relativetransforms[tagindex], &temp);
484                 }
485         }
486         else if (model->num_bones)
487         {
488                 if (tagindex < 0 || tagindex >= model->num_bones)
489                         return 4;
490                 Matrix4x4_Clear(&blendmatrix);
491                 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
492                 {
493                         lerp = frameblend[blendindex].lerp;
494                         Matrix4x4_FromBonePose7s(&bonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + tagindex));
495                         parenttagindex = tagindex;
496                         while ((parenttagindex = model->data_bones[parenttagindex].parent) >= 0)
497                         {
498                                 Matrix4x4_FromBonePose7s(&parentbonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + parenttagindex));
499                                 tempbonematrix = bonematrix;
500                                 Matrix4x4_Concat(&bonematrix, &parentbonematrix, &tempbonematrix);
501                         }
502                         Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
503                 }
504                 *outmatrix = blendmatrix;
505         }
506         else if (model->num_tags)
507         {
508                 if (tagindex < 0 || tagindex >= model->num_tags)
509                         return 4;
510                 for (k = 0;k < 12;k++)
511                         blendtag[k] = 0;
512                 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
513                 {
514                         lerp = frameblend[blendindex].lerp;
515                         input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
516                         for (k = 0;k < 12;k++)
517                                 blendtag[k] += input[k] * lerp;
518                 }
519                 Matrix4x4_FromArray12FloatGL(outmatrix, blendtag);
520         }
521
522         if(!mod_alias_supporttagscale.integer)
523                 Matrix4x4_Normalize3(outmatrix, outmatrix);
524
525         return 0;
526 }
527
528 int Mod_Alias_GetExtendedTagInfoForIndex(const dp_model_t *model, unsigned int skin, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
529 {
530         int blendindex;
531         int k;
532         float lerp;
533         matrix4x4_t bonematrix;
534         matrix4x4_t blendmatrix;
535         const float *input;
536         float blendtag[12];
537
538         if (skeleton && skeleton->relativetransforms)
539         {
540                 if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
541                         return 1;
542                 *parentindex = skeleton->model->data_bones[tagindex].parent;
543                 *tagname = skeleton->model->data_bones[tagindex].name;
544                 *tag_localmatrix = skeleton->relativetransforms[tagindex];
545                 return 0;
546         }
547         else if (model->num_bones)
548         {
549                 if (tagindex < 0 || tagindex >= model->num_bones)
550                         return 1;
551                 *parentindex = model->data_bones[tagindex].parent;
552                 *tagname = model->data_bones[tagindex].name;
553                 Matrix4x4_Clear(&blendmatrix);
554                 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
555                 {
556                         lerp = frameblend[blendindex].lerp;
557                         Matrix4x4_FromBonePose7s(&bonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + tagindex));
558                         Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
559                 }
560                 *tag_localmatrix = blendmatrix;
561                 return 0;
562         }
563         else if (model->num_tags)
564         {
565                 if (tagindex < 0 || tagindex >= model->num_tags)
566                         return 1;
567                 *parentindex = -1;
568                 *tagname = model->data_tags[tagindex].name;
569                 for (k = 0;k < 12;k++)
570                         blendtag[k] = 0;
571                 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
572                 {
573                         lerp = frameblend[blendindex].lerp;
574                         input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
575                         for (k = 0;k < 12;k++)
576                                 blendtag[k] += input[k] * lerp;
577                 }
578                 Matrix4x4_FromArray12FloatGL(tag_localmatrix, blendtag);
579                 return 0;
580         }
581
582         return 2;
583 }
584
585 int Mod_Alias_GetTagIndexForName(const dp_model_t *model, unsigned int skin, const char *tagname)
586 {
587         int i;
588         if(skin >= (unsigned int)model->numskins)
589                 skin = 0;
590         if (model->num_bones)
591                 for (i = 0;i < model->num_bones;i++)
592                         if (!strcasecmp(tagname, model->data_bones[i].name))
593                                 return i + 1;
594         if (model->num_tags)
595                 for (i = 0;i < model->num_tags;i++)
596                         if (!strcasecmp(tagname, model->data_tags[i].name))
597                                 return i + 1;
598         return 0;
599 }
600
601 static void Mod_BuildBaseBonePoses(void)
602 {
603         int boneindex;
604         matrix4x4_t *basebonepose;
605         float *outinvmatrix = loadmodel->data_baseboneposeinverse;
606         matrix4x4_t bonematrix;
607         matrix4x4_t tempbonematrix;
608         if (!loadmodel->num_bones)
609                 return;
610         basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
611         for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
612         {
613                 Matrix4x4_FromBonePose7s(&bonematrix, loadmodel->num_posescale, loadmodel->data_poses7s + 7 * boneindex);
614                 if (loadmodel->data_bones[boneindex].parent >= 0)
615                 {
616                         tempbonematrix = bonematrix;
617                         Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
618                 }
619                 basebonepose[boneindex] = bonematrix;
620                 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
621                 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
622         }
623         Mem_Free(basebonepose);
624 }
625
626 static qboolean Mod_Alias_CalculateBoundingBox(void)
627 {
628         int vnum;
629         qboolean firstvertex = true;
630         float dist, yawradius, radius;
631         float *v;
632         qboolean isanimated = false;
633         VectorClear(loadmodel->normalmins);
634         VectorClear(loadmodel->normalmaxs);
635         yawradius = 0;
636         radius = 0;
637         if (loadmodel->AnimateVertices)
638         {
639                 float *vertex3f, *refvertex3f;
640                 frameblend_t frameblend[MAX_FRAMEBLENDS];
641                 memset(frameblend, 0, sizeof(frameblend));
642                 frameblend[0].lerp = 1;
643                 vertex3f = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]) * 2);
644                 refvertex3f = NULL;
645                 for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++)
646                 {
647                         loadmodel->AnimateVertices(loadmodel, frameblend, NULL, vertex3f, NULL, NULL, NULL);
648                         if (!refvertex3f)
649                         {
650                                 // make a copy of the first frame for comparing all others
651                                 refvertex3f = vertex3f + loadmodel->surfmesh.num_vertices * 3;
652                                 memcpy(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
653                         }
654                         else
655                         {
656                                 if (!isanimated && memcmp(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3])))
657                                         isanimated = true;
658                         }
659                         for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
660                         {
661                                 if (firstvertex)
662                                 {
663                                         firstvertex = false;
664                                         VectorCopy(v, loadmodel->normalmins);
665                                         VectorCopy(v, loadmodel->normalmaxs);
666                                 }
667                                 else
668                                 {
669                                         if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
670                                         if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
671                                         if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
672                                         if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
673                                         if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
674                                         if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
675                                 }
676                                 dist = v[0] * v[0] + v[1] * v[1];
677                                 if (yawradius < dist)
678                                         yawradius = dist;
679                                 dist += v[2] * v[2];
680                                 if (radius < dist)
681                                         radius = dist;
682                         }
683                 }
684                 if (vertex3f)
685                         Mem_Free(vertex3f);
686         }
687         else
688         {
689                 for (vnum = 0, v = loadmodel->surfmesh.data_vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
690                 {
691                         if (firstvertex)
692                         {
693                                 firstvertex = false;
694                                 VectorCopy(v, loadmodel->normalmins);
695                                 VectorCopy(v, loadmodel->normalmaxs);
696                         }
697                         else
698                         {
699                                 if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
700                                 if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
701                                 if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
702                                 if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
703                                 if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
704                                 if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
705                         }
706                         dist = v[0] * v[0] + v[1] * v[1];
707                         if (yawradius < dist)
708                                 yawradius = dist;
709                         dist += v[2] * v[2];
710                         if (radius < dist)
711                                 radius = dist;
712                 }
713         }
714         radius = sqrt(radius);
715         yawradius = sqrt(yawradius);
716         loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius;
717         loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = yawradius;
718         loadmodel->yawmins[2] = loadmodel->normalmins[2];
719         loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
720         loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
721         loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
722         loadmodel->radius = radius;
723         loadmodel->radius2 = radius * radius;
724         return isanimated;
725 }
726
727 static void Mod_Alias_MorphMesh_CompileFrames(void)
728 {
729         int i, j;
730         frameblend_t frameblend[MAX_FRAMEBLENDS];
731         unsigned char *datapointer;
732         memset(frameblend, 0, sizeof(frameblend));
733         frameblend[0].lerp = 1;
734         datapointer = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * (sizeof(float[3]) * 4 + loadmodel->surfmesh.num_morphframes * sizeof(texvecvertex_t)));
735         loadmodel->surfmesh.data_vertex3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
736         loadmodel->surfmesh.data_svector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
737         loadmodel->surfmesh.data_tvector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
738         loadmodel->surfmesh.data_normal3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
739         loadmodel->surfmesh.data_morphtexvecvertex = (texvecvertex_t *)datapointer;datapointer += loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices * sizeof(texvecvertex_t);
740         // this counts down from the last frame to the first so that the final data in surfmesh is for frame zero (which is what the renderer expects to be there)
741         for (i = loadmodel->surfmesh.num_morphframes-1;i >= 0;i--)
742         {
743                 frameblend[0].subframe = i;
744                 loadmodel->AnimateVertices(loadmodel, frameblend, NULL, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_normal3f, NULL, NULL);
745                 Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
746                 // encode the svector and tvector in 3 byte format for permanent storage
747                 for (j = 0;j < loadmodel->surfmesh.num_vertices;j++)
748                 {
749                         VectorScaleCast(loadmodel->surfmesh.data_svector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].svec);
750                         VectorScaleCast(loadmodel->surfmesh.data_tvector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].tvec);
751                 }
752         }
753 }
754
755 static void Mod_MDLMD2MD3_TraceLine(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
756 {
757         int i;
758         float segmentmins[3], segmentmaxs[3];
759         msurface_t *surface;
760         float vertex3fbuf[1024 * 3];
761         float *vertex3f = vertex3fbuf;
762         float *freevertex3f = NULL;
763         // for static cases we can just call CollisionBIH which is much faster
764         if ((frameblend == NULL || (frameblend[0].subframe == 0 && frameblend[1].lerp == 0)) && (skeleton == NULL || skeleton->relativetransforms == NULL))
765         {
766                 Mod_CollisionBIH_TraceLine(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
767                 return;
768         }
769         memset(trace, 0, sizeof(*trace));
770         trace->fraction = 1;
771         trace->hitsupercontentsmask = hitsupercontentsmask;
772         trace->skipsupercontentsmask = skipsupercontentsmask;
773         trace->skipmaterialflagsmask = skipmaterialflagsmask;
774         segmentmins[0] = min(start[0], end[0]) - 1;
775         segmentmins[1] = min(start[1], end[1]) - 1;
776         segmentmins[2] = min(start[2], end[2]) - 1;
777         segmentmaxs[0] = max(start[0], end[0]) + 1;
778         segmentmaxs[1] = max(start[1], end[1]) + 1;
779         segmentmaxs[2] = max(start[2], end[2]) + 1;
780         if (frameblend == NULL || frameblend[0].subframe != 0 || frameblend[0].lerp != 0 || skeleton != NULL)
781         {
782                 if (model->surfmesh.num_vertices > 1024)
783                         vertex3f = freevertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
784                 model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
785         }
786         else
787                 vertex3f = model->surfmesh.data_vertex3f;
788         for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
789                 Collision_TraceLineTriangleMeshFloat(trace, start, end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
790         if (freevertex3f)
791                 Mem_Free(freevertex3f);
792 }
793
794 static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
795 {
796         int i;
797         vec3_t shiftstart, shiftend;
798         float segmentmins[3], segmentmaxs[3];
799         msurface_t *surface;
800         float vertex3fbuf[1024*3];
801         float *vertex3f = vertex3fbuf;
802         colboxbrushf_t thisbrush_start, thisbrush_end;
803         vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
804
805         if (VectorCompare(boxmins, boxmaxs))
806         {
807                 VectorAdd(start, boxmins, shiftstart);
808                 VectorAdd(end, boxmins, shiftend);
809                 Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
810                 VectorSubtract(trace->endpos, boxmins, trace->endpos);
811                 return;
812         }
813
814         // for static cases we can just call CollisionBIH which is much faster
815         if ((frameblend == NULL || (frameblend[0].subframe == 0 && frameblend[1].lerp == 0)) && (skeleton == NULL || skeleton->relativetransforms == NULL))
816         {
817                 Mod_CollisionBIH_TraceBox(model, frameblend, skeleton, trace, start, boxmins, boxmaxs, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
818                 return;
819         }
820
821         // box trace, performed as brush trace
822         memset(trace, 0, sizeof(*trace));
823         trace->fraction = 1;
824         trace->hitsupercontentsmask = hitsupercontentsmask;
825         trace->skipsupercontentsmask = skipsupercontentsmask;
826         trace->skipmaterialflagsmask = skipmaterialflagsmask;
827         if (model->surfmesh.num_vertices > 1024)
828                 vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
829         segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1;
830         segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1;
831         segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1;
832         segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1;
833         segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1;
834         segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1;
835         VectorAdd(start, boxmins, boxstartmins);
836         VectorAdd(start, boxmaxs, boxstartmaxs);
837         VectorAdd(end, boxmins, boxendmins);
838         VectorAdd(end, boxmaxs, boxendmaxs);
839         Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL);
840         Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL);
841         model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
842         for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
843                 Collision_TraceBrushTriangleMeshFloat(trace, &thisbrush_start.brush, &thisbrush_end.brush, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
844         if (vertex3f != vertex3fbuf)
845                 Mem_Free(vertex3f);
846 }
847
848 static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap)
849 {
850         int i, j;
851         for (i = 0;i < inverts;i++)
852         {
853                 if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
854                         continue;
855                 j = vertremap[i]; // not onseam
856                 if (j >= 0)
857                         out[j] = v[i];
858                 j = vertremap[i+inverts]; // onseam
859                 if (j >= 0)
860                         out[j] = v[i];
861         }
862 }
863
864 static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *vertremap)
865 {
866         int i, f, pose, groupframes;
867         float interval;
868         daliasframetype_t *pframetype;
869         daliasframe_t *pinframe;
870         daliasgroup_t *group;
871         daliasinterval_t *intervals;
872         animscene_t *scene;
873         pose = 0;
874         scene = loadmodel->animscenes;
875         for (f = 0;f < loadmodel->numframes;f++)
876         {
877                 pframetype = (daliasframetype_t *)datapointer;
878                 datapointer += sizeof(daliasframetype_t);
879                 if (LittleLong (pframetype->type) == ALIAS_SINGLE)
880                 {
881                         // a single frame is still treated as a group
882                         interval = 0.1f;
883                         groupframes = 1;
884                 }
885                 else
886                 {
887                         // read group header
888                         group = (daliasgroup_t *)datapointer;
889                         datapointer += sizeof(daliasgroup_t);
890                         groupframes = LittleLong (group->numframes);
891
892                         // intervals (time per frame)
893                         intervals = (daliasinterval_t *)datapointer;
894                         datapointer += sizeof(daliasinterval_t) * groupframes;
895
896                         interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
897                         if (interval < 0.01f)
898                         {
899                                 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
900                                 interval = 0.1f;
901                         }
902                 }
903
904                 // get scene name from first frame
905                 pinframe = (daliasframe_t *)datapointer;
906
907                 strlcpy(scene->name, pinframe->name, sizeof(scene->name));
908                 scene->firstframe = pose;
909                 scene->framecount = groupframes;
910                 scene->framerate = 1.0f / interval;
911                 scene->loop = true;
912                 scene++;
913
914                 // read frames
915                 for (i = 0;i < groupframes;i++)
916                 {
917                         datapointer += sizeof(daliasframe_t);
918                         Mod_ConvertAliasVerts(inverts, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphmdlvertex + pose * loadmodel->surfmesh.num_vertices, vertremap);
919                         datapointer += sizeof(trivertx_t) * inverts;
920                         pose++;
921                 }
922         }
923 }
924
925 void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
926 {
927         int i;
928         char stripbuf[MAX_QPATH];
929         skinfileitem_t *skinfileitem;
930         if(developer_extra.integer)
931                 Con_DPrintf("Looking up texture for %s (default: %s)\n", meshname, shadername);
932         if (skinfile)
933         {
934                 // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
935                 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
936                 {
937                         memset(skin, 0, sizeof(*skin));
938                         // see if a mesh
939                         for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
940                         {
941                                 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
942                                 if (!strcmp(skinfileitem->name, meshname))
943                                 {
944                                         Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf));
945                                         if(developer_extra.integer)
946                                                 Con_DPrintf("--> got %s from skin file\n", stripbuf);
947                                         Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
948                                         break;
949                                 }
950                         }
951                         if (!skinfileitem)
952                         {
953                                 // don't render unmentioned meshes
954                                 Mod_LoadCustomMaterial(loadmodel->mempool, skin, meshname, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing());
955                                 if(developer_extra.integer)
956                                         Con_DPrintf("--> skipping\n");
957                                 skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW;
958                         }
959                 }
960         }
961         else
962         {
963                 if(developer_extra.integer)
964                         Con_DPrintf("--> using default\n");
965                 Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf));
966                 Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
967         }
968 }
969
970 #define BOUNDI(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%d exceeds %d - %d)", loadmodel->name, VALUE, MIN, MAX);
971 #define BOUNDF(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%f exceeds %f - %f)", loadmodel->name, VALUE, MIN, MAX);
972 void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
973 {
974         int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
975         float scales, scalet, interval;
976         msurface_t *surface;
977         unsigned char *data;
978         mdl_t *pinmodel;
979         stvert_t *pinstverts;
980         dtriangle_t *pintriangles;
981         daliasskintype_t *pinskintype;
982         daliasskingroup_t *pinskingroup;
983         daliasskininterval_t *pinskinintervals;
984         daliasframetype_t *pinframetype;
985         daliasgroup_t *pinframegroup;
986         unsigned char *datapointer, *startframes, *startskins;
987         char name[MAX_QPATH];
988         skinframe_t *tempskinframe;
989         animscene_t *tempskinscenes;
990         texture_t *tempaliasskins;
991         float *vertst;
992         int *vertonseam, *vertremap;
993         skinfile_t *skinfiles;
994
995         datapointer = (unsigned char *)buffer;
996         pinmodel = (mdl_t *)datapointer;
997         datapointer += sizeof(mdl_t);
998
999         version = LittleLong (pinmodel->version);
1000         if (version != ALIAS_VERSION)
1001                 Host_Error ("%s has wrong version number (%i should be %i)",
1002                                  loadmodel->name, version, ALIAS_VERSION);
1003
1004         loadmodel->modeldatatypestring = "MDL";
1005
1006         loadmodel->type = mod_alias;
1007         loadmodel->DrawSky = NULL;
1008         loadmodel->DrawAddWaterPlanes = NULL;
1009         loadmodel->Draw = R_Q1BSP_Draw;
1010         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1011         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1012         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1013         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1014         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1015         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1016         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1017         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1018         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1019         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1020         // FIXME add TraceBrush!
1021         loadmodel->PointSuperContents = NULL;
1022         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1023
1024         loadmodel->num_surfaces = 1;
1025         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1026         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
1027         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1028         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1029         loadmodel->sortedmodelsurfaces[0] = 0;
1030
1031         loadmodel->numskins = LittleLong(pinmodel->numskins);
1032         BOUNDI(loadmodel->numskins,0,65536);
1033         skinwidth = LittleLong (pinmodel->skinwidth);
1034         BOUNDI(skinwidth,0,65536);
1035         skinheight = LittleLong (pinmodel->skinheight);
1036         BOUNDI(skinheight,0,65536);
1037         numverts = LittleLong(pinmodel->numverts);
1038         BOUNDI(numverts,0,65536);
1039         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
1040         BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
1041         loadmodel->numframes = LittleLong(pinmodel->numframes);
1042         BOUNDI(loadmodel->numframes,0,65536);
1043         loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
1044         BOUNDI((int)loadmodel->synctype,0,2);
1045         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1046         i = LittleLong (pinmodel->flags);
1047         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1048
1049         for (i = 0;i < 3;i++)
1050         {
1051                 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
1052                 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
1053         }
1054
1055         startskins = datapointer;
1056         totalskins = 0;
1057         for (i = 0;i < loadmodel->numskins;i++)
1058         {
1059                 pinskintype = (daliasskintype_t *)datapointer;
1060                 datapointer += sizeof(daliasskintype_t);
1061                 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
1062                         groupskins = 1;
1063                 else
1064                 {
1065                         pinskingroup = (daliasskingroup_t *)datapointer;
1066                         datapointer += sizeof(daliasskingroup_t);
1067                         groupskins = LittleLong(pinskingroup->numskins);
1068                         datapointer += sizeof(daliasskininterval_t) * groupskins;
1069                 }
1070
1071                 for (j = 0;j < groupskins;j++)
1072                 {
1073                         datapointer += skinwidth * skinheight;
1074                         totalskins++;
1075                 }
1076         }
1077
1078         pinstverts = (stvert_t *)datapointer;
1079         datapointer += sizeof(stvert_t) * numverts;
1080
1081         pintriangles = (dtriangle_t *)datapointer;
1082         datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
1083
1084         startframes = datapointer;
1085         loadmodel->surfmesh.num_morphframes = 0;
1086         for (i = 0;i < loadmodel->numframes;i++)
1087         {
1088                 pinframetype = (daliasframetype_t *)datapointer;
1089                 datapointer += sizeof(daliasframetype_t);
1090                 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1091                         groupframes = 1;
1092                 else
1093                 {
1094                         pinframegroup = (daliasgroup_t *)datapointer;
1095                         datapointer += sizeof(daliasgroup_t);
1096                         groupframes = LittleLong(pinframegroup->numframes);
1097                         datapointer += sizeof(daliasinterval_t) * groupframes;
1098                 }
1099
1100                 for (j = 0;j < groupframes;j++)
1101                 {
1102                         datapointer += sizeof(daliasframe_t);
1103                         datapointer += sizeof(trivertx_t) * numverts;
1104                         loadmodel->surfmesh.num_morphframes++;
1105                 }
1106         }
1107         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1108
1109         // store texture coordinates into temporary array, they will be stored
1110         // after usage is determined (triangle data)
1111         vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1112         vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1113         vertonseam = vertremap + numverts * 2;
1114
1115         scales = 1.0 / skinwidth;
1116         scalet = 1.0 / skinheight;
1117         for (i = 0;i < numverts;i++)
1118         {
1119                 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1120                 vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales;
1121                 vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet;
1122                 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1123                 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1124         }
1125
1126 // load triangle data
1127         loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1128
1129         // read the triangle elements
1130         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1131                 for (j = 0;j < 3;j++)
1132                         loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1133         // validate (note numverts is used because this is the original data)
1134         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1135         // now butcher the elements according to vertonseam and tri->facesfront
1136         // and then compact the vertex set to remove duplicates
1137         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1138                 if (!LittleLong(pintriangles[i].facesfront)) // backface
1139                         for (j = 0;j < 3;j++)
1140                                 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1141                                         loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1142         // count the usage
1143         // (this uses vertremap to count usage to save some memory)
1144         for (i = 0;i < numverts*2;i++)
1145                 vertremap[i] = 0;
1146         for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1147                 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1148         // build remapping table and compact array
1149         loadmodel->surfmesh.num_vertices = 0;
1150         for (i = 0;i < numverts*2;i++)
1151         {
1152                 if (vertremap[i])
1153                 {
1154                         vertremap[i] = loadmodel->surfmesh.num_vertices;
1155                         vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1156                         vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1157                         loadmodel->surfmesh.num_vertices++;
1158                 }
1159                 else
1160                         vertremap[i] = -1; // not used at all
1161         }
1162         // remap the elements to the new vertex set
1163         for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1164                 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1165         // store the texture coordinates
1166         loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1167         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1168         {
1169                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1170                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1171         }
1172
1173         // generate ushort elements array if possible
1174         if (loadmodel->surfmesh.num_vertices <= 65536)
1175                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1176         if (loadmodel->surfmesh.data_element3s)
1177                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1178                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1179
1180 // load the frames
1181         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1182         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1183         if (r_enableshadowvolumes.integer)
1184         {
1185                 loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
1186         }
1187         Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1188         if (loadmodel->surfmesh.data_neighbor3i)
1189                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1190         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1191         Mod_Alias_MorphMesh_CompileFrames();
1192
1193         Mem_Free(vertst);
1194         Mem_Free(vertremap);
1195
1196         // load the skins
1197         skinfiles = Mod_LoadSkinFiles();
1198         if (skinfiles)
1199         {
1200                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1201                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1202                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1203                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1204                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1205                 Mod_FreeSkinFiles(skinfiles);
1206                 for (i = 0;i < loadmodel->numskins;i++)
1207                 {
1208                         loadmodel->skinscenes[i].firstframe = i;
1209                         loadmodel->skinscenes[i].framecount = 1;
1210                         loadmodel->skinscenes[i].loop = true;
1211                         loadmodel->skinscenes[i].framerate = 10;
1212                 }
1213         }
1214         else
1215         {
1216                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1217                 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1218                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1219                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1220                 totalskins = 0;
1221                 datapointer = startskins;
1222                 for (i = 0;i < loadmodel->numskins;i++)
1223                 {
1224                         pinskintype = (daliasskintype_t *)datapointer;
1225                         datapointer += sizeof(daliasskintype_t);
1226
1227                         if (pinskintype->type == ALIAS_SKIN_SINGLE)
1228                         {
1229                                 groupskins = 1;
1230                                 interval = 0.1f;
1231                         }
1232                         else
1233                         {
1234                                 pinskingroup = (daliasskingroup_t *)datapointer;
1235                                 datapointer += sizeof(daliasskingroup_t);
1236
1237                                 groupskins = LittleLong (pinskingroup->numskins);
1238
1239                                 pinskinintervals = (daliasskininterval_t *)datapointer;
1240                                 datapointer += sizeof(daliasskininterval_t) * groupskins;
1241
1242                                 interval = LittleFloat(pinskinintervals[0].interval);
1243                                 if (interval < 0.01f)
1244                                 {
1245                                         Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1246                                         interval = 0.1f;
1247                                 }
1248                         }
1249
1250                         dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1251                         loadmodel->skinscenes[i].firstframe = totalskins;
1252                         loadmodel->skinscenes[i].framecount = groupskins;
1253                         loadmodel->skinscenes[i].framerate = 1.0f / interval;
1254                         loadmodel->skinscenes[i].loop = true;
1255
1256                         for (j = 0;j < groupskins;j++)
1257                         {
1258                                 if (groupskins > 1)
1259                                         dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1260                                 else
1261                                         dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1262                                 if (!Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, false, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL))
1263                                         Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadInternalQuake(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight));
1264                                 datapointer += skinwidth * skinheight;
1265                                 totalskins++;
1266                         }
1267                 }
1268                 // check for skins that don't exist in the model, but do exist as external images
1269                 // (this was added because yummyluv kept pestering me about support for it)
1270                 // TODO: support shaders here?
1271                 for (;;)
1272                 {
1273                         dpsnprintf(name, sizeof(name), "%s_%i", loadmodel->name, loadmodel->numskins);
1274                         tempskinframe = R_SkinFrame_LoadExternal(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false, false);
1275                         if (!tempskinframe)
1276                                 break;
1277                         // expand the arrays to make room
1278                         tempskinscenes = loadmodel->skinscenes;
1279                         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1280                         memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1281                         Mem_Free(tempskinscenes);
1282
1283                         tempaliasskins = loadmodel->data_textures;
1284                         loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1285                         memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1286                         Mem_Free(tempaliasskins);
1287
1288                         // store the info about the new skin
1289                         Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, tempskinframe);
1290                         strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1291                         loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1292                         loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1293                         loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1294                         loadmodel->skinscenes[loadmodel->numskins].loop = true;
1295
1296                         //increase skin counts
1297                         loadmodel->num_textures++;
1298                         loadmodel->numskins++;
1299                         totalskins++;
1300
1301                         // fix up the pointers since they are pointing at the old textures array
1302                         // FIXME: this is a hack!
1303                         for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1304                                 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1305                 }
1306         }
1307
1308         surface = loadmodel->data_surfaces;
1309         surface->texture = loadmodel->data_textures;
1310         surface->num_firsttriangle = 0;
1311         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1312         surface->num_firstvertex = 0;
1313         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1314
1315         if(mod_alias_force_animated.string[0])
1316                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1317
1318         // Always make a BIH for the first frame, we can use it where possible.
1319         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1320         if (!loadmodel->surfmesh.isanimated)
1321         {
1322                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1323                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1324                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1325                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1326                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1327         }
1328
1329         // because shaders can do somewhat unexpected things, check for unusual features now
1330         for (i = 0;i < loadmodel->num_textures;i++)
1331         {
1332                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1333                         mod->DrawSky = R_Q1BSP_DrawSky;
1334                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1335                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1336         }
1337 }
1338
1339 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
1340 {
1341         int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1342         float iskinwidth, iskinheight;
1343         unsigned char *data;
1344         msurface_t *surface;
1345         md2_t *pinmodel;
1346         unsigned char *base, *datapointer;
1347         md2frame_t *pinframe;
1348         char *inskin;
1349         md2triangle_t *intri;
1350         unsigned short *inst;
1351         struct md2verthash_s
1352         {
1353                 struct md2verthash_s *next;
1354                 unsigned short xyz;
1355                 unsigned short st;
1356         }
1357         *hash, **md2verthash, *md2verthashdata;
1358         skinfile_t *skinfiles;
1359
1360         pinmodel = (md2_t *)buffer;
1361         base = (unsigned char *)buffer;
1362
1363         version = LittleLong (pinmodel->version);
1364         if (version != MD2ALIAS_VERSION)
1365                 Host_Error ("%s has wrong version number (%i should be %i)",
1366                         loadmodel->name, version, MD2ALIAS_VERSION);
1367
1368         loadmodel->modeldatatypestring = "MD2";
1369
1370         loadmodel->type = mod_alias;
1371         loadmodel->DrawSky = NULL;
1372         loadmodel->DrawAddWaterPlanes = NULL;
1373         loadmodel->Draw = R_Q1BSP_Draw;
1374         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1375         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1376         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1377         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1378         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1379         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1380         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1381         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1382         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1383         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1384         loadmodel->PointSuperContents = NULL;
1385         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1386
1387         if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1388                 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1389         if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1390                 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1391         if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1392                 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1393         if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1394                 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1395
1396         end = LittleLong(pinmodel->ofs_end);
1397         if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1398                 Host_Error ("%s is not a valid model", loadmodel->name);
1399         if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1400                 Host_Error ("%s is not a valid model", loadmodel->name);
1401         if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1402                 Host_Error ("%s is not a valid model", loadmodel->name);
1403         if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1404                 Host_Error ("%s is not a valid model", loadmodel->name);
1405         if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1406                 Host_Error ("%s is not a valid model", loadmodel->name);
1407
1408         loadmodel->numskins = LittleLong(pinmodel->num_skins);
1409         numxyz = LittleLong(pinmodel->num_xyz);
1410         numst = LittleLong(pinmodel->num_st);
1411         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1412         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1413         loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1414         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1415         skinwidth = LittleLong(pinmodel->skinwidth);
1416         skinheight = LittleLong(pinmodel->skinheight);
1417         iskinwidth = 1.0f / skinwidth;
1418         iskinheight = 1.0f / skinheight;
1419
1420         loadmodel->num_surfaces = 1;
1421         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1422         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));
1423         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1424         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1425         loadmodel->sortedmodelsurfaces[0] = 0;
1426         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1427         loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1428         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1429         if (r_enableshadowvolumes.integer)
1430         {
1431                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1432         }
1433
1434         loadmodel->synctype = ST_RAND;
1435
1436         // load the skins
1437         inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1438         skinfiles = Mod_LoadSkinFiles();
1439         if (skinfiles)
1440         {
1441                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1442                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1443                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1444                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1445                 Mod_FreeSkinFiles(skinfiles);
1446         }
1447         else if (loadmodel->numskins)
1448         {
1449                 // skins found (most likely not a player model)
1450                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1451                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1452                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1453                 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1454                         Mod_LoadTextureFromQ3Shader(loadmodel->mempool, loadmodel->name, loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, MATERIALFLAG_WALL);
1455         }
1456         else
1457         {
1458                 // no skins (most likely a player model)
1459                 loadmodel->numskins = 1;
1460                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1461                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1462                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1463                 Mod_LoadCustomMaterial(loadmodel->mempool, loadmodel->data_textures, loadmodel->name, SUPERCONTENTS_SOLID, MATERIALFLAG_WALL, R_SkinFrame_LoadMissing());
1464         }
1465
1466         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1467         for (i = 0;i < loadmodel->numskins;i++)
1468         {
1469                 loadmodel->skinscenes[i].firstframe = i;
1470                 loadmodel->skinscenes[i].framecount = 1;
1471                 loadmodel->skinscenes[i].loop = true;
1472                 loadmodel->skinscenes[i].framerate = 10;
1473         }
1474
1475         // load the triangles and stvert data
1476         inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1477         intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1478         md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1479         md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1480         // swap the triangle list
1481         loadmodel->surfmesh.num_vertices = 0;
1482         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1483         {
1484                 for (j = 0;j < 3;j++)
1485                 {
1486                         xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1487                         st = (unsigned short) LittleShort (intri[i].index_st[j]);
1488                         if (xyz >= numxyz)
1489                         {
1490                                 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1491                                 xyz = 0;
1492                         }
1493                         if (st >= numst)
1494                         {
1495                                 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1496                                 st = 0;
1497                         }
1498                         hashindex = (xyz * 256 + st) & 65535;
1499                         for (hash = md2verthash[hashindex];hash;hash = hash->next)
1500                                 if (hash->xyz == xyz && hash->st == st)
1501                                         break;
1502                         if (hash == NULL)
1503                         {
1504                                 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1505                                 hash->xyz = xyz;
1506                                 hash->st = st;
1507                                 hash->next = md2verthash[hashindex];
1508                                 md2verthash[hashindex] = hash;
1509                         }
1510                         loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1511                 }
1512         }
1513
1514         vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1515         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));
1516         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1517         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1518         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1519         {
1520                 int sts, stt;
1521                 hash = md2verthashdata + i;
1522                 vertremap[i] = hash->xyz;
1523                 sts = LittleShort(inst[hash->st*2+0]);
1524                 stt = LittleShort(inst[hash->st*2+1]);
1525                 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1526                 {
1527                         Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1528                         sts = 0;
1529                         stt = 0;
1530                 }
1531                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1532                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1533         }
1534
1535         Mem_Free(md2verthash);
1536         Mem_Free(md2verthashdata);
1537
1538         // generate ushort elements array if possible
1539         if (loadmodel->surfmesh.num_vertices <= 65536)
1540                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1541         if (loadmodel->surfmesh.data_element3s)
1542                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1543                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1544
1545         // load the frames
1546         datapointer = (base + LittleLong(pinmodel->ofs_frames));
1547         for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1548         {
1549                 int k;
1550                 trivertx_t *v;
1551                 trivertx_t *out;
1552                 pinframe = (md2frame_t *)datapointer;
1553                 datapointer += sizeof(md2frame_t);
1554                 // store the frame scale/translate into the appropriate array
1555                 for (j = 0;j < 3;j++)
1556                 {
1557                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1558                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1559                 }
1560                 // convert the vertices
1561                 v = (trivertx_t *)datapointer;
1562                 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1563                 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1564                         out[k] = v[vertremap[k]];
1565                 datapointer += numxyz * sizeof(trivertx_t);
1566
1567                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1568                 loadmodel->animscenes[i].firstframe = i;
1569                 loadmodel->animscenes[i].framecount = 1;
1570                 loadmodel->animscenes[i].framerate = 10;
1571                 loadmodel->animscenes[i].loop = true;
1572         }
1573
1574         Mem_Free(vertremap);
1575
1576         if (loadmodel->surfmesh.data_neighbor3i)
1577                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1578         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1579         Mod_Alias_MorphMesh_CompileFrames();
1580         if(mod_alias_force_animated.string[0])
1581                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1582
1583         surface = loadmodel->data_surfaces;
1584         surface->texture = loadmodel->data_textures;
1585         surface->num_firsttriangle = 0;
1586         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1587         surface->num_firstvertex = 0;
1588         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1589
1590         // Always make a BIH for the first frame, we can use it where possible.
1591         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1592         if (!loadmodel->surfmesh.isanimated)
1593         {
1594                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1595                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1596                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1597                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1598                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1599         }
1600
1601         // because shaders can do somewhat unexpected things, check for unusual features now
1602         for (i = 0;i < loadmodel->num_textures;i++)
1603         {
1604                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1605                         mod->DrawSky = R_Q1BSP_DrawSky;
1606                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1607                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1608         }
1609 }
1610
1611 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
1612 {
1613         int i, j, k, version, meshvertices, meshtriangles;
1614         unsigned char *data;
1615         msurface_t *surface;
1616         md3modelheader_t *pinmodel;
1617         md3frameinfo_t *pinframe;
1618         md3mesh_t *pinmesh;
1619         md3tag_t *pintag;
1620         skinfile_t *skinfiles;
1621
1622         pinmodel = (md3modelheader_t *)buffer;
1623
1624         if (memcmp(pinmodel->identifier, "IDP3", 4))
1625                 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1626         version = LittleLong (pinmodel->version);
1627         if (version != MD3VERSION)
1628                 Host_Error ("%s has wrong version number (%i should be %i)",
1629                         loadmodel->name, version, MD3VERSION);
1630
1631         skinfiles = Mod_LoadSkinFiles();
1632         if (loadmodel->numskins < 1)
1633                 loadmodel->numskins = 1;
1634
1635         loadmodel->modeldatatypestring = "MD3";
1636
1637         loadmodel->type = mod_alias;
1638         loadmodel->DrawSky = NULL;
1639         loadmodel->DrawAddWaterPlanes = NULL;
1640         loadmodel->Draw = R_Q1BSP_Draw;
1641         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1642         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1643         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1644         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1645         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1646         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1647         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1648         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1649         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1650         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1651         loadmodel->PointSuperContents = NULL;
1652         loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1653         loadmodel->synctype = ST_RAND;
1654         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1655         i = LittleLong (pinmodel->flags);
1656         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1657
1658         // set up some global info about the model
1659         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1660         loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1661
1662         // make skinscenes for the skins (no groups)
1663         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1664         for (i = 0;i < loadmodel->numskins;i++)
1665         {
1666                 loadmodel->skinscenes[i].firstframe = i;
1667                 loadmodel->skinscenes[i].framecount = 1;
1668                 loadmodel->skinscenes[i].loop = true;
1669                 loadmodel->skinscenes[i].framerate = 10;
1670         }
1671
1672         // load frameinfo
1673         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1674         for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1675         {
1676                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1677                 loadmodel->animscenes[i].firstframe = i;
1678                 loadmodel->animscenes[i].framecount = 1;
1679                 loadmodel->animscenes[i].framerate = 10;
1680                 loadmodel->animscenes[i].loop = true;
1681         }
1682
1683         // load tags
1684         loadmodel->num_tagframes = loadmodel->numframes;
1685         loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1686         loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1687         for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1688         {
1689                 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1690                 for (j = 0;j < 9;j++)
1691                         loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1692                 for (j = 0;j < 3;j++)
1693                         loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1694                 //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);
1695         }
1696
1697         // load meshes
1698         meshvertices = 0;
1699         meshtriangles = 0;
1700         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)))
1701         {
1702                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1703                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1704                 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1705                         Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1706                 meshvertices += LittleLong(pinmesh->num_vertices);
1707                 meshtriangles += LittleLong(pinmesh->num_triangles);
1708         }
1709
1710         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1711         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1712         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1713         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));
1714         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1715         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1716         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1717         loadmodel->surfmesh.num_vertices = meshvertices;
1718         loadmodel->surfmesh.num_triangles = meshtriangles;
1719         loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1720         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1721         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1722         if (r_enableshadowvolumes.integer)
1723         {
1724                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1725         }
1726         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1727         loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1728         if (meshvertices <= 65536)
1729         {
1730                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1731         }
1732
1733         meshvertices = 0;
1734         meshtriangles = 0;
1735         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)))
1736         {
1737                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1738                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1739                 loadmodel->sortedmodelsurfaces[i] = i;
1740                 surface = loadmodel->data_surfaces + i;
1741                 surface->texture = loadmodel->data_textures + i;
1742                 surface->num_firsttriangle = meshtriangles;
1743                 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1744                 surface->num_firstvertex = meshvertices;
1745                 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1746                 meshvertices += surface->num_vertices;
1747                 meshtriangles += surface->num_triangles;
1748
1749                 for (j = 0;j < surface->num_triangles * 3;j++)
1750                         loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1751                 for (j = 0;j < surface->num_vertices;j++)
1752                 {
1753                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1754                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1755                 }
1756                 for (j = 0;j < loadmodel->numframes;j++)
1757                 {
1758                         const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1759                         md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1760                         for (k = 0;k < surface->num_vertices;k++, in++, out++)
1761                         {
1762                                 out->origin[0] = LittleShort(in->origin[0]);
1763                                 out->origin[1] = LittleShort(in->origin[1]);
1764                                 out->origin[2] = LittleShort(in->origin[2]);
1765                                 out->pitch = in->pitch;
1766                                 out->yaw = in->yaw;
1767                         }
1768                 }
1769
1770                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1771
1772                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1773         }
1774         if (loadmodel->surfmesh.data_element3s)
1775                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1776                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1777         if (loadmodel->surfmesh.data_neighbor3i)
1778                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1779         Mod_Alias_MorphMesh_CompileFrames();
1780         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
1781         Mod_FreeSkinFiles(skinfiles);
1782         Mod_MakeSortedSurfaces(loadmodel);
1783         if(mod_alias_force_animated.string[0])
1784                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
1785
1786         // Always make a BIH for the first frame, we can use it where possible.
1787         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1788         if (!loadmodel->surfmesh.isanimated)
1789         {
1790                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1791                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
1792                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1793                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1794                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1795         }
1796
1797         // because shaders can do somewhat unexpected things, check for unusual features now
1798         for (i = 0;i < loadmodel->num_textures;i++)
1799         {
1800                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
1801                         mod->DrawSky = R_Q1BSP_DrawSky;
1802                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
1803                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
1804         }
1805 }
1806
1807 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1808 {
1809         zymtype1header_t *pinmodel, *pheader;
1810         unsigned char *pbase;
1811         int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1812         float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1813         zymvertex_t *verts, *vertdata;
1814         zymscene_t *scene;
1815         zymbone_t *bone;
1816         char *shadername;
1817         skinfile_t *skinfiles;
1818         unsigned char *data;
1819         msurface_t *surface;
1820
1821         pinmodel = (zymtype1header_t *)buffer;
1822         pbase = (unsigned char *)buffer;
1823         if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1824                 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1825         if (BigLong(pinmodel->type) != 1)
1826                 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1827
1828         loadmodel->modeldatatypestring = "ZYM";
1829
1830         loadmodel->type = mod_alias;
1831         loadmodel->synctype = ST_RAND;
1832
1833         // byteswap header
1834         pheader = pinmodel;
1835         pheader->type = BigLong(pinmodel->type);
1836         pheader->filesize = BigLong(pinmodel->filesize);
1837         pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1838         pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1839         pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1840         pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1841         pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1842         pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1843         pheader->radius = BigFloat(pinmodel->radius);
1844         pheader->numverts = BigLong(pinmodel->numverts);
1845         pheader->numtris = BigLong(pinmodel->numtris);
1846         pheader->numshaders = BigLong(pinmodel->numshaders);
1847         pheader->numbones = BigLong(pinmodel->numbones);
1848         pheader->numscenes = BigLong(pinmodel->numscenes);
1849         pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1850         pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1851         pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1852         pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1853         pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1854         pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1855         pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1856         pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1857         pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1858         pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1859         pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1860         pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1861         pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1862         pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1863         pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1864         pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1865         pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1866         pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1867
1868         if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1869         {
1870                 Con_Printf("%s has no geometry\n", loadmodel->name);
1871                 return;
1872         }
1873         if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1874         {
1875                 Con_Printf("%s has no animations\n", loadmodel->name);
1876                 return;
1877         }
1878
1879         loadmodel->DrawSky = NULL;
1880         loadmodel->DrawAddWaterPlanes = NULL;
1881         loadmodel->Draw = R_Q1BSP_Draw;
1882         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1883         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1884         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1885         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1886         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1887         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1888         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1889         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1890         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1891         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1892         loadmodel->PointSuperContents = NULL;
1893         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1894
1895         loadmodel->numframes = pheader->numscenes;
1896         loadmodel->num_surfaces = pheader->numshaders;
1897
1898         skinfiles = Mod_LoadSkinFiles();
1899         if (loadmodel->numskins < 1)
1900                 loadmodel->numskins = 1;
1901
1902         // make skinscenes for the skins (no groups)
1903         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1904         for (i = 0;i < loadmodel->numskins;i++)
1905         {
1906                 loadmodel->skinscenes[i].firstframe = i;
1907                 loadmodel->skinscenes[i].framecount = 1;
1908                 loadmodel->skinscenes[i].loop = true;
1909                 loadmodel->skinscenes[i].framerate = 10;
1910         }
1911
1912         // model bbox
1913         // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
1914         modelradius = pheader->radius;
1915         for (i = 0;i < 3;i++)
1916         {
1917                 loadmodel->normalmins[i] = pheader->mins[i];
1918                 loadmodel->normalmaxs[i] = pheader->maxs[i];
1919                 loadmodel->rotatedmins[i] = -modelradius;
1920                 loadmodel->rotatedmaxs[i] = modelradius;
1921         }
1922         corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1923         corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1924         loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1925         if (loadmodel->yawmaxs[0] > modelradius)
1926                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1927         loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1928         loadmodel->yawmins[2] = loadmodel->normalmins[2];
1929         loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1930         loadmodel->radius = modelradius;
1931         loadmodel->radius2 = modelradius * modelradius;
1932
1933         // go through the lumps, swapping things
1934
1935         //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1936         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1937         scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1938         numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1939         for (i = 0;i < pheader->numscenes;i++)
1940         {
1941                 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1942                 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1943                 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1944                 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1945                 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1946                 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1947                         Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1948                 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1949                         Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1950                 if (loadmodel->animscenes[i].framerate < 0)
1951                         Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1952                 scene++;
1953         }
1954
1955         //zymlump_t lump_bones; // zymbone_t bone[numbones];
1956         loadmodel->num_bones = pheader->numbones;
1957         loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1958         bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1959         for (i = 0;i < pheader->numbones;i++)
1960         {
1961                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1962                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1963                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1964                 if (loadmodel->data_bones[i].parent >= i)
1965                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1966         }
1967
1968         //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1969         vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1970         bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1971         for (i = 0;i < pheader->numverts;i++)
1972         {
1973                 vertbonecounts[i] = BigLong(bonecount[i]);
1974                 if (vertbonecounts[i] != 1)
1975                         Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1976         }
1977
1978         loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1979
1980         meshvertices = pheader->numverts;
1981         meshtriangles = pheader->numtris;
1982
1983         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1984         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1985         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1986         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]));
1987         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1988         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1989         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1990         loadmodel->surfmesh.num_vertices = meshvertices;
1991         loadmodel->surfmesh.num_triangles = meshtriangles;
1992         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1993         if (r_enableshadowvolumes.integer)
1994         {
1995                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1996         }
1997         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1998         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1999         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2000         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2001         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2002         loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2003         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2004         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2005         loadmodel->surfmesh.num_blends = 0;
2006         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2007         if (loadmodel->surfmesh.num_vertices <= 65536)
2008         {
2009                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2010         }
2011         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2012         loadmodel->surfmesh.data_blendweights = NULL;
2013
2014         //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
2015         poses = (float *) (pheader->lump_poses.start + pbase);
2016         // figure out scale of model from root bone, for compatibility with old zmodel versions
2017         tempvec[0] = BigFloat(poses[0]);
2018         tempvec[1] = BigFloat(poses[1]);
2019         tempvec[2] = BigFloat(poses[2]);
2020         modelscale = VectorLength(tempvec);
2021         biggestorigin = 0;
2022         for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
2023         {
2024                 f = fabs(BigFloat(poses[i]));
2025                 biggestorigin = max(biggestorigin, f);
2026         }
2027         loadmodel->num_posescale = biggestorigin / 32767.0f;
2028         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2029         for (i = 0;i < numposes;i++)
2030         {
2031                 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
2032                 for (j = 0;j < loadmodel->num_bones;j++)
2033                 {
2034                         float pose[12];
2035                         matrix4x4_t posematrix;
2036                         for (k = 0;k < 12;k++)
2037                                 pose[k] = BigFloat(frameposes[j*12+k]);
2038                         //if (j < loadmodel->num_bones)
2039                         //      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));
2040                         // scale child bones to match the root scale
2041                         if (loadmodel->data_bones[j].parent >= 0)
2042                         {
2043                                 pose[3] *= modelscale;
2044                                 pose[7] *= modelscale;
2045                                 pose[11] *= modelscale;
2046                         }
2047                         // normalize rotation matrix
2048                         VectorNormalize(pose + 0);
2049                         VectorNormalize(pose + 4);
2050                         VectorNormalize(pose + 8);
2051                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2052                         Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2053                 }
2054         }
2055
2056         //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2057         verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2058         vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2059         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2060         // (converting from weight-blending skeletal animation to
2061         //  deformation-based skeletal animation)
2062         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2063         for (i = 0;i < loadmodel->num_bones;i++)
2064         {
2065                 float m[12];
2066                 for (k = 0;k < 12;k++)
2067                         m[k] = BigFloat(poses[i*12+k]);
2068                 if (loadmodel->data_bones[i].parent >= 0)
2069                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2070                 else
2071                         for (k = 0;k < 12;k++)
2072                                 bonepose[12*i+k] = m[k];
2073         }
2074         for (j = 0;j < pheader->numverts;j++)
2075         {
2076                 // this format really should have had a per vertexweight weight value...
2077                 // but since it does not, the weighting is completely ignored and
2078                 // only one weight is allowed per vertex
2079                 int boneindex = BigLong(vertdata[j].bonenum);
2080                 const float *m = bonepose + 12 * boneindex;
2081                 float relativeorigin[3];
2082                 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2083                 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2084                 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2085                 // transform the vertex bone weight into the base mesh
2086                 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2087                 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2088                 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2089                 // store the weight as the primary weight on this vertex
2090                 loadmodel->surfmesh.blends[j] = boneindex;
2091                 loadmodel->surfmesh.data_skeletalindex4ub[j*4  ] = boneindex;
2092                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0;
2093                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0;
2094                 loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0;
2095                 loadmodel->surfmesh.data_skeletalweight4ub[j*4  ] = 255;
2096                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0;
2097                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0;
2098                 loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0;
2099         }
2100         Z_Free(bonepose);
2101         // normals and tangents are calculated after elements are loaded
2102
2103         //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2104         outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2105         intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2106         for (i = 0;i < pheader->numverts;i++)
2107         {
2108                 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2109                 // flip T coordinate for OpenGL
2110                 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2111         }
2112
2113         //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2114         //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2115         //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2116
2117         //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2118         //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)
2119         // byteswap, validate, and swap winding order of tris
2120         count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2121         if (pheader->lump_render.length != count)
2122                 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2123         renderlist = (int *) (pheader->lump_render.start + pbase);
2124         renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2125         meshtriangles = 0;
2126         for (i = 0;i < loadmodel->num_surfaces;i++)
2127         {
2128                 int firstvertex, lastvertex;
2129                 if (renderlist >= renderlistend)
2130                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2131                 count = BigLong(*renderlist);renderlist++;
2132                 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2133                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2134
2135                 loadmodel->sortedmodelsurfaces[i] = i;
2136                 surface = loadmodel->data_surfaces + i;
2137                 surface->texture = loadmodel->data_textures + i;
2138                 surface->num_firsttriangle = meshtriangles;
2139                 surface->num_triangles = count;
2140                 meshtriangles += surface->num_triangles;
2141
2142                 // load the elements
2143                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2144                 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2145                 {
2146                         outelements[j*3+2] = BigLong(renderlist[0]);
2147                         outelements[j*3+1] = BigLong(renderlist[1]);
2148                         outelements[j*3+0] = BigLong(renderlist[2]);
2149                 }
2150                 // validate the elements and find the used vertex range
2151                 firstvertex = meshvertices;
2152                 lastvertex = 0;
2153                 for (j = 0;j < surface->num_triangles * 3;j++)
2154                 {
2155                         if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2156                                 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2157                         firstvertex = min(firstvertex, outelements[j]);
2158                         lastvertex = max(lastvertex, outelements[j]);
2159                 }
2160                 surface->num_firstvertex = firstvertex;
2161                 surface->num_vertices = lastvertex + 1 - firstvertex;
2162
2163                 // since zym models do not have named sections, reuse their shader
2164                 // name as the section name
2165                 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2166                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2167         }
2168         Mod_FreeSkinFiles(skinfiles);
2169         Mem_Free(vertbonecounts);
2170         Mem_Free(verts);
2171         Mod_MakeSortedSurfaces(loadmodel);
2172
2173         // compute all the mesh information that was not loaded from the file
2174         if (loadmodel->surfmesh.data_element3s)
2175                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2176                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2177         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2178         Mod_BuildBaseBonePoses();
2179         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);
2180         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);
2181         if (loadmodel->surfmesh.data_neighbor3i)
2182                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2183         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2184         if(mod_alias_force_animated.string[0])
2185                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2186
2187         // Always make a BIH for the first frame, we can use it where possible.
2188         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2189         if (!loadmodel->surfmesh.isanimated)
2190         {
2191                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2192                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2193                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2194                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2195                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2196         }
2197
2198         // because shaders can do somewhat unexpected things, check for unusual features now
2199         for (i = 0;i < loadmodel->num_textures;i++)
2200         {
2201                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2202                         mod->DrawSky = R_Q1BSP_DrawSky;
2203                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2204                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2205         }
2206 }
2207
2208 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2209 {
2210         dpmheader_t *pheader;
2211         dpmframe_t *frames;
2212         dpmbone_t *bone;
2213         dpmmesh_t *dpmmesh;
2214         unsigned char *pbase;
2215         int i, j, k, meshvertices, meshtriangles;
2216         skinfile_t *skinfiles;
2217         unsigned char *data;
2218         float *bonepose;
2219         float biggestorigin, tempvec[3], modelscale;
2220         float f;
2221         float *poses;
2222
2223         pheader = (dpmheader_t *)buffer;
2224         pbase = (unsigned char *)buffer;
2225         if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2226                 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2227         if (BigLong(pheader->type) != 2)
2228                 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2229
2230         loadmodel->modeldatatypestring = "DPM";
2231
2232         loadmodel->type = mod_alias;
2233         loadmodel->synctype = ST_RAND;
2234
2235         // byteswap header
2236         pheader->type = BigLong(pheader->type);
2237         pheader->filesize = BigLong(pheader->filesize);
2238         pheader->mins[0] = BigFloat(pheader->mins[0]);
2239         pheader->mins[1] = BigFloat(pheader->mins[1]);
2240         pheader->mins[2] = BigFloat(pheader->mins[2]);
2241         pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2242         pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2243         pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2244         pheader->yawradius = BigFloat(pheader->yawradius);
2245         pheader->allradius = BigFloat(pheader->allradius);
2246         pheader->num_bones = BigLong(pheader->num_bones);
2247         pheader->num_meshs = BigLong(pheader->num_meshs);
2248         pheader->num_frames = BigLong(pheader->num_frames);
2249         pheader->ofs_bones = BigLong(pheader->ofs_bones);
2250         pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2251         pheader->ofs_frames = BigLong(pheader->ofs_frames);
2252
2253         if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2254         {
2255                 Con_Printf("%s has no geometry\n", loadmodel->name);
2256                 return;
2257         }
2258         if (pheader->num_frames < 1)
2259         {
2260                 Con_Printf("%s has no frames\n", loadmodel->name);
2261                 return;
2262         }
2263
2264         loadmodel->DrawSky = NULL;
2265         loadmodel->DrawAddWaterPlanes = NULL;
2266         loadmodel->Draw = R_Q1BSP_Draw;
2267         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2268         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2269         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2270         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2271         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2272         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2273         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2274         loadmodel->DrawLight = R_Q1BSP_DrawLight;
2275         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2276         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2277         loadmodel->PointSuperContents = NULL;
2278         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2279
2280         // model bbox
2281         // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox()
2282         for (i = 0;i < 3;i++)
2283         {
2284                 loadmodel->normalmins[i] = pheader->mins[i];
2285                 loadmodel->normalmaxs[i] = pheader->maxs[i];
2286                 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2287                 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2288                 loadmodel->rotatedmins[i] = -pheader->allradius;
2289                 loadmodel->rotatedmaxs[i] = pheader->allradius;
2290         }
2291         loadmodel->radius = pheader->allradius;
2292         loadmodel->radius2 = pheader->allradius * pheader->allradius;
2293
2294         // load external .skin files if present
2295         skinfiles = Mod_LoadSkinFiles();
2296         if (loadmodel->numskins < 1)
2297                 loadmodel->numskins = 1;
2298
2299         meshvertices = 0;
2300         meshtriangles = 0;
2301
2302         // gather combined statistics from the meshes
2303         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2304         for (i = 0;i < (int)pheader->num_meshs;i++)
2305         {
2306                 int numverts = BigLong(dpmmesh->num_verts);
2307                 meshvertices += numverts;
2308                 meshtriangles += BigLong(dpmmesh->num_tris);
2309                 dpmmesh++;
2310         }
2311
2312         loadmodel->numframes = pheader->num_frames;
2313         loadmodel->num_bones = pheader->num_bones;
2314         loadmodel->num_poses = loadmodel->numframes;
2315         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
2316         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2317         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2318         // do most allocations as one merged chunk
2319         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));
2320         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2321         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2322         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2323         loadmodel->surfmesh.num_vertices = meshvertices;
2324         loadmodel->surfmesh.num_triangles = meshtriangles;
2325         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2326         if (r_enableshadowvolumes.integer)
2327         {
2328                 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2329         }
2330         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2331         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2332         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2333         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2334         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2335         loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2336         loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]);
2337         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2338         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2339         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2340         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2341         loadmodel->surfmesh.num_blends = 0;
2342         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2343         if (meshvertices <= 65536)
2344         {
2345                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2346         }
2347         loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]);
2348         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2349
2350         for (i = 0;i < loadmodel->numskins;i++)
2351         {
2352                 loadmodel->skinscenes[i].firstframe = i;
2353                 loadmodel->skinscenes[i].framecount = 1;
2354                 loadmodel->skinscenes[i].loop = true;
2355                 loadmodel->skinscenes[i].framerate = 10;
2356         }
2357
2358         // load the bone info
2359         bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2360         for (i = 0;i < loadmodel->num_bones;i++)
2361         {
2362                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2363                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2364                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2365                 if (loadmodel->data_bones[i].parent >= i)
2366                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2367         }
2368
2369         // load the frames
2370         frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2371         // figure out scale of model from root bone, for compatibility with old dpmodel versions
2372         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2373         tempvec[0] = BigFloat(poses[0]);
2374         tempvec[1] = BigFloat(poses[1]);
2375         tempvec[2] = BigFloat(poses[2]);
2376         modelscale = VectorLength(tempvec);
2377         biggestorigin = 0;
2378         for (i = 0;i < loadmodel->numframes;i++)
2379         {
2380                 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2381                 loadmodel->animscenes[i].firstframe = i;
2382                 loadmodel->animscenes[i].framecount = 1;
2383                 loadmodel->animscenes[i].loop = true;
2384                 loadmodel->animscenes[i].framerate = 10;
2385                 // load the bone poses for this frame
2386                 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2387                 for (j = 0;j < loadmodel->num_bones*12;j++)
2388                 {
2389                         f = fabs(BigFloat(poses[j]));
2390                         biggestorigin = max(biggestorigin, f);
2391                 }
2392                 // stuff not processed here: mins, maxs, yawradius, allradius
2393         }
2394         loadmodel->num_posescale = biggestorigin / 32767.0f;
2395         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2396         for (i = 0;i < loadmodel->numframes;i++)
2397         {
2398                 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2399                 for (j = 0;j < loadmodel->num_bones;j++)
2400                 {
2401                         float pose[12];
2402                         matrix4x4_t posematrix;
2403                         for (k = 0;k < 12;k++)
2404                                 pose[k] = BigFloat(frameposes[j*12+k]);
2405                         // scale child bones to match the root scale
2406                         if (loadmodel->data_bones[j].parent >= 0)
2407                         {
2408                                 pose[3] *= modelscale;
2409                                 pose[7] *= modelscale;
2410                                 pose[11] *= modelscale;
2411                         }
2412                         // normalize rotation matrix
2413                         VectorNormalize(pose + 0);
2414                         VectorNormalize(pose + 4);
2415                         VectorNormalize(pose + 8);
2416                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2417                         Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j));
2418                 }
2419         }
2420
2421         // load the meshes now
2422         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2423         meshvertices = 0;
2424         meshtriangles = 0;
2425         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2426         // (converting from weight-blending skeletal animation to
2427         //  deformation-based skeletal animation)
2428         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2429         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2430         for (i = 0;i < loadmodel->num_bones;i++)
2431         {
2432                 float m[12];
2433                 for (k = 0;k < 12;k++)
2434                         m[k] = BigFloat(poses[i*12+k]);
2435                 if (loadmodel->data_bones[i].parent >= 0)
2436                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2437                 else
2438                         for (k = 0;k < 12;k++)
2439                                 bonepose[12*i+k] = m[k];
2440         }
2441         for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2442         {
2443                 const int *inelements;
2444                 int *outelements;
2445                 const float *intexcoord;
2446                 msurface_t *surface;
2447
2448                 loadmodel->sortedmodelsurfaces[i] = i;
2449                 surface = loadmodel->data_surfaces + i;
2450                 surface->texture = loadmodel->data_textures + i;
2451                 surface->num_firsttriangle = meshtriangles;
2452                 surface->num_triangles = BigLong(dpmmesh->num_tris);
2453                 surface->num_firstvertex = meshvertices;
2454                 surface->num_vertices = BigLong(dpmmesh->num_verts);
2455                 meshvertices += surface->num_vertices;
2456                 meshtriangles += surface->num_triangles;
2457
2458                 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2459                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2460                 for (j = 0;j < surface->num_triangles;j++)
2461                 {
2462                         // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2463                         outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
2464                         outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
2465                         outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
2466                         inelements += 3;
2467                         outelements += 3;
2468                 }
2469
2470                 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2471                 for (j = 0;j < surface->num_vertices*2;j++)
2472                         loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2473
2474                 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2475                 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2476                 {
2477                         int weightindex[4] = { 0, 0, 0, 0 };
2478                         float weightinfluence[4] = { 0, 0, 0, 0 };
2479                         int l;
2480                         int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2481                         data += sizeof(dpmvertex_t);
2482                         for (k = 0;k < numweights;k++)
2483                         {
2484                                 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2485                                 int boneindex = BigLong(vert->bonenum);
2486                                 const float *m = bonepose + 12 * boneindex;
2487                                 float influence = BigFloat(vert->influence);
2488                                 float relativeorigin[3], relativenormal[3];
2489                                 relativeorigin[0] = BigFloat(vert->origin[0]);
2490                                 relativeorigin[1] = BigFloat(vert->origin[1]);
2491                                 relativeorigin[2] = BigFloat(vert->origin[2]);
2492                                 relativenormal[0] = BigFloat(vert->normal[0]);
2493                                 relativenormal[1] = BigFloat(vert->normal[1]);
2494                                 relativenormal[2] = BigFloat(vert->normal[2]);
2495                                 // blend the vertex bone weights into the base mesh
2496                                 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2497                                 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2498                                 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2499                                 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2500                                 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2501                                 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2502                                 if (!k)
2503                                 {
2504                                         // store the first (and often only) weight
2505                                         weightinfluence[0] = influence;
2506                                         weightindex[0] = boneindex;
2507                                 }
2508                                 else
2509                                 {
2510                                         // sort the new weight into this vertex's weight table
2511                                         // (which only accepts up to 4 bones per vertex)
2512                                         for (l = 0;l < 4;l++)
2513                                         {
2514                                                 if (weightinfluence[l] < influence)
2515                                                 {
2516                                                         // move weaker influence weights out of the way first
2517                                                         int l2;
2518                                                         for (l2 = 3;l2 > l;l2--)
2519                                                         {
2520                                                                 weightinfluence[l2] = weightinfluence[l2-1];
2521                                                                 weightindex[l2] = weightindex[l2-1];
2522                                                         }
2523                                                         // store the new weight
2524                                                         weightinfluence[l] = influence;
2525                                                         weightindex[l] = boneindex;
2526                                                         break;
2527                                                 }
2528                                         }
2529                                 }
2530                                 data += sizeof(dpmbonevert_t);
2531                         }
2532                         loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2533                         loadmodel->surfmesh.data_skeletalindex4ub[j*4  ] = weightindex[0];
2534                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1];
2535                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2];
2536                         loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3];
2537                         loadmodel->surfmesh.data_skeletalweight4ub[j*4  ] = (unsigned char)(weightinfluence[0]*255.0f);
2538                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f);
2539                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f);
2540                         loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f);
2541                 }
2542
2543                 // since dpm models do not have named sections, reuse their shader name as the section name
2544                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2545
2546                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2547         }
2548         if (loadmodel->surfmesh.num_blends < meshvertices)
2549                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2550         Z_Free(bonepose);
2551         Mod_FreeSkinFiles(skinfiles);
2552         Mod_MakeSortedSurfaces(loadmodel);
2553
2554         // compute all the mesh information that was not loaded from the file
2555         if (loadmodel->surfmesh.data_element3s)
2556                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2557                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2558         Mod_BuildBaseBonePoses();
2559         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);
2560         if (loadmodel->surfmesh.data_neighbor3i)
2561                 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2562         loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
2563         if(mod_alias_force_animated.string[0])
2564                 loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0;
2565
2566         // Always make a BIH for the first frame, we can use it where possible.
2567         Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2568         if (!loadmodel->surfmesh.isanimated)
2569         {
2570                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2571                 loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush;
2572                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2573                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2574                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2575         }
2576
2577         // because shaders can do somewhat unexpected things, check for unusual features now
2578         for (i = 0;i < loadmodel->num_textures;i++)
2579         {
2580                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY))
2581                         mod->DrawSky = R_Q1BSP_DrawSky;
2582                 if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
2583                         mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
2584         }
2585 }
2586
2587 // no idea why PSK/PSA files contain weird quaternions but they do...
2588 #define PSKQUATNEGATIONS
2589 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2590 {
2591         int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2592         int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2593         fs_offset_t filesize;
2594         pskpnts_t *pnts;
2595         pskvtxw_t *vtxw;
2596         pskface_t *faces;
2597         pskmatt_t *matts;
2598         pskboneinfo_t *bones;
2599         pskrawweights_t *rawweights;
2600         //pskboneinfo_t *animbones;
2601         pskaniminfo_t *anims;
2602         pskanimkeys_t *animkeys;
2603         void *animfilebuffer, *animbuffer, *animbufferend;
2604         unsigned char *data;
2605         pskchunk_t *pchunk;
2606         skinfile_t *skinfiles;
2607         char animname[MAX_QPATH];
2608         size_t size;
2609         float biggestorigin;
2610
2611         pchunk = (pskchunk_t *)buffer;
2612         if (strcmp(pchunk->id, "ACTRHEAD"))
2613                 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2614
2615         loadmodel->modeldatatypestring = "PSK";
2616
2617         loadmodel->type = mod_alias;
2618         loadmodel->DrawSky = NULL;
2619         loadmodel->DrawAddWaterPlanes = NULL;
2620         loadmodel->Draw = R_Q1BSP_Draw;
2621         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2622         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2623         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2624         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2625         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2626         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2627         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2628         loadmodel->DrawLight = R_Q1BSP_DrawLight;
2629         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2630         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2631         loadmodel->PointSuperContents = NULL;
2632         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2633         loadmodel->synctype = ST_RAND;
2634
2635         FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2636         strlcat(animname, ".psa", sizeof(animname));
2637         animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2638         animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2639         if (!animbuffer)
2640                 animbufferend = animbuffer;
2641
2642         numpnts = 0;
2643         pnts = NULL;
2644         numvtxw = 0;
2645         vtxw = NULL;
2646         numfaces = 0;
2647         faces = NULL;
2648         nummatts = 0;
2649         matts = NULL;
2650         numbones = 0;
2651         bones = NULL;
2652         numrawweights = 0;
2653         rawweights = NULL;
2654         numanims = 0;
2655         anims = NULL;
2656         numanimkeys = 0;
2657         animkeys = NULL;
2658
2659         while (buffer < bufferend)
2660         {
2661                 pchunk = (pskchunk_t *)buffer;
2662                 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2663                 version = LittleLong(pchunk->version);
2664                 recordsize = LittleLong(pchunk->recordsize);
2665                 numrecords = LittleLong(pchunk->numrecords);
2666                 if (developer_extra.integer)
2667                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2668                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2669                         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);
2670                 if (!strcmp(pchunk->id, "ACTRHEAD"))
2671                 {
2672                         // nothing to do
2673                 }
2674                 else if (!strcmp(pchunk->id, "PNTS0000"))
2675                 {
2676                         pskpnts_t *p;
2677                         if (recordsize != sizeof(*p))
2678                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2679                         // byteswap in place and keep the pointer
2680                         numpnts = numrecords;
2681                         pnts = (pskpnts_t *)buffer;
2682                         for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2683                         {
2684                                 p->origin[0] = LittleFloat(p->origin[0]);
2685                                 p->origin[1] = LittleFloat(p->origin[1]);
2686                                 p->origin[2] = LittleFloat(p->origin[2]);
2687                         }
2688                         buffer = p;
2689                 }
2690                 else if (!strcmp(pchunk->id, "VTXW0000"))
2691                 {
2692                         pskvtxw_t *p;
2693                         if (recordsize != sizeof(*p))
2694                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2695                         // byteswap in place and keep the pointer
2696                         numvtxw = numrecords;
2697                         vtxw = (pskvtxw_t *)buffer;
2698                         for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2699                         {
2700                                 p->pntsindex = LittleShort(p->pntsindex);
2701                                 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2702                                 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2703                                 if (p->pntsindex >= numpnts)
2704                                 {
2705                                         Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2706                                         p->pntsindex = 0;
2707                                 }
2708                         }
2709                         buffer = p;
2710                 }
2711                 else if (!strcmp(pchunk->id, "FACE0000"))
2712                 {
2713                         pskface_t *p;
2714                         if (recordsize != sizeof(*p))
2715                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2716                         // byteswap in place and keep the pointer
2717                         numfaces = numrecords;
2718                         faces = (pskface_t *)buffer;
2719                         for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2720                         {
2721                                 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2722                                 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2723                                 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2724                                 p->group = LittleLong(p->group);
2725                                 if (p->vtxwindex[0] >= numvtxw)
2726                                 {
2727                                         Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2728                                         p->vtxwindex[0] = 0;
2729                                 }
2730                                 if (p->vtxwindex[1] >= numvtxw)
2731                                 {
2732                                         Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2733                                         p->vtxwindex[1] = 0;
2734                                 }
2735                                 if (p->vtxwindex[2] >= numvtxw)
2736                                 {
2737                                         Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2738                                         p->vtxwindex[2] = 0;
2739                                 }
2740                         }
2741                         buffer = p;
2742                 }
2743                 else if (!strcmp(pchunk->id, "MATT0000"))
2744                 {
2745                         pskmatt_t *p;
2746                         if (recordsize != sizeof(*p))
2747                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2748                         // byteswap in place and keep the pointer
2749                         nummatts = numrecords;
2750                         matts = (pskmatt_t *)buffer;
2751                         for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2752                         {
2753                                 // nothing to do
2754                         }
2755                         buffer = p;
2756                 }
2757                 else if (!strcmp(pchunk->id, "REFSKELT"))
2758                 {
2759                         pskboneinfo_t *p;
2760                         if (recordsize != sizeof(*p))
2761                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2762                         // byteswap in place and keep the pointer
2763                         numbones = numrecords;
2764                         bones = (pskboneinfo_t *)buffer;
2765                         for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2766                         {
2767                                 p->numchildren = LittleLong(p->numchildren);
2768                                 p->parent = LittleLong(p->parent);
2769                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2770                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2771                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2772                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2773                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2774                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2775                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2776                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2777                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2778                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2779                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2780 #ifdef PSKQUATNEGATIONS
2781                                 if (index)
2782                                 {
2783                                         p->basepose.quat[0] *= -1;
2784                                         p->basepose.quat[1] *= -1;
2785                                         p->basepose.quat[2] *= -1;
2786                                 }
2787                                 else
2788                                 {
2789                                         p->basepose.quat[0] *=  1;
2790                                         p->basepose.quat[1] *= -1;
2791                                         p->basepose.quat[2] *=  1;
2792                                 }
2793 #endif
2794                                 if (p->parent < 0 || p->parent >= numbones)
2795                                 {
2796                                         Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2797                                         p->parent = 0;
2798                                 }
2799                         }
2800                         buffer = p;
2801                 }
2802                 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2803                 {
2804                         pskrawweights_t *p;
2805                         if (recordsize != sizeof(*p))
2806                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2807                         // byteswap in place and keep the pointer
2808                         numrawweights = numrecords;
2809                         rawweights = (pskrawweights_t *)buffer;
2810                         for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2811                         {
2812                                 p->weight = LittleFloat(p->weight);
2813                                 p->pntsindex = LittleLong(p->pntsindex);
2814                                 p->boneindex = LittleLong(p->boneindex);
2815                                 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2816                                 {
2817                                         Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2818                                         p->pntsindex = 0;
2819                                 }
2820                                 if (p->boneindex < 0 || p->boneindex >= numbones)
2821                                 {
2822                                         Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2823                                         p->boneindex = 0;
2824                                 }
2825                         }
2826                         buffer = p;
2827                 }
2828         }
2829
2830         while (animbuffer < animbufferend)
2831         {
2832                 pchunk = (pskchunk_t *)animbuffer;
2833                 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2834                 version = LittleLong(pchunk->version);
2835                 recordsize = LittleLong(pchunk->recordsize);
2836                 numrecords = LittleLong(pchunk->numrecords);
2837                 if (developer_extra.integer)
2838                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2839                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2840                         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);
2841                 if (!strcmp(pchunk->id, "ANIMHEAD"))
2842                 {
2843                         // nothing to do
2844                 }
2845                 else if (!strcmp(pchunk->id, "BONENAMES"))
2846                 {
2847                         pskboneinfo_t *p;
2848                         if (recordsize != sizeof(*p))
2849                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2850                         // byteswap in place and keep the pointer
2851                         numanimbones = numrecords;
2852                         //animbones = (pskboneinfo_t *)animbuffer;
2853                         // NOTE: supposedly psa does not need to match the psk model, the
2854                         // bones missing from the psa would simply use their base
2855                         // positions from the psk, but this is hard for me to implement
2856                         // and people can easily make animations that match.
2857                         if (numanimbones != numbones)
2858                                 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2859                         for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2860                         {
2861                                 p->numchildren = LittleLong(p->numchildren);
2862                                 p->parent = LittleLong(p->parent);
2863                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2864                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2865                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2866                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2867                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2868                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2869                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2870                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2871                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2872                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2873                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2874 #ifdef PSKQUATNEGATIONS
2875                                 if (index)
2876                                 {
2877                                         p->basepose.quat[0] *= -1;
2878                                         p->basepose.quat[1] *= -1;
2879                                         p->basepose.quat[2] *= -1;
2880                                 }
2881                                 else
2882                                 {
2883                                         p->basepose.quat[0] *=  1;
2884                                         p->basepose.quat[1] *= -1;
2885                                         p->basepose.quat[2] *=  1;
2886                                 }
2887 #endif
2888                                 if (p->parent < 0 || p->parent >= numanimbones)
2889                                 {
2890                                         Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2891                                         p->parent = 0;
2892                                 }
2893                                 // check that bones are the same as in the base
2894                                 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2895                                         Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2896                         }
2897                         animbuffer = p;
2898                 }
2899                 else if (!strcmp(pchunk->id, "ANIMINFO"))
2900         &nbs