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