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