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