Mod_BuildAliasSkinsFromSkinFile: strip image extension
[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                         Z_Free(bonepose);
133                 maxbonepose = model->num_bones*2 + model->surfmesh.num_blends;
134                 bonepose = (float (*)[12])Z_Malloc(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         static char stripbuf[MAX_QPATH];
959         skinfileitem_t *skinfileitem;
960         if (skinfile)
961         {
962                 // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
963                 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
964                 {
965                         memset(skin, 0, sizeof(*skin));
966                         // see if a mesh
967                         for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
968                         {
969                                 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
970                                 if (!strcmp(skinfileitem->name, meshname))
971                                 {
972                                         Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf));
973                                         Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
974                                         break;
975                                 }
976                         }
977                         if (!skinfileitem)
978                         {
979                                 // don't render unmentioned meshes
980                                 Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
981                                 skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW;
982                         }
983                 }
984         }
985         else
986         {
987                 Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf));
988                 Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
989         }
990 }
991
992 #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);
993 #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);
994 void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
995 {
996         int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
997         float scales, scalet, interval;
998         msurface_t *surface;
999         unsigned char *data;
1000         mdl_t *pinmodel;
1001         stvert_t *pinstverts;
1002         dtriangle_t *pintriangles;
1003         daliasskintype_t *pinskintype;
1004         daliasskingroup_t *pinskingroup;
1005         daliasskininterval_t *pinskinintervals;
1006         daliasframetype_t *pinframetype;
1007         daliasgroup_t *pinframegroup;
1008         unsigned char *datapointer, *startframes, *startskins;
1009         char name[MAX_QPATH];
1010         skinframe_t *tempskinframe;
1011         animscene_t *tempskinscenes;
1012         texture_t *tempaliasskins;
1013         float *vertst;
1014         int *vertonseam, *vertremap;
1015         skinfile_t *skinfiles;
1016
1017         datapointer = (unsigned char *)buffer;
1018         pinmodel = (mdl_t *)datapointer;
1019         datapointer += sizeof(mdl_t);
1020
1021         version = LittleLong (pinmodel->version);
1022         if (version != ALIAS_VERSION)
1023                 Host_Error ("%s has wrong version number (%i should be %i)",
1024                                  loadmodel->name, version, ALIAS_VERSION);
1025
1026         loadmodel->modeldatatypestring = "MDL";
1027
1028         loadmodel->type = mod_alias;
1029         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1030         loadmodel->DrawSky = NULL;
1031         loadmodel->DrawAddWaterPlanes = NULL;
1032         loadmodel->Draw = R_Q1BSP_Draw;
1033         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1034         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1035         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1036         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1037         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1038         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1039         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1040         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1041         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1042         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1043         loadmodel->PointSuperContents = NULL;
1044
1045         loadmodel->num_surfaces = 1;
1046         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1047         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
1048         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1049         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1050         loadmodel->sortedmodelsurfaces[0] = 0;
1051
1052         loadmodel->numskins = LittleLong(pinmodel->numskins);
1053         BOUNDI(loadmodel->numskins,0,65536);
1054         skinwidth = LittleLong (pinmodel->skinwidth);
1055         BOUNDI(skinwidth,0,65536);
1056         skinheight = LittleLong (pinmodel->skinheight);
1057         BOUNDI(skinheight,0,65536);
1058         numverts = LittleLong(pinmodel->numverts);
1059         BOUNDI(numverts,0,65536);
1060         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
1061         BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
1062         loadmodel->numframes = LittleLong(pinmodel->numframes);
1063         BOUNDI(loadmodel->numframes,0,65536);
1064         loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
1065         BOUNDI((int)loadmodel->synctype,0,2);
1066         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1067         i = LittleLong (pinmodel->flags);
1068         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1069
1070         for (i = 0;i < 3;i++)
1071         {
1072                 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
1073                 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
1074         }
1075
1076         startskins = datapointer;
1077         totalskins = 0;
1078         for (i = 0;i < loadmodel->numskins;i++)
1079         {
1080                 pinskintype = (daliasskintype_t *)datapointer;
1081                 datapointer += sizeof(daliasskintype_t);
1082                 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
1083                         groupskins = 1;
1084                 else
1085                 {
1086                         pinskingroup = (daliasskingroup_t *)datapointer;
1087                         datapointer += sizeof(daliasskingroup_t);
1088                         groupskins = LittleLong(pinskingroup->numskins);
1089                         datapointer += sizeof(daliasskininterval_t) * groupskins;
1090                 }
1091
1092                 for (j = 0;j < groupskins;j++)
1093                 {
1094                         datapointer += skinwidth * skinheight;
1095                         totalskins++;
1096                 }
1097         }
1098
1099         pinstverts = (stvert_t *)datapointer;
1100         datapointer += sizeof(stvert_t) * numverts;
1101
1102         pintriangles = (dtriangle_t *)datapointer;
1103         datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
1104
1105         startframes = datapointer;
1106         loadmodel->surfmesh.num_morphframes = 0;
1107         for (i = 0;i < loadmodel->numframes;i++)
1108         {
1109                 pinframetype = (daliasframetype_t *)datapointer;
1110                 datapointer += sizeof(daliasframetype_t);
1111                 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
1112                         groupframes = 1;
1113                 else
1114                 {
1115                         pinframegroup = (daliasgroup_t *)datapointer;
1116                         datapointer += sizeof(daliasgroup_t);
1117                         groupframes = LittleLong(pinframegroup->numframes);
1118                         datapointer += sizeof(daliasinterval_t) * groupframes;
1119                 }
1120
1121                 for (j = 0;j < groupframes;j++)
1122                 {
1123                         datapointer += sizeof(daliasframe_t);
1124                         datapointer += sizeof(trivertx_t) * numverts;
1125                         loadmodel->surfmesh.num_morphframes++;
1126                 }
1127         }
1128         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1129
1130         // store texture coordinates into temporary array, they will be stored
1131         // after usage is determined (triangle data)
1132         vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
1133         vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
1134         vertonseam = vertremap + numverts * 2;
1135
1136         scales = 1.0 / skinwidth;
1137         scalet = 1.0 / skinheight;
1138         for (i = 0;i < numverts;i++)
1139         {
1140                 vertonseam[i] = LittleLong(pinstverts[i].onseam);
1141                 vertst[i*2+0] = (LittleLong(pinstverts[i].s) + 0.5) * scales;
1142                 vertst[i*2+1] = (LittleLong(pinstverts[i].t) + 0.5) * scalet;
1143                 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
1144                 vertst[(i+numverts)*2+1] = vertst[i*2+1];
1145         }
1146
1147 // load triangle data
1148         loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
1149
1150         // read the triangle elements
1151         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1152                 for (j = 0;j < 3;j++)
1153                         loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
1154         // validate (note numverts is used because this is the original data)
1155         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
1156         // now butcher the elements according to vertonseam and tri->facesfront
1157         // and then compact the vertex set to remove duplicates
1158         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1159                 if (!LittleLong(pintriangles[i].facesfront)) // backface
1160                         for (j = 0;j < 3;j++)
1161                                 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
1162                                         loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
1163         // count the usage
1164         // (this uses vertremap to count usage to save some memory)
1165         for (i = 0;i < numverts*2;i++)
1166                 vertremap[i] = 0;
1167         for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1168                 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
1169         // build remapping table and compact array
1170         loadmodel->surfmesh.num_vertices = 0;
1171         for (i = 0;i < numverts*2;i++)
1172         {
1173                 if (vertremap[i])
1174                 {
1175                         vertremap[i] = loadmodel->surfmesh.num_vertices;
1176                         vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
1177                         vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
1178                         loadmodel->surfmesh.num_vertices++;
1179                 }
1180                 else
1181                         vertremap[i] = -1; // not used at all
1182         }
1183         // remap the elements to the new vertex set
1184         for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
1185                 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
1186         // store the texture coordinates
1187         loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
1188         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1189         {
1190                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
1191                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
1192         }
1193
1194         // generate ushort elements array if possible
1195         if (loadmodel->surfmesh.num_vertices <= 65536)
1196                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1197         if (loadmodel->surfmesh.data_element3s)
1198                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1199                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1200
1201 // load the frames
1202         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1203         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
1204         loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
1205         Mod_MDL_LoadFrames (startframes, numverts, vertremap);
1206         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1207         Mod_Alias_CalculateBoundingBox();
1208         Mod_Alias_MorphMesh_CompileFrames();
1209
1210         Mem_Free(vertst);
1211         Mem_Free(vertremap);
1212
1213         // load the skins
1214         skinfiles = Mod_LoadSkinFiles();
1215         if (skinfiles)
1216         {
1217                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1218                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1219                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1220                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1221                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1222                 Mod_FreeSkinFiles(skinfiles);
1223                 for (i = 0;i < loadmodel->numskins;i++)
1224                 {
1225                         loadmodel->skinscenes[i].firstframe = i;
1226                         loadmodel->skinscenes[i].framecount = 1;
1227                         loadmodel->skinscenes[i].loop = true;
1228                         loadmodel->skinscenes[i].framerate = 10;
1229                 }
1230         }
1231         else
1232         {
1233                 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1234                 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1235                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1236                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1237                 totalskins = 0;
1238                 datapointer = startskins;
1239                 for (i = 0;i < loadmodel->numskins;i++)
1240                 {
1241                         pinskintype = (daliasskintype_t *)datapointer;
1242                         datapointer += sizeof(daliasskintype_t);
1243
1244                         if (pinskintype->type == ALIAS_SKIN_SINGLE)
1245                         {
1246                                 groupskins = 1;
1247                                 interval = 0.1f;
1248                         }
1249                         else
1250                         {
1251                                 pinskingroup = (daliasskingroup_t *)datapointer;
1252                                 datapointer += sizeof(daliasskingroup_t);
1253
1254                                 groupskins = LittleLong (pinskingroup->numskins);
1255
1256                                 pinskinintervals = (daliasskininterval_t *)datapointer;
1257                                 datapointer += sizeof(daliasskininterval_t) * groupskins;
1258
1259                                 interval = LittleFloat(pinskinintervals[0].interval);
1260                                 if (interval < 0.01f)
1261                                 {
1262                                         Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1263                                         interval = 0.1f;
1264                                 }
1265                         }
1266
1267                         dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1268                         loadmodel->skinscenes[i].firstframe = totalskins;
1269                         loadmodel->skinscenes[i].framecount = groupskins;
1270                         loadmodel->skinscenes[i].framerate = 1.0f / interval;
1271                         loadmodel->skinscenes[i].loop = true;
1272
1273                         for (j = 0;j < groupskins;j++)
1274                         {
1275                                 if (groupskins > 1)
1276                                         dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1277                                 else
1278                                         dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1279                                 if (!Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS))
1280                                         Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, R_SkinFrame_LoadInternalQuake(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight));
1281                                 datapointer += skinwidth * skinheight;
1282                                 totalskins++;
1283                         }
1284                 }
1285                 // check for skins that don't exist in the model, but do exist as external images
1286                 // (this was added because yummyluv kept pestering me about support for it)
1287                 // TODO: support shaders here?
1288                 while ((tempskinframe = R_SkinFrame_LoadExternal(va("%s_%i", loadmodel->name, loadmodel->numskins), (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false)))
1289                 {
1290                         // expand the arrays to make room
1291                         tempskinscenes = loadmodel->skinscenes;
1292                         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1293                         memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1294                         Mem_Free(tempskinscenes);
1295
1296                         tempaliasskins = loadmodel->data_textures;
1297                         loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1298                         memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1299                         Mem_Free(tempaliasskins);
1300
1301                         // store the info about the new skin
1302                         Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, tempskinframe);
1303                         strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1304                         loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1305                         loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1306                         loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1307                         loadmodel->skinscenes[loadmodel->numskins].loop = true;
1308
1309                         //increase skin counts
1310                         loadmodel->numskins++;
1311                         totalskins++;
1312
1313                         // fix up the pointers since they are pointing at the old textures array
1314                         // FIXME: this is a hack!
1315                         for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1316                                 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1317                 }
1318         }
1319
1320         surface = loadmodel->data_surfaces;
1321         surface->texture = loadmodel->data_textures;
1322         surface->num_firsttriangle = 0;
1323         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1324         surface->num_firstvertex = 0;
1325         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1326
1327         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
1328
1329         if (!loadmodel->surfmesh.isanimated)
1330         {
1331                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1332                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1333                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1334                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1335                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1336         }
1337 }
1338
1339 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
1340 {
1341         int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1342         float iskinwidth, iskinheight;
1343         unsigned char *data;
1344         msurface_t *surface;
1345         md2_t *pinmodel;
1346         unsigned char *base, *datapointer;
1347         md2frame_t *pinframe;
1348         char *inskin;
1349         md2triangle_t *intri;
1350         unsigned short *inst;
1351         struct md2verthash_s
1352         {
1353                 struct md2verthash_s *next;
1354                 unsigned short xyz;
1355                 unsigned short st;
1356         }
1357         *hash, **md2verthash, *md2verthashdata;
1358         skinfile_t *skinfiles;
1359
1360         pinmodel = (md2_t *)buffer;
1361         base = (unsigned char *)buffer;
1362
1363         version = LittleLong (pinmodel->version);
1364         if (version != MD2ALIAS_VERSION)
1365                 Host_Error ("%s has wrong version number (%i should be %i)",
1366                         loadmodel->name, version, MD2ALIAS_VERSION);
1367
1368         loadmodel->modeldatatypestring = "MD2";
1369
1370         loadmodel->type = mod_alias;
1371         loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1372         loadmodel->DrawSky = NULL;
1373         loadmodel->DrawAddWaterPlanes = NULL;
1374         loadmodel->Draw = R_Q1BSP_Draw;
1375         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1376         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1377         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1378         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1379         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1380         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1381         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1382         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1383         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1384         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1385         loadmodel->PointSuperContents = NULL;
1386
1387         if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1388                 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1389         if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1390                 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1391         if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1392                 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1393         if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1394                 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1395
1396         end = LittleLong(pinmodel->ofs_end);
1397         if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1398                 Host_Error ("%s is not a valid model", loadmodel->name);
1399         if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1400                 Host_Error ("%s is not a valid model", loadmodel->name);
1401         if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1402                 Host_Error ("%s is not a valid model", loadmodel->name);
1403         if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1404                 Host_Error ("%s is not a valid model", loadmodel->name);
1405         if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1406                 Host_Error ("%s is not a valid model", loadmodel->name);
1407
1408         loadmodel->numskins = LittleLong(pinmodel->num_skins);
1409         numxyz = LittleLong(pinmodel->num_xyz);
1410         numst = LittleLong(pinmodel->num_st);
1411         loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1412         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1413         loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1414         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1415         skinwidth = LittleLong(pinmodel->skinwidth);
1416         skinheight = LittleLong(pinmodel->skinheight);
1417         iskinwidth = 1.0f / skinwidth;
1418         iskinheight = 1.0f / skinheight;
1419
1420         loadmodel->num_surfaces = 1;
1421         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1422         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->numframes * sizeof(animscene_t) + loadmodel->numframes * sizeof(float[6]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]));
1423         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1424         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1425         loadmodel->sortedmodelsurfaces[0] = 0;
1426         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1427         loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1428         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1429         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1430
1431         loadmodel->synctype = ST_RAND;
1432
1433         // load the skins
1434         inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1435         skinfiles = Mod_LoadSkinFiles();
1436         if (skinfiles)
1437         {
1438                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1439                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1440                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1441                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1442                 Mod_FreeSkinFiles(skinfiles);
1443         }
1444         else if (loadmodel->numskins)
1445         {
1446                 // skins found (most likely not a player model)
1447                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1448                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1449                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1450                 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1451                         Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
1452         }
1453         else
1454         {
1455                 // no skins (most likely a player model)
1456                 loadmodel->numskins = 1;
1457                 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1458                 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1459                 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1460                 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL);
1461         }
1462
1463         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1464         for (i = 0;i < loadmodel->numskins;i++)
1465         {
1466                 loadmodel->skinscenes[i].firstframe = i;
1467                 loadmodel->skinscenes[i].framecount = 1;
1468                 loadmodel->skinscenes[i].loop = true;
1469                 loadmodel->skinscenes[i].framerate = 10;
1470         }
1471
1472         // load the triangles and stvert data
1473         inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1474         intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1475         md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1476         md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1477         // swap the triangle list
1478         loadmodel->surfmesh.num_vertices = 0;
1479         for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1480         {
1481                 for (j = 0;j < 3;j++)
1482                 {
1483                         xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1484                         st = (unsigned short) LittleShort (intri[i].index_st[j]);
1485                         if (xyz >= numxyz)
1486                         {
1487                                 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1488                                 xyz = 0;
1489                         }
1490                         if (st >= numst)
1491                         {
1492                                 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1493                                 st = 0;
1494                         }
1495                         hashindex = (xyz * 256 + st) & 65535;
1496                         for (hash = md2verthash[hashindex];hash;hash = hash->next)
1497                                 if (hash->xyz == xyz && hash->st == st)
1498                                         break;
1499                         if (hash == NULL)
1500                         {
1501                                 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1502                                 hash->xyz = xyz;
1503                                 hash->st = st;
1504                                 hash->next = md2verthash[hashindex];
1505                                 md2verthash[hashindex] = hash;
1506                         }
1507                         loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1508                 }
1509         }
1510
1511         vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1512         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));
1513         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1514         loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1515         for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1516         {
1517                 int sts, stt;
1518                 hash = md2verthashdata + i;
1519                 vertremap[i] = hash->xyz;
1520                 sts = LittleShort(inst[hash->st*2+0]);
1521                 stt = LittleShort(inst[hash->st*2+1]);
1522                 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1523                 {
1524                         Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1525                         sts = 0;
1526                         stt = 0;
1527                 }
1528                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1529                 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1530         }
1531
1532         Mem_Free(md2verthash);
1533         Mem_Free(md2verthashdata);
1534
1535         // generate ushort elements array if possible
1536         if (loadmodel->surfmesh.num_vertices <= 65536)
1537                 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1538         if (loadmodel->surfmesh.data_element3s)
1539                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1540                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1541
1542         // load the frames
1543         datapointer = (base + LittleLong(pinmodel->ofs_frames));
1544         for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1545         {
1546                 int k;
1547                 trivertx_t *v;
1548                 trivertx_t *out;
1549                 pinframe = (md2frame_t *)datapointer;
1550                 datapointer += sizeof(md2frame_t);
1551                 // store the frame scale/translate into the appropriate array
1552                 for (j = 0;j < 3;j++)
1553                 {
1554                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1555                         loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1556                 }
1557                 // convert the vertices
1558                 v = (trivertx_t *)datapointer;
1559                 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1560                 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1561                         out[k] = v[vertremap[k]];
1562                 datapointer += numxyz * sizeof(trivertx_t);
1563
1564                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1565                 loadmodel->animscenes[i].firstframe = i;
1566                 loadmodel->animscenes[i].framecount = 1;
1567                 loadmodel->animscenes[i].framerate = 10;
1568                 loadmodel->animscenes[i].loop = true;
1569         }
1570
1571         Mem_Free(vertremap);
1572
1573         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1574         Mod_Alias_CalculateBoundingBox();
1575         Mod_Alias_MorphMesh_CompileFrames();
1576
1577         surface = loadmodel->data_surfaces;
1578         surface->texture = loadmodel->data_textures;
1579         surface->num_firsttriangle = 0;
1580         surface->num_triangles = loadmodel->surfmesh.num_triangles;
1581         surface->num_firstvertex = 0;
1582         surface->num_vertices = loadmodel->surfmesh.num_vertices;
1583
1584         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
1585
1586         if (!loadmodel->surfmesh.isanimated)
1587         {
1588                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1589                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1590                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1591                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1592                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1593         }
1594 }
1595
1596 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
1597 {
1598         int i, j, k, version, meshvertices, meshtriangles;
1599         unsigned char *data;
1600         msurface_t *surface;
1601         md3modelheader_t *pinmodel;
1602         md3frameinfo_t *pinframe;
1603         md3mesh_t *pinmesh;
1604         md3tag_t *pintag;
1605         skinfile_t *skinfiles;
1606
1607         pinmodel = (md3modelheader_t *)buffer;
1608
1609         if (memcmp(pinmodel->identifier, "IDP3", 4))
1610                 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1611         version = LittleLong (pinmodel->version);
1612         if (version != MD3VERSION)
1613                 Host_Error ("%s has wrong version number (%i should be %i)",
1614                         loadmodel->name, version, MD3VERSION);
1615
1616         skinfiles = Mod_LoadSkinFiles();
1617         if (loadmodel->numskins < 1)
1618                 loadmodel->numskins = 1;
1619
1620         loadmodel->modeldatatypestring = "MD3";
1621
1622         loadmodel->type = mod_alias;
1623         loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1624         loadmodel->DrawSky = NULL;
1625         loadmodel->DrawAddWaterPlanes = NULL;
1626         loadmodel->Draw = R_Q1BSP_Draw;
1627         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1628         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1629         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1630         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1631         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1632         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1633         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1634         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1635         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1636         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1637         loadmodel->PointSuperContents = NULL;
1638         loadmodel->synctype = ST_RAND;
1639         // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1640         i = LittleLong (pinmodel->flags);
1641         loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1642
1643         // set up some global info about the model
1644         loadmodel->numframes = LittleLong(pinmodel->num_frames);
1645         loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1646
1647         // make skinscenes for the skins (no groups)
1648         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1649         for (i = 0;i < loadmodel->numskins;i++)
1650         {
1651                 loadmodel->skinscenes[i].firstframe = i;
1652                 loadmodel->skinscenes[i].framecount = 1;
1653                 loadmodel->skinscenes[i].loop = true;
1654                 loadmodel->skinscenes[i].framerate = 10;
1655         }
1656
1657         // load frameinfo
1658         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1659         for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1660         {
1661                 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1662                 loadmodel->animscenes[i].firstframe = i;
1663                 loadmodel->animscenes[i].framecount = 1;
1664                 loadmodel->animscenes[i].framerate = 10;
1665                 loadmodel->animscenes[i].loop = true;
1666         }
1667
1668         // load tags
1669         loadmodel->num_tagframes = loadmodel->numframes;
1670         loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1671         loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1672         for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1673         {
1674                 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1675                 for (j = 0;j < 9;j++)
1676                         loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1677                 for (j = 0;j < 3;j++)
1678                         loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1679                 //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);
1680         }
1681
1682         // load meshes
1683         meshvertices = 0;
1684         meshtriangles = 0;
1685         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)))
1686         {
1687                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1688                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1689                 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1690                         Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1691                 meshvertices += LittleLong(pinmesh->num_vertices);
1692                 meshtriangles += LittleLong(pinmesh->num_triangles);
1693         }
1694
1695         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1696         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1697         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1698         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));
1699         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1700         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1701         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1702         loadmodel->surfmesh.num_vertices = meshvertices;
1703         loadmodel->surfmesh.num_triangles = meshtriangles;
1704         loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1705         loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1706         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1707         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1708         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1709         loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1710         if (meshvertices <= 65536)
1711                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1712
1713         meshvertices = 0;
1714         meshtriangles = 0;
1715         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)))
1716         {
1717                 if (memcmp(pinmesh->identifier, "IDP3", 4))
1718                         Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1719                 loadmodel->sortedmodelsurfaces[i] = i;
1720                 surface = loadmodel->data_surfaces + i;
1721                 surface->texture = loadmodel->data_textures + i;
1722                 surface->num_firsttriangle = meshtriangles;
1723                 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1724                 surface->num_firstvertex = meshvertices;
1725                 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1726                 meshvertices += surface->num_vertices;
1727                 meshtriangles += surface->num_triangles;
1728
1729                 for (j = 0;j < surface->num_triangles * 3;j++)
1730                         loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1731                 for (j = 0;j < surface->num_vertices;j++)
1732                 {
1733                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1734                         loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1735                 }
1736                 for (j = 0;j < loadmodel->numframes;j++)
1737                 {
1738                         const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1739                         md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1740                         for (k = 0;k < surface->num_vertices;k++, in++, out++)
1741                         {
1742                                 out->origin[0] = LittleShort(in->origin[0]);
1743                                 out->origin[1] = LittleShort(in->origin[1]);
1744                                 out->origin[2] = LittleShort(in->origin[2]);
1745                                 out->pitch = in->pitch;
1746                                 out->yaw = in->yaw;
1747                         }
1748                 }
1749
1750                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1751
1752                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1753         }
1754         if (loadmodel->surfmesh.data_element3s)
1755                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1756                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1757         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1758         Mod_Alias_MorphMesh_CompileFrames();
1759         Mod_Alias_CalculateBoundingBox();
1760         Mod_FreeSkinFiles(skinfiles);
1761         Mod_MakeSortedSurfaces(loadmodel);
1762
1763         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1
1764              || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
1765
1766         if (!loadmodel->surfmesh.isanimated)
1767         {
1768                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
1769                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
1770                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
1771                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
1772                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
1773         }
1774 }
1775
1776 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1777 {
1778         zymtype1header_t *pinmodel, *pheader;
1779         unsigned char *pbase;
1780         int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1781         float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale;
1782         zymvertex_t *verts, *vertdata;
1783         zymscene_t *scene;
1784         zymbone_t *bone;
1785         char *shadername;
1786         skinfile_t *skinfiles;
1787         unsigned char *data;
1788         msurface_t *surface;
1789
1790         pinmodel = (zymtype1header_t *)buffer;
1791         pbase = (unsigned char *)buffer;
1792         if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1793                 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1794         if (BigLong(pinmodel->type) != 1)
1795                 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1796
1797         loadmodel->modeldatatypestring = "ZYM";
1798
1799         loadmodel->type = mod_alias;
1800         loadmodel->synctype = ST_RAND;
1801
1802         // byteswap header
1803         pheader = pinmodel;
1804         pheader->type = BigLong(pinmodel->type);
1805         pheader->filesize = BigLong(pinmodel->filesize);
1806         pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1807         pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1808         pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1809         pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1810         pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1811         pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1812         pheader->radius = BigFloat(pinmodel->radius);
1813         pheader->numverts = BigLong(pinmodel->numverts);
1814         pheader->numtris = BigLong(pinmodel->numtris);
1815         pheader->numshaders = BigLong(pinmodel->numshaders);
1816         pheader->numbones = BigLong(pinmodel->numbones);
1817         pheader->numscenes = BigLong(pinmodel->numscenes);
1818         pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1819         pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1820         pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1821         pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1822         pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1823         pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1824         pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1825         pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1826         pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1827         pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1828         pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1829         pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1830         pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1831         pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1832         pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1833         pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1834         pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1835         pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1836
1837         if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1838         {
1839                 Con_Printf("%s has no geometry\n", loadmodel->name);
1840                 return;
1841         }
1842         if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1843         {
1844                 Con_Printf("%s has no animations\n", loadmodel->name);
1845                 return;
1846         }
1847
1848         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1849         loadmodel->DrawSky = NULL;
1850         loadmodel->DrawAddWaterPlanes = NULL;
1851         loadmodel->Draw = R_Q1BSP_Draw;
1852         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1853         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1854         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
1855         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
1856         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
1857         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1858         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1859         loadmodel->DrawLight = R_Q1BSP_DrawLight;
1860         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1861         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
1862         loadmodel->PointSuperContents = NULL;
1863
1864         loadmodel->numframes = pheader->numscenes;
1865         loadmodel->num_surfaces = pheader->numshaders;
1866
1867         skinfiles = Mod_LoadSkinFiles();
1868         if (loadmodel->numskins < 1)
1869                 loadmodel->numskins = 1;
1870
1871         // make skinscenes for the skins (no groups)
1872         loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1873         for (i = 0;i < loadmodel->numskins;i++)
1874         {
1875                 loadmodel->skinscenes[i].firstframe = i;
1876                 loadmodel->skinscenes[i].framecount = 1;
1877                 loadmodel->skinscenes[i].loop = true;
1878                 loadmodel->skinscenes[i].framerate = 10;
1879         }
1880
1881         // model bbox
1882         modelradius = pheader->radius;
1883         for (i = 0;i < 3;i++)
1884         {
1885                 loadmodel->normalmins[i] = pheader->mins[i];
1886                 loadmodel->normalmaxs[i] = pheader->maxs[i];
1887                 loadmodel->rotatedmins[i] = -modelradius;
1888                 loadmodel->rotatedmaxs[i] = modelradius;
1889         }
1890         corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1891         corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1892         loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1893         if (loadmodel->yawmaxs[0] > modelradius)
1894                 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1895         loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1896         loadmodel->yawmins[2] = loadmodel->normalmins[2];
1897         loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1898         loadmodel->radius = modelradius;
1899         loadmodel->radius2 = modelradius * modelradius;
1900
1901         // go through the lumps, swapping things
1902
1903         //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1904         loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1905         scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1906         numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1907         for (i = 0;i < pheader->numscenes;i++)
1908         {
1909                 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1910                 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1911                 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1912                 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1913                 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1914                 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1915                         Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1916                 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1917                         Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1918                 if (loadmodel->animscenes[i].framerate < 0)
1919                         Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1920                 scene++;
1921         }
1922
1923         //zymlump_t lump_bones; // zymbone_t bone[numbones];
1924         loadmodel->num_bones = pheader->numbones;
1925         loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t));
1926         bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1927         for (i = 0;i < pheader->numbones;i++)
1928         {
1929                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1930                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1931                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1932                 if (loadmodel->data_bones[i].parent >= i)
1933                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1934         }
1935
1936         //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1937         vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1938         bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1939         for (i = 0;i < pheader->numverts;i++)
1940         {
1941                 vertbonecounts[i] = BigLong(bonecount[i]);
1942                 if (vertbonecounts[i] != 1)
1943                         Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1944         }
1945
1946         loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones;
1947
1948         meshvertices = pheader->numverts;
1949         meshtriangles = pheader->numtris;
1950
1951         loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1952         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1953         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1954         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]));
1955         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1956         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1957         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1958         loadmodel->surfmesh.num_vertices = meshvertices;
1959         loadmodel->surfmesh.num_triangles = meshtriangles;
1960         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1961         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1962         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1963         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1964         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1965         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1966         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1967         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1968         loadmodel->surfmesh.num_blends = 0;
1969         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
1970         if (loadmodel->surfmesh.num_vertices <= 65536)
1971                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
1972         loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
1973         loadmodel->surfmesh.data_blendweights = NULL;
1974
1975         //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1976         poses = (float *) (pheader->lump_poses.start + pbase);
1977         // figure out scale of model from root bone, for compatibility with old zmodel versions
1978         tempvec[0] = BigFloat(poses[0]);
1979         tempvec[1] = BigFloat(poses[1]);
1980         tempvec[2] = BigFloat(poses[2]);
1981         modelscale = VectorLength(tempvec);
1982         biggestorigin = 0;
1983         for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
1984         {
1985                 f = fabs(BigFloat(poses[i]));
1986                 biggestorigin = max(biggestorigin, f);
1987         }
1988         loadmodel->num_posescale = biggestorigin / 32767.0f;
1989         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
1990         for (i = 0;i < numposes;i++)
1991         {
1992                 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
1993                 for (j = 0;j < loadmodel->num_bones;j++)
1994                 {
1995                         float pose[12];
1996                         matrix4x4_t posematrix;
1997                         for (k = 0;k < 12;k++)
1998                                 pose[k] = BigFloat(frameposes[j*12+k]);
1999                         //if (j < loadmodel->num_bones)
2000                         //      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));
2001                         // scale child bones to match the root scale
2002                         if (loadmodel->data_bones[j].parent >= 0)
2003                         {
2004                                 pose[3] *= modelscale;
2005                                 pose[7] *= modelscale;
2006                                 pose[11] *= modelscale;
2007                         }
2008                         // normalize rotation matrix
2009                         VectorNormalize(pose + 0);
2010                         VectorNormalize(pose + 4);
2011                         VectorNormalize(pose + 8);
2012                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2013                         Matrix4x4_ToBonePose6s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses6s + 6*(i*loadmodel->num_bones+j));
2014                 }
2015         }
2016
2017         //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
2018         verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
2019         vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
2020         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2021         // (converting from weight-blending skeletal animation to
2022         //  deformation-based skeletal animation)
2023         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2024         for (i = 0;i < loadmodel->num_bones;i++)
2025         {
2026                 float m[12];
2027                 for (k = 0;k < 12;k++)
2028                         m[k] = BigFloat(poses[i*12+k]);
2029                 if (loadmodel->data_bones[i].parent >= 0)
2030                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2031                 else
2032                         for (k = 0;k < 12;k++)
2033                                 bonepose[12*i+k] = m[k];
2034         }
2035         for (j = 0;j < pheader->numverts;j++)
2036         {
2037                 // this format really should have had a per vertexweight weight value...
2038                 // but since it does not, the weighting is completely ignored and
2039                 // only one weight is allowed per vertex
2040                 int boneindex = BigLong(vertdata[j].bonenum);
2041                 const float *m = bonepose + 12 * boneindex;
2042                 float relativeorigin[3];
2043                 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
2044                 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
2045                 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
2046                 // transform the vertex bone weight into the base mesh
2047                 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
2048                 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
2049                 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
2050                 // store the weight as the primary weight on this vertex
2051                 loadmodel->surfmesh.blends[j] = boneindex;
2052         }
2053         Z_Free(bonepose);
2054         // normals and tangents are calculated after elements are loaded
2055
2056         //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
2057         outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
2058         intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
2059         for (i = 0;i < pheader->numverts;i++)
2060         {
2061                 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
2062                 // flip T coordinate for OpenGL
2063                 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
2064         }
2065
2066         //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
2067         //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
2068         //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
2069
2070         //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
2071         //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)
2072         // byteswap, validate, and swap winding order of tris
2073         count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
2074         if (pheader->lump_render.length != count)
2075                 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
2076         renderlist = (int *) (pheader->lump_render.start + pbase);
2077         renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
2078         meshtriangles = 0;
2079         for (i = 0;i < loadmodel->num_surfaces;i++)
2080         {
2081                 int firstvertex, lastvertex;
2082                 if (renderlist >= renderlistend)
2083                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2084                 count = BigLong(*renderlist);renderlist++;
2085                 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
2086                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
2087
2088                 loadmodel->sortedmodelsurfaces[i] = i;
2089                 surface = loadmodel->data_surfaces + i;
2090                 surface->texture = loadmodel->data_textures + i;
2091                 surface->num_firsttriangle = meshtriangles;
2092                 surface->num_triangles = count;
2093                 meshtriangles += surface->num_triangles;
2094
2095                 // load the elements
2096                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2097                 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2098                 {
2099                         outelements[j*3+2] = BigLong(renderlist[0]);
2100                         outelements[j*3+1] = BigLong(renderlist[1]);
2101                         outelements[j*3+0] = BigLong(renderlist[2]);
2102                 }
2103                 // validate the elements and find the used vertex range
2104                 firstvertex = meshvertices;
2105                 lastvertex = 0;
2106                 for (j = 0;j < surface->num_triangles * 3;j++)
2107                 {
2108                         if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2109                                 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2110                         firstvertex = min(firstvertex, outelements[j]);
2111                         lastvertex = max(lastvertex, outelements[j]);
2112                 }
2113                 surface->num_firstvertex = firstvertex;
2114                 surface->num_vertices = lastvertex + 1 - firstvertex;
2115
2116                 // since zym models do not have named sections, reuse their shader
2117                 // name as the section name
2118                 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2119                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2120         }
2121         Mod_FreeSkinFiles(skinfiles);
2122         Mem_Free(vertbonecounts);
2123         Mem_Free(verts);
2124         Mod_MakeSortedSurfaces(loadmodel);
2125
2126         // compute all the mesh information that was not loaded from the file
2127         if (loadmodel->surfmesh.data_element3s)
2128                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2129                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2130         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2131         Mod_BuildBaseBonePoses();
2132         Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, true);
2133         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);
2134         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2135
2136         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
2137
2138         if (!loadmodel->surfmesh.isanimated)
2139         {
2140                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2141                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2142                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2143                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2144                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2145         }
2146 }
2147
2148 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2149 {
2150         dpmheader_t *pheader;
2151         dpmframe_t *frames;
2152         dpmbone_t *bone;
2153         dpmmesh_t *dpmmesh;
2154         unsigned char *pbase;
2155         int i, j, k, meshvertices, meshtriangles;
2156         skinfile_t *skinfiles;
2157         unsigned char *data;
2158         float *bonepose;
2159         float biggestorigin, tempvec[3], modelscale;
2160         float f;
2161         float *poses;
2162
2163         pheader = (dpmheader_t *)buffer;
2164         pbase = (unsigned char *)buffer;
2165         if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2166                 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2167         if (BigLong(pheader->type) != 2)
2168                 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2169
2170         loadmodel->modeldatatypestring = "DPM";
2171
2172         loadmodel->type = mod_alias;
2173         loadmodel->synctype = ST_RAND;
2174
2175         // byteswap header
2176         pheader->type = BigLong(pheader->type);
2177         pheader->filesize = BigLong(pheader->filesize);
2178         pheader->mins[0] = BigFloat(pheader->mins[0]);
2179         pheader->mins[1] = BigFloat(pheader->mins[1]);
2180         pheader->mins[2] = BigFloat(pheader->mins[2]);
2181         pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2182         pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2183         pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2184         pheader->yawradius = BigFloat(pheader->yawradius);
2185         pheader->allradius = BigFloat(pheader->allradius);
2186         pheader->num_bones = BigLong(pheader->num_bones);
2187         pheader->num_meshs = BigLong(pheader->num_meshs);
2188         pheader->num_frames = BigLong(pheader->num_frames);
2189         pheader->ofs_bones = BigLong(pheader->ofs_bones);
2190         pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2191         pheader->ofs_frames = BigLong(pheader->ofs_frames);
2192
2193         if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2194         {
2195                 Con_Printf("%s has no geometry\n", loadmodel->name);
2196                 return;
2197         }
2198         if (pheader->num_frames < 1)
2199         {
2200                 Con_Printf("%s has no frames\n", loadmodel->name);
2201                 return;
2202         }
2203
2204         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2205         loadmodel->DrawSky = NULL;
2206         loadmodel->DrawAddWaterPlanes = NULL;
2207         loadmodel->Draw = R_Q1BSP_Draw;
2208         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2209         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2210         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2211         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2212         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2213         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2214         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2215         loadmodel->DrawLight = R_Q1BSP_DrawLight;
2216         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2217         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2218         loadmodel->PointSuperContents = NULL;
2219
2220         // model bbox
2221         for (i = 0;i < 3;i++)
2222         {
2223                 loadmodel->normalmins[i] = pheader->mins[i];
2224                 loadmodel->normalmaxs[i] = pheader->maxs[i];
2225                 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2226                 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2227                 loadmodel->rotatedmins[i] = -pheader->allradius;
2228                 loadmodel->rotatedmaxs[i] = pheader->allradius;
2229         }
2230         loadmodel->radius = pheader->allradius;
2231         loadmodel->radius2 = pheader->allradius * pheader->allradius;
2232
2233         // load external .skin files if present
2234         skinfiles = Mod_LoadSkinFiles();
2235         if (loadmodel->numskins < 1)
2236                 loadmodel->numskins = 1;
2237
2238         meshvertices = 0;
2239         meshtriangles = 0;
2240
2241         // gather combined statistics from the meshes
2242         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2243         for (i = 0;i < (int)pheader->num_meshs;i++)
2244         {
2245                 int numverts = BigLong(dpmmesh->num_verts);
2246                 meshvertices += numverts;
2247                 meshtriangles += BigLong(dpmmesh->num_tris);
2248                 dpmmesh++;
2249         }
2250
2251         loadmodel->numframes = pheader->num_frames;
2252         loadmodel->num_bones = pheader->num_bones;
2253         loadmodel->num_poses = loadmodel->numframes;
2254         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
2255         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2256         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2257         // do most allocations as one merged chunk
2258         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));
2259         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2260         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2261         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2262         loadmodel->surfmesh.num_vertices = meshvertices;
2263         loadmodel->surfmesh.num_triangles = meshtriangles;
2264         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2265         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2266         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2267         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2268         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2269         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2270         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2271         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2272         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2273         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2274         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2275         loadmodel->surfmesh.num_blends = 0;
2276         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2277         if (meshvertices <= 65536)
2278                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2279         loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
2280         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
2281
2282         for (i = 0;i < loadmodel->numskins;i++)
2283         {
2284                 loadmodel->skinscenes[i].firstframe = i;
2285                 loadmodel->skinscenes[i].framecount = 1;
2286                 loadmodel->skinscenes[i].loop = true;
2287                 loadmodel->skinscenes[i].framerate = 10;
2288         }
2289
2290         // load the bone info
2291         bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2292         for (i = 0;i < loadmodel->num_bones;i++)
2293         {
2294                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2295                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2296                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2297                 if (loadmodel->data_bones[i].parent >= i)
2298                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2299         }
2300
2301         // load the frames
2302         frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2303         // figure out scale of model from root bone, for compatibility with old dpmodel versions
2304         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2305         tempvec[0] = BigFloat(poses[0]);
2306         tempvec[1] = BigFloat(poses[1]);
2307         tempvec[2] = BigFloat(poses[2]);
2308         modelscale = VectorLength(tempvec);
2309         biggestorigin = 0;
2310         for (i = 0;i < loadmodel->numframes;i++)
2311         {
2312                 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2313                 loadmodel->animscenes[i].firstframe = i;
2314                 loadmodel->animscenes[i].framecount = 1;
2315                 loadmodel->animscenes[i].loop = true;
2316                 loadmodel->animscenes[i].framerate = 10;
2317                 // load the bone poses for this frame
2318                 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2319                 for (j = 0;j < loadmodel->num_bones*12;j++)
2320                 {
2321                         f = fabs(BigFloat(poses[j]));
2322                         biggestorigin = max(biggestorigin, f);
2323                 }
2324                 // stuff not processed here: mins, maxs, yawradius, allradius
2325         }
2326         loadmodel->num_posescale = biggestorigin / 32767.0f;
2327         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2328         for (i = 0;i < loadmodel->numframes;i++)
2329         {
2330                 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2331                 for (j = 0;j < loadmodel->num_bones;j++)
2332                 {
2333                         float pose[12];
2334                         matrix4x4_t posematrix;
2335                         for (k = 0;k < 12;k++)
2336                                 pose[k] = BigFloat(frameposes[j*12+k]);
2337                         // scale child bones to match the root scale
2338                         if (loadmodel->data_bones[j].parent >= 0)
2339                         {
2340                                 pose[3] *= modelscale;
2341                                 pose[7] *= modelscale;
2342                                 pose[11] *= modelscale;
2343                         }
2344                         // normalize rotation matrix
2345                         VectorNormalize(pose + 0);
2346                         VectorNormalize(pose + 4);
2347                         VectorNormalize(pose + 8);
2348                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2349                         Matrix4x4_ToBonePose6s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses6s + 6*(i*loadmodel->num_bones+j));
2350                 }
2351         }
2352
2353         // load the meshes now
2354         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2355         meshvertices = 0;
2356         meshtriangles = 0;
2357         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2358         // (converting from weight-blending skeletal animation to
2359         //  deformation-based skeletal animation)
2360         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2361         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2362         for (i = 0;i < loadmodel->num_bones;i++)
2363         {
2364                 float m[12];
2365                 for (k = 0;k < 12;k++)
2366                         m[k] = BigFloat(poses[i*12+k]);
2367                 if (loadmodel->data_bones[i].parent >= 0)
2368                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2369                 else
2370                         for (k = 0;k < 12;k++)
2371                                 bonepose[12*i+k] = m[k];
2372         }
2373         for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2374         {
2375                 const int *inelements;
2376                 int *outelements;
2377                 const float *intexcoord;
2378                 msurface_t *surface;
2379
2380                 loadmodel->sortedmodelsurfaces[i] = i;
2381                 surface = loadmodel->data_surfaces + i;
2382                 surface->texture = loadmodel->data_textures + i;
2383                 surface->num_firsttriangle = meshtriangles;
2384                 surface->num_triangles = BigLong(dpmmesh->num_tris);
2385                 surface->num_firstvertex = meshvertices;
2386                 surface->num_vertices = BigLong(dpmmesh->num_verts);
2387                 meshvertices += surface->num_vertices;
2388                 meshtriangles += surface->num_triangles;
2389
2390                 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2391                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2392                 for (j = 0;j < surface->num_triangles;j++)
2393                 {
2394                         // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2395                         outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
2396                         outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
2397                         outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
2398                         inelements += 3;
2399                         outelements += 3;
2400                 }
2401
2402                 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2403                 for (j = 0;j < surface->num_vertices*2;j++)
2404                         loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2405
2406                 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2407                 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2408                 {
2409                         int weightindex[4] = { 0, 0, 0, 0 };
2410                         float weightinfluence[4] = { 0, 0, 0, 0 };
2411                         int l;
2412                         int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2413                         data += sizeof(dpmvertex_t);
2414                         for (k = 0;k < numweights;k++)
2415                         {
2416                                 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2417                                 int boneindex = BigLong(vert->bonenum);
2418                                 const float *m = bonepose + 12 * boneindex;
2419                                 float influence = BigFloat(vert->influence);
2420                                 float relativeorigin[3], relativenormal[3];
2421                                 relativeorigin[0] = BigFloat(vert->origin[0]);
2422                                 relativeorigin[1] = BigFloat(vert->origin[1]);
2423                                 relativeorigin[2] = BigFloat(vert->origin[2]);
2424                                 relativenormal[0] = BigFloat(vert->normal[0]);
2425                                 relativenormal[1] = BigFloat(vert->normal[1]);
2426                                 relativenormal[2] = BigFloat(vert->normal[2]);
2427                                 // blend the vertex bone weights into the base mesh
2428                                 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2429                                 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2430                                 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2431                                 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2432                                 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2433                                 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2434                                 if (!k)
2435                                 {
2436                                         // store the first (and often only) weight
2437                                         weightinfluence[0] = influence;
2438                                         weightindex[0] = boneindex;
2439                                 }
2440                                 else
2441                                 {
2442                                         // sort the new weight into this vertex's weight table
2443                                         // (which only accepts up to 4 bones per vertex)
2444                                         for (l = 0;l < 4;l++)
2445                                         {
2446                                                 if (weightinfluence[l] < influence)
2447                                                 {
2448                                                         // move weaker influence weights out of the way first
2449                                                         int l2;
2450                                                         for (l2 = 3;l2 > l;l2--)
2451                                                         {
2452                                                                 weightinfluence[l2] = weightinfluence[l2-1];
2453                                                                 weightindex[l2] = weightindex[l2-1];
2454                                                         }
2455                                                         // store the new weight
2456                                                         weightinfluence[l] = influence;
2457                                                         weightindex[l] = boneindex;
2458                                                         break;
2459                                                 }
2460                                         }
2461                                 }
2462                                 data += sizeof(dpmbonevert_t);
2463                         }
2464                         loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
2465                 }
2466
2467                 // since dpm models do not have named sections, reuse their shader name as the section name
2468                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2469
2470                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2471         }
2472         if (loadmodel->surfmesh.num_blends < meshvertices)
2473                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
2474         Z_Free(bonepose);
2475         Mod_FreeSkinFiles(skinfiles);
2476         Mod_MakeSortedSurfaces(loadmodel);
2477
2478         // compute all the mesh information that was not loaded from the file
2479         if (loadmodel->surfmesh.data_element3s)
2480                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2481                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2482         Mod_BuildBaseBonePoses();
2483         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);
2484         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2485
2486         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
2487
2488         if (!loadmodel->surfmesh.isanimated)
2489         {
2490                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
2491                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
2492                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
2493                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
2494                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
2495         }
2496 }
2497
2498 // no idea why PSK/PSA files contain weird quaternions but they do...
2499 #define PSKQUATNEGATIONS
2500 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2501 {
2502         int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2503         int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2504         fs_offset_t filesize;
2505         pskpnts_t *pnts;
2506         pskvtxw_t *vtxw;
2507         pskface_t *faces;
2508         pskmatt_t *matts;
2509         pskboneinfo_t *bones;
2510         pskrawweights_t *rawweights;
2511         //pskboneinfo_t *animbones;
2512         pskaniminfo_t *anims;
2513         pskanimkeys_t *animkeys;
2514         void *animfilebuffer, *animbuffer, *animbufferend;
2515         unsigned char *data;
2516         pskchunk_t *pchunk;
2517         skinfile_t *skinfiles;
2518         char animname[MAX_QPATH];
2519         size_t size;
2520         float biggestorigin;
2521
2522         pchunk = (pskchunk_t *)buffer;
2523         if (strcmp(pchunk->id, "ACTRHEAD"))
2524                 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2525
2526         loadmodel->modeldatatypestring = "PSK";
2527
2528         loadmodel->type = mod_alias;
2529         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2530         loadmodel->DrawSky = NULL;
2531         loadmodel->DrawAddWaterPlanes = NULL;
2532         loadmodel->Draw = R_Q1BSP_Draw;
2533         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2534         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2535         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2536         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2537         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2538         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2539         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2540         loadmodel->DrawLight = R_Q1BSP_DrawLight;
2541         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2542         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2543         loadmodel->PointSuperContents = NULL;
2544         loadmodel->synctype = ST_RAND;
2545
2546         FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2547         strlcat(animname, ".psa", sizeof(animname));
2548         animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2549         animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2550         if (animbuffer == NULL)
2551                 Host_Error("%s: can't find .psa file (%s)", loadmodel->name, animname);
2552
2553         numpnts = 0;
2554         pnts = NULL;
2555         numvtxw = 0;
2556         vtxw = NULL;
2557         numfaces = 0;
2558         faces = NULL;
2559         nummatts = 0;
2560         matts = NULL;
2561         numbones = 0;
2562         bones = NULL;
2563         numrawweights = 0;
2564         rawweights = NULL;
2565         numanims = 0;
2566         anims = NULL;
2567         numanimkeys = 0;
2568         animkeys = NULL;
2569
2570         while (buffer < bufferend)
2571         {
2572                 pchunk = (pskchunk_t *)buffer;
2573                 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2574                 version = LittleLong(pchunk->version);
2575                 recordsize = LittleLong(pchunk->recordsize);
2576                 numrecords = LittleLong(pchunk->numrecords);
2577                 if (developer_extra.integer)
2578                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2579                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2580                         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);
2581                 if (!strcmp(pchunk->id, "ACTRHEAD"))
2582                 {
2583                         // nothing to do
2584                 }
2585                 else if (!strcmp(pchunk->id, "PNTS0000"))
2586                 {
2587                         pskpnts_t *p;
2588                         if (recordsize != sizeof(*p))
2589                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2590                         // byteswap in place and keep the pointer
2591                         numpnts = numrecords;
2592                         pnts = (pskpnts_t *)buffer;
2593                         for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2594                         {
2595                                 p->origin[0] = LittleFloat(p->origin[0]);
2596                                 p->origin[1] = LittleFloat(p->origin[1]);
2597                                 p->origin[2] = LittleFloat(p->origin[2]);
2598                         }
2599                         buffer = p;
2600                 }
2601                 else if (!strcmp(pchunk->id, "VTXW0000"))
2602                 {
2603                         pskvtxw_t *p;
2604                         if (recordsize != sizeof(*p))
2605                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2606                         // byteswap in place and keep the pointer
2607                         numvtxw = numrecords;
2608                         vtxw = (pskvtxw_t *)buffer;
2609                         for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2610                         {
2611                                 p->pntsindex = LittleShort(p->pntsindex);
2612                                 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2613                                 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2614                                 if (p->pntsindex >= numpnts)
2615                                 {
2616                                         Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2617                                         p->pntsindex = 0;
2618                                 }
2619                         }
2620                         buffer = p;
2621                 }
2622                 else if (!strcmp(pchunk->id, "FACE0000"))
2623                 {
2624                         pskface_t *p;
2625                         if (recordsize != sizeof(*p))
2626                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2627                         // byteswap in place and keep the pointer
2628                         numfaces = numrecords;
2629                         faces = (pskface_t *)buffer;
2630                         for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2631                         {
2632                                 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2633                                 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2634                                 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2635                                 p->group = LittleLong(p->group);
2636                                 if (p->vtxwindex[0] >= numvtxw)
2637                                 {
2638                                         Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2639                                         p->vtxwindex[0] = 0;
2640                                 }
2641                                 if (p->vtxwindex[1] >= numvtxw)
2642                                 {
2643                                         Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2644                                         p->vtxwindex[1] = 0;
2645                                 }
2646                                 if (p->vtxwindex[2] >= numvtxw)
2647                                 {
2648                                         Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2649                                         p->vtxwindex[2] = 0;
2650                                 }
2651                         }
2652                         buffer = p;
2653                 }
2654                 else if (!strcmp(pchunk->id, "MATT0000"))
2655                 {
2656                         pskmatt_t *p;
2657                         if (recordsize != sizeof(*p))
2658                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2659                         // byteswap in place and keep the pointer
2660                         nummatts = numrecords;
2661                         matts = (pskmatt_t *)buffer;
2662                         for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2663                         {
2664                                 // nothing to do
2665                         }
2666                         buffer = p;
2667                 }
2668                 else if (!strcmp(pchunk->id, "REFSKELT"))
2669                 {
2670                         pskboneinfo_t *p;
2671                         if (recordsize != sizeof(*p))
2672                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2673                         // byteswap in place and keep the pointer
2674                         numbones = numrecords;
2675                         bones = (pskboneinfo_t *)buffer;
2676                         for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2677                         {
2678                                 p->numchildren = LittleLong(p->numchildren);
2679                                 p->parent = LittleLong(p->parent);
2680                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2681                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2682                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2683                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2684                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2685                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2686                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2687                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2688                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2689                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2690                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2691 #ifdef PSKQUATNEGATIONS
2692                                 if (index)
2693                                 {
2694                                         p->basepose.quat[0] *= -1;
2695                                         p->basepose.quat[1] *= -1;
2696                                         p->basepose.quat[2] *= -1;
2697                                 }
2698                                 else
2699                                 {
2700                                         p->basepose.quat[0] *=  1;
2701                                         p->basepose.quat[1] *= -1;
2702                                         p->basepose.quat[2] *=  1;
2703                                 }
2704 #endif
2705                                 if (p->parent < 0 || p->parent >= numbones)
2706                                 {
2707                                         Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2708                                         p->parent = 0;
2709                                 }
2710                         }
2711                         buffer = p;
2712                 }
2713                 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2714                 {
2715                         pskrawweights_t *p;
2716                         if (recordsize != sizeof(*p))
2717                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2718                         // byteswap in place and keep the pointer
2719                         numrawweights = numrecords;
2720                         rawweights = (pskrawweights_t *)buffer;
2721                         for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2722                         {
2723                                 p->weight = LittleFloat(p->weight);
2724                                 p->pntsindex = LittleLong(p->pntsindex);
2725                                 p->boneindex = LittleLong(p->boneindex);
2726                                 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2727                                 {
2728                                         Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2729                                         p->pntsindex = 0;
2730                                 }
2731                                 if (p->boneindex < 0 || p->boneindex >= numbones)
2732                                 {
2733                                         Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2734                                         p->boneindex = 0;
2735                                 }
2736                         }
2737                         buffer = p;
2738                 }
2739         }
2740
2741         while (animbuffer < animbufferend)
2742         {
2743                 pchunk = (pskchunk_t *)animbuffer;
2744                 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2745                 version = LittleLong(pchunk->version);
2746                 recordsize = LittleLong(pchunk->recordsize);
2747                 numrecords = LittleLong(pchunk->numrecords);
2748                 if (developer_extra.integer)
2749                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2750                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2751                         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);
2752                 if (!strcmp(pchunk->id, "ANIMHEAD"))
2753                 {
2754                         // nothing to do
2755                 }
2756                 else if (!strcmp(pchunk->id, "BONENAMES"))
2757                 {
2758                         pskboneinfo_t *p;
2759                         if (recordsize != sizeof(*p))
2760                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2761                         // byteswap in place and keep the pointer
2762                         numanimbones = numrecords;
2763                         //animbones = (pskboneinfo_t *)animbuffer;
2764                         // NOTE: supposedly psa does not need to match the psk model, the
2765                         // bones missing from the psa would simply use their base
2766                         // positions from the psk, but this is hard for me to implement
2767                         // and people can easily make animations that match.
2768                         if (numanimbones != numbones)
2769                                 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2770                         for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2771                         {
2772                                 p->numchildren = LittleLong(p->numchildren);
2773                                 p->parent = LittleLong(p->parent);
2774                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2775                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2776                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2777                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2778                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2779                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2780                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2781                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2782                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2783                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2784                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2785 #ifdef PSKQUATNEGATIONS
2786                                 if (index)
2787                                 {
2788                                         p->basepose.quat[0] *= -1;
2789                                         p->basepose.quat[1] *= -1;
2790                                         p->basepose.quat[2] *= -1;
2791                                 }
2792                                 else
2793                                 {
2794                                         p->basepose.quat[0] *=  1;
2795                                         p->basepose.quat[1] *= -1;
2796                                         p->basepose.quat[2] *=  1;
2797                                 }
2798 #endif
2799                                 if (p->parent < 0 || p->parent >= numanimbones)
2800                                 {
2801                                         Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2802                                         p->parent = 0;
2803                                 }
2804                                 // check that bones are the same as in the base
2805                                 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2806                                         Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2807                         }
2808                         animbuffer = p;
2809                 }
2810                 else if (!strcmp(pchunk->id, "ANIMINFO"))
2811                 {
2812                         pskaniminfo_t *p;
2813                         if (recordsize != sizeof(*p))
2814                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2815                         // byteswap in place and keep the pointer
2816                         numanims = numrecords;
2817                         anims = (pskaniminfo_t *)animbuffer;
2818                         for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2819                         {
2820                                 p->numbones = LittleLong(p->numbones);
2821                                 p->playtime = LittleFloat(p->playtime);
2822                                 p->fps = LittleFloat(p->fps);
2823                                 p->firstframe = LittleLong(p->firstframe);
2824                                 p->numframes = LittleLong(p->numframes);
2825                                 if (p->numbones != numbones)
2826                                         Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2827                         }
2828                         animbuffer = p;
2829                 }
2830                 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2831                 {
2832                         pskanimkeys_t *p;
2833                         if (recordsize != sizeof(*p))
2834                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2835                         numanimkeys = numrecords;
2836                         animkeys = (pskanimkeys_t *)animbuffer;
2837                         for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2838                         {
2839                                 p->origin[0] = LittleFloat(p->origin[0]);
2840                                 p->origin[1] = LittleFloat(p->origin[1]);
2841                                 p->origin[2] = LittleFloat(p->origin[2]);
2842                                 p->quat[0] = LittleFloat(p->quat[0]);
2843                                 p->quat[1] = LittleFloat(p->quat[1]);
2844                                 p->quat[2] = LittleFloat(p->quat[2]);
2845                                 p->quat[3] = LittleFloat(p->quat[3]);
2846                                 p->frametime = LittleFloat(p->frametime);
2847 #ifdef PSKQUATNEGATIONS
2848                                 if (index % numbones)
2849                                 {
2850                                         p->quat[0] *= -1;
2851                                         p->quat[1] *= -1;
2852                                         p->quat[2] *= -1;
2853                                 }
2854                                 else
2855                                 {
2856                                         p->quat[0] *=  1;
2857                                         p->quat[1] *= -1;
2858                                         p->quat[2] *=  1;
2859                                 }
2860 #endif
2861                         }
2862                         animbuffer = p;
2863                         // TODO: allocate bonepose stuff
2864                 }
2865                 else
2866                         Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2867         }
2868
2869         if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights || !numanims || !anims || !numanimkeys || !animkeys)
2870                 Host_Error("%s: missing required chunks", loadmodel->name);
2871
2872         loadmodel->numframes = 0;
2873         for (index = 0;index < numanims;index++)
2874                 loadmodel->numframes += anims[index].numframes;
2875
2876         if (numanimkeys != numbones * loadmodel->numframes)
2877                 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2878
2879         meshvertices = numvtxw;
2880         meshtriangles = numfaces;
2881
2882         // load external .skin files if present
2883         skinfiles = Mod_LoadSkinFiles();
2884         if (loadmodel->numskins < 1)
2885                 loadmodel->numskins = 1;
2886         loadmodel->num_bones = numbones;
2887         loadmodel->num_poses = loadmodel->numframes;
2888         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2889         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2890         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2891         loadmodel->surfmesh.num_vertices = meshvertices;
2892         loadmodel->surfmesh.num_triangles = meshtriangles;
2893         // do most allocations as one merged chunk
2894         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);
2895         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2896         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2897         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2898         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2899         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2900         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2901         loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2902         loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2903         loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2904         loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2905         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2906         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2907         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2908         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2909         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2910         loadmodel->surfmesh.num_blends = 0;
2911         loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
2912         if (loadmodel->surfmesh.num_vertices <= 65536)
2913                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2914         loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
2915         loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
2916
2917         for (i = 0;i < loadmodel->numskins;i++)
2918         {
2919                 loadmodel->skinscenes[i].firstframe = i;
2920                 loadmodel->skinscenes[i].framecount = 1;
2921                 loadmodel->skinscenes[i].loop = true;
2922                 loadmodel->skinscenes[i].framerate = 10;
2923         }
2924
2925         // create surfaces
2926         for (index = 0, i = 0;index < nummatts;index++)
2927         {
2928                 // since psk models do not have named sections, reuse their shader name as the section name
2929                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2930                 loadmodel->sortedmodelsurfaces[index] = index;
2931                 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2932                 loadmodel->data_surfaces[index].num_firstvertex = 0;
2933                 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2934         }
2935
2936         // copy over the vertex locations and texcoords
2937         for (index = 0;index < numvtxw;index++)
2938         {
2939                 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
2940                 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
2941                 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
2942                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
2943                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
2944         }
2945
2946         // loading the faces is complicated because we need to sort them into surfaces by mattindex
2947         for (index = 0;index < numfaces;index++)
2948                 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
2949         for (index = 0, i = 0;index < nummatts;index++)
2950         {
2951                 loadmodel->data_surfaces[index].num_firsttriangle = i;
2952                 i += loadmodel->data_surfaces[index].num_triangles;
2953                 loadmodel->data_surfaces[index].num_triangles = 0;
2954         }
2955         for (index = 0;index < numfaces;index++)
2956         {
2957                 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
2958                 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
2959                 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
2960                 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
2961         }
2962
2963         // copy over the bones
2964         for (index = 0;index < numbones;index++)
2965         {
2966                 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
2967                 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
2968                 if (loadmodel->data_bones[index].parent >= index)
2969                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
2970         }
2971
2972         // sort the psk point weights into the vertex weight tables
2973         // (which only accept up to 4 bones per vertex)
2974         for (index = 0;index < numvtxw;index++)
2975         {
2976                 int weightindex[4] = { 0, 0, 0, 0 };
2977                 float weightinfluence[4] = { 0, 0, 0, 0 };
2978                 int l;
2979                 for (j = 0;j < numrawweights;j++)
2980                 {
2981                         if (rawweights[j].pntsindex == vtxw[index].pntsindex)
2982                         {
2983                                 int boneindex = rawweights[j].boneindex;
2984                                 float influence = rawweights[j].weight;
2985                                 for (l = 0;l < 4;l++)
2986                                 {
2987                                         if (weightinfluence[l] < influence)
2988                                         {
2989                                                 // move lower influence weights out of the way first
2990                                                 int l2;
2991                                                 for (l2 = 3;l2 > l;l2--)
2992                                                 {
2993                                                         weightinfluence[l2] = weightinfluence[l2-1];
2994                                                         weightindex[l2] = weightindex[l2-1];
2995                                                 }
2996                                                 // store the new weight
2997                                                 weightinfluence[l] = influence;
2998                                                 weightindex[l] = boneindex;
2999                                                 break;
3000                                         }
3001                                 }
3002                         }
3003                 }
3004                 loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence);
3005         }
3006         if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices)
3007                 loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t));
3008
3009         // set up the animscenes based on the anims
3010         for (index = 0, i = 0;index < numanims;index++)
3011         {
3012                 for (j = 0;j < anims[index].numframes;j++, i++)
3013                 {
3014                         dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
3015                         loadmodel->animscenes[i].firstframe = i;
3016                         loadmodel->animscenes[i].framecount = 1;
3017                         loadmodel->animscenes[i].loop = true;
3018                         loadmodel->animscenes[i].framerate = anims[index].fps;
3019                 }
3020         }
3021
3022         // calculate the scaling value for bone origins so they can be compressed to short
3023         biggestorigin = 0;
3024         for (index = 0;index < numanimkeys;index++)
3025         {
3026                 pskanimkeys_t *k = animkeys + index;
3027                 biggestorigin = max(biggestorigin, fabs(k->origin[0]));
3028                 biggestorigin = max(biggestorigin, fabs(k->origin[1]));
3029                 biggestorigin = max(biggestorigin, fabs(k->origin[2]));
3030         }
3031         loadmodel->num_posescale = biggestorigin / 32767.0f;
3032         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
3033
3034         // load the poses from the animkeys
3035         for (index = 0;index < numanimkeys;index++)
3036         {
3037                 pskanimkeys_t *k = animkeys + index;
3038                 float quat[4];
3039                 Vector4Copy(k->quat, quat);
3040                 if (quat[3] > 0)
3041                         Vector4Negate(quat, quat);
3042                 Vector4Normalize2(quat, quat);
3043                 // compress poses to the short[6] format for longterm storage
3044                 loadmodel->data_poses6s[index*6+0] = k->origin[0] * loadmodel->num_poseinvscale;
3045                 loadmodel->data_poses6s[index*6+1] = k->origin[1] * loadmodel->num_poseinvscale;
3046                 loadmodel->data_poses6s[index*6+2] = k->origin[2] * loadmodel->num_poseinvscale;
3047                 loadmodel->data_poses6s[index*6+3] = quat[0] * 32767.0f;
3048                 loadmodel->data_poses6s[index*6+4] = quat[1] * 32767.0f;
3049                 loadmodel->data_poses6s[index*6+5] = quat[2] * 32767.0f;
3050         }
3051         Mod_FreeSkinFiles(skinfiles);
3052         Mem_Free(animfilebuffer);
3053         Mod_MakeSortedSurfaces(loadmodel);
3054
3055         // compute all the mesh information that was not loaded from the file
3056         // TODO: honor smoothing groups somehow?
3057         if (loadmodel->surfmesh.data_element3s)
3058                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3059                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3060         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
3061         Mod_BuildBaseBonePoses();
3062         Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, true);
3063         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);
3064         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
3065         Mod_Alias_CalculateBoundingBox();
3066
3067         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
3068
3069         if (!loadmodel->surfmesh.isanimated)
3070         {
3071                 Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
3072                 loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
3073                 loadmodel->TraceLine = Mod_CollisionBIH_TraceLine;
3074                 loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh;
3075                 loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh;
3076         }
3077 }
3078
3079 void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
3080 {
3081         unsigned char *data;
3082         const char *text;
3083         unsigned char *pbase, *pend;
3084         iqmheader_t *header;
3085         skinfile_t *skinfiles;
3086         int i, j, k, meshvertices, meshtriangles;
3087         float *vposition = NULL, *vtexcoord = NULL, *vnormal = NULL, *vtangent = NULL;
3088         unsigned char *vblendindexes = NULL, *vblendweights = NULL;
3089         iqmjoint_t *joint;
3090         iqmanim_t *anim;
3091         iqmpose_t *pose;
3092         iqmmesh_t *mesh;
3093         iqmbounds_t *bounds;
3094         iqmvertexarray_t *va;
3095         unsigned short *framedata;
3096         float biggestorigin;
3097         const int *inelements;
3098         int *outelements;
3099         float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector;
3100
3101         pbase = (unsigned char *)buffer;
3102         pend = (unsigned char *)bufferend;
3103         header = (iqmheader_t *)buffer;
3104         if (memcmp(header->id, "INTERQUAKEMODEL", 16))
3105                 Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name);
3106         if (LittleLong(header->version) != 1)
3107                 Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 models are currently supported (name = %s)", loadmodel->name);
3108
3109         loadmodel->modeldatatypestring = "IQM";
3110
3111         loadmodel->type = mod_alias;
3112         loadmodel->synctype = ST_RAND;
3113
3114         // byteswap header
3115         header->version = LittleLong(header->version);
3116         header->filesize = LittleLong(header->filesize);
3117         header->flags = LittleLong(header->flags);
3118         header->num_text = LittleLong(header->num_text);
3119         header->ofs_text = LittleLong(header->ofs_text);
3120         header->num_meshes = LittleLong(header->num_meshes);
3121         header->ofs_meshes = LittleLong(header->ofs_meshes);
3122         header->num_vertexarrays = LittleLong(header->num_vertexarrays);
3123         header->num_vertexes = LittleLong(header->num_vertexes);
3124         header->ofs_vertexarrays = LittleLong(header->ofs_vertexarrays);
3125         header->num_triangles = LittleLong(header->num_triangles);
3126         header->ofs_triangles = LittleLong(header->ofs_triangles);
3127         header->ofs_neighbors = LittleLong(header->ofs_neighbors);
3128         header->num_joints = LittleLong(header->num_joints);
3129         header->ofs_joints = LittleLong(header->ofs_joints);
3130         header->num_poses = LittleLong(header->num_poses);
3131         header->ofs_poses = LittleLong(header->ofs_poses);
3132         header->num_anims = LittleLong(header->num_anims);
3133         header->ofs_anims = LittleLong(header->ofs_anims);
3134         header->num_frames = LittleLong(header->num_frames);
3135         header->num_framechannels = LittleLong(header->num_framechannels);
3136         header->ofs_frames = LittleLong(header->ofs_frames);
3137         header->ofs_bounds = LittleLong(header->ofs_bounds);
3138         header->num_comment = LittleLong(header->num_comment);
3139         header->ofs_comment = LittleLong(header->ofs_comment);
3140         header->num_extensions = LittleLong(header->num_extensions);
3141         header->ofs_extensions = LittleLong(header->ofs_extensions);
3142
3143         if (header->num_triangles < 1 || header->num_vertexes < 3 || header->num_vertexarrays < 1 || header->num_meshes < 1)
3144         {
3145                 Con_Printf("%s has no geometry\n", loadmodel->name);
3146                 return;
3147         }
3148         if (header->num_frames < 1 || header->num_anims < 1)
3149         {
3150                 Con_Printf("%s has no animations\n", loadmodel->name);
3151                 return;
3152         }
3153
3154         if (pbase + header->ofs_text + header->num_text > pend ||
3155                 pbase + header->ofs_meshes + header->num_meshes*sizeof(iqmmesh_t) > pend ||
3156                 pbase + header->ofs_vertexarrays + header->num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
3157                 pbase + header->ofs_triangles + header->num_triangles*sizeof(int[3]) > pend ||
3158                 (header->ofs_neighbors && pbase + header->ofs_neighbors + header->num_triangles*sizeof(int[3]) > pend) ||
3159                 pbase + header->ofs_joints + header->num_joints*sizeof(iqmjoint_t) > pend ||
3160                 pbase + header->ofs_poses + header->num_poses*sizeof(iqmpose_t) > pend ||
3161                 pbase + header->ofs_anims + header->num_anims*sizeof(iqmanim_t) > pend ||
3162                 pbase + header->ofs_frames + header->num_frames*header->num_framechannels*sizeof(unsigned short) > pend ||
3163                 (header->ofs_bounds && pbase + header->ofs_bounds + header->num_frames*sizeof(iqmbounds_t) > pend) ||
3164                 pbase + header->ofs_comment + header->num_comment > pend)
3165         {
3166                 Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
3167                 return;
3168         }
3169
3170         va = (iqmvertexarray_t *)(pbase + header->ofs_vertexarrays);
3171         for (i = 0;i < (int)header->num_vertexarrays;i++)
3172         {
3173                 size_t vsize;
3174                 va[i].type = LittleLong(va[i].type);
3175                 va[i].flags = LittleLong(va[i].flags);
3176                 va[i].format = LittleLong(va[i].format);
3177                 va[i].size = LittleLong(va[i].size);
3178                 va[i].offset = LittleLong(va[i].offset);
3179                 vsize = header->num_vertexes*va[i].size;
3180                 switch (va[i].format)
3181                 { 
3182                 case IQM_FLOAT: vsize *= sizeof(float); break;
3183                 case IQM_UBYTE: vsize *= sizeof(unsigned char); break;
3184                 default: continue;
3185                 }
3186                 if (pbase + va[i].offset + vsize > pend)
3187                   continue;
3188                 switch (va[i].type)
3189                 {
3190                 case IQM_POSITION:
3191                         if (va[i].format == IQM_FLOAT && va[i].size == 3)
3192                                 vposition = (float *)(pbase + va[i].offset);
3193                         break;
3194                 case IQM_TEXCOORD:
3195                         if (va[i].format == IQM_FLOAT && va[i].size == 2)
3196                                 vtexcoord = (float *)(pbase + va[i].offset);
3197                         break;
3198                 case IQM_NORMAL:
3199                         if (va[i].format == IQM_FLOAT && va[i].size == 3)
3200                                 vnormal = (float *)(pbase + va[i].offset);
3201                         break;
3202                 case IQM_TANGENT:
3203                         if (va[i].format == IQM_FLOAT && va[i].size == 4)
3204                                 vtangent = (float *)(pbase + va[i].offset);
3205                         break;
3206                 case IQM_BLENDINDEXES:
3207                         if (va[i].format == IQM_UBYTE && va[i].size == 4)
3208                                 vblendindexes = (unsigned char *)(pbase + va[i].offset);
3209                         break;
3210                 case IQM_BLENDWEIGHTS:
3211                         if (va[i].format == IQM_UBYTE && va[i].size == 4)
3212                                 vblendweights = (unsigned char *)(pbase + va[i].offset);
3213                         break;
3214                 }
3215         }
3216         if (!vposition || !vtexcoord || !vblendindexes || !vblendweights)
3217         {
3218                 Con_Printf("%s is missing vertex array data\n", loadmodel->name);
3219                 return;
3220         }
3221
3222         text = header->num_text && header->ofs_text ? (const char *)(pbase + header->ofs_text) : "";
3223
3224         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
3225         loadmodel->DrawSky = NULL;
3226         loadmodel->DrawAddWaterPlanes = NULL;
3227         loadmodel->Draw = R_Q1BSP_Draw;
3228         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
3229         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
3230         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
3231         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
3232         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
3233         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
3234         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
3235         loadmodel->DrawLight = R_Q1BSP_DrawLight;
3236         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
3237         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
3238         loadmodel->PointSuperContents = NULL;
3239
3240         // load external .skin files if present
3241         skinfiles = Mod_LoadSkinFiles();
3242         if (loadmodel->numskins < 1)
3243                 loadmodel->numskins = 1;
3244
3245         loadmodel->numframes = header->num_anims;
3246         loadmodel->num_bones = header->num_joints;
3247         loadmodel->num_poses = header->num_frames;
3248         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header->num_meshes;
3249         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
3250         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
3251
3252         meshvertices = header->num_vertexes;
3253         meshtriangles = header->num_triangles;
3254
3255         // do most allocations as one merged chunk
3256         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));
3257         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
3258         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
3259         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
3260         loadmodel->surfmesh.num_vertices = meshvertices;
3261         loadmodel->surfmesh.num_triangles = meshtriangles;
3262         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3263         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
3264         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
3265         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3266         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
3267         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
3268         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
3269         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
3270         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
3271         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);