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