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