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