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