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