]> icculus.org git repositories - divverent/darkplaces.git/blob - model_alias.c
added mod_q1bsp_polygoncollisions cvar (off by default, because it
[divverent/darkplaces.git] / model_alias.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21 #include "quakedef.h"
22 #include "image.h"
23 #include "r_shadow.h"
24
25 cvar_t r_skeletal_debugbone = {0, "r_skeletal_debugbone", "-1", "development cvar for testing skeletal model code"};
26 cvar_t r_skeletal_debugbonecomponent = {0, "r_skeletal_debugbonecomponent", "3", "development cvar for testing skeletal model code"};
27 cvar_t r_skeletal_debugbonevalue = {0, "r_skeletal_debugbonevalue", "100", "development cvar for testing skeletal model code"};
28 cvar_t r_skeletal_debugtranslatex = {0, "r_skeletal_debugtranslatex", "1", "development cvar for testing skeletal model code"};
29 cvar_t r_skeletal_debugtranslatey = {0, "r_skeletal_debugtranslatey", "1", "development cvar for testing skeletal model code"};
30 cvar_t r_skeletal_debugtranslatez = {0, "r_skeletal_debugtranslatez", "1", "development cvar for testing skeletal model code"};
31 cvar_t mod_alias_supporttagscale = {0, "mod_alias_supporttagscale", "1", "support scaling factors in bone/tag attachment matrices as supported by MD3"};
32
33 float mod_md3_sin[320];
34
35 void Mod_AliasInit (void)
36 {
37         int i;
38         Cvar_RegisterVariable(&r_skeletal_debugbone);
39         Cvar_RegisterVariable(&r_skeletal_debugbonecomponent);
40         Cvar_RegisterVariable(&r_skeletal_debugbonevalue);
41         Cvar_RegisterVariable(&r_skeletal_debugtranslatex);
42         Cvar_RegisterVariable(&r_skeletal_debugtranslatey);
43         Cvar_RegisterVariable(&r_skeletal_debugtranslatez);
44         Cvar_RegisterVariable(&mod_alias_supporttagscale);
45         for (i = 0;i < 320;i++)
46                 mod_md3_sin[i] = sin(i * M_PI * 2.0f / 256.0);
47 }
48
49 int Mod_Skeletal_AddBlend(dp_model_t *model, const int *newindex, const float *newinfluence)
50 {
51         int i, total;
52         float scale;
53         blendweights_t *weights;
54         blendweights_t newweights;
55         if(!newinfluence[1])
56                 return newindex[0];
57         scale = 0;
58         for (i = 0;i < 4;i++)
59                 scale += newinfluence[i];
60         scale = 255.0f / scale;
61         total = 0;
62         for (i = 0;i < 4;i++)
63         {
64                 newweights.index[i] = newindex[i];
65                 newweights.influence[i] = (unsigned char)(newinfluence[i] * scale);
66                 total += newweights.influence[i];
67         }       
68         while (total > 255)
69         {
70                 for (i = 0;i < 4;i++)
71                 {
72                         if(newweights.influence[i] > 0 && total > 255) 
73                         { 
74                                 newweights.influence[i]--;
75                                 total--; 
76                         }
77                 }
78         }
79         while (total < 255)
80         {
81                 for (i = 0; i < 4;i++)
82                 {
83                         if(newweights.influence[i] < 255 && total < 255) 
84                         { 
85                                 newweights.influence[i]++; 
86                                 total++; 
87                         }
88                 }
89         }
90         weights = model->surfmesh.data_blendweights;
91         for (i = 0;i < model->surfmesh.num_blends;i++, weights++)
92         {
93                 if (!memcmp(weights, &newweights, sizeof(blendweights_t)))
94                         return model->num_bones + i;
95         }
96         model->surfmesh.num_blends++;
97         memcpy(weights, &newweights, sizeof(blendweights_t));
98         return model->num_bones + i;
99
100                  
101 static int maxbonepose = 0;
102 static float (*bonepose)[12] = NULL;
103
104 void Mod_Skeletal_FreeBuffers(void)
105 {
106         if(bonepose)
107                 Mem_Free(bonepose);
108         maxbonepose = 0;
109         bonepose = NULL;
110 }
111
112 #if defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1400)
113 #define RESTRICT __restrict
114 #else
115 #define RESTRICT
116 #endif
117
118 void Mod_Skeletal_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
119 {
120         // vertex weighted skeletal
121         int i, k;
122         int blends;
123         float m[12];
124         float (*boneposerelative)[12];
125         const blendweights_t * RESTRICT weights;
126
127         if (maxbonepose < model->num_bones*2 + model->surfmesh.num_blends)
128         {
129                 if (bonepose)
130                         Mem_Free(bonepose);
131                 maxbonepose = model->num_bones*2 + model->surfmesh.num_blends;
132                 bonepose = (float (*)[12])Mem_Alloc(r_main_mempool, maxbonepose * sizeof(float[12]));
133         }
134
135         boneposerelative = bonepose + model->num_bones;
136
137         if (skeleton && !skeleton->relativetransforms)
138                 skeleton = NULL;
139
140         // interpolate matrices
141         if (skeleton)
142         {
143                 for (i = 0;i < model->num_bones;i++)
144                 {
145                         Matrix4x4_ToArray12FloatD3D(&skeleton->relativetransforms[i], m);
146                         if (model->data_bones[i].parent >= 0)
147                                 R_ConcatTransforms(bonepose[model->data_bones[i].parent], m, bonepose[i]);
148                         else
149                                 memcpy(bonepose[i], m, sizeof(m));
150
151                         // create a relative deformation matrix to describe displacement
152                         // from the base mesh, which is used by the actual weighting
153                         R_ConcatTransforms(bonepose[i], model->data_baseboneposeinverse + i * 12, boneposerelative[i]);
154                 }
155         }
156         else
157         {
158                 float originscale = model->num_posescale;
159                 float x,y,z,w,lerp;
160                 const short * RESTRICT pose6s;
161                 for (i = 0;i < model->num_bones;i++)
162                 {
163                         memset(m, 0, sizeof(m));
164                         for (blends = 0;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
165                         {
166                                 pose6s = model->data_poses6s + 6 * (frameblend[blends].subframe * model->num_bones + i);
167                                 lerp = frameblend[blends].lerp;
168                                 x = pose6s[3] * (1.0f / 32767.0f);
169                                 y = pose6s[4] * (1.0f / 32767.0f);
170                                 z = pose6s[5] * (1.0f / 32767.0f);
171                                 w = 1.0f - (x*x+y*y+z*z);
172                                 w = w > 0.0f ? -sqrt(w) : 0.0f;
173                                 m[ 0] += (1-2*(y*y+z*z)) * lerp;
174                                 m[ 1] += (  2*(x*y-z*w)) * lerp;
175                                 m[ 2] += (  2*(x*z+y*w)) * lerp;
176                                 m[ 3] += (pose6s[0] * originscale) * lerp;
177                                 m[ 4] += (  2*(x*y+z*w)) * lerp;
178                                 m[ 5] += (1-2*(x*x+z*z)) * lerp;
179                                 m[ 6] += (  2*(y*z-x*w)) * lerp;
180                                 m[ 7] += (pose6s[1] * originscale) * lerp;
181                                 m[ 8] += (  2*(x*z-y*w)) * lerp;
182                                 m[ 9] += (  2*(y*z+x*w)) * lerp;
183                                 m[10] += (1-2*(x*x+y*y)) * lerp;
184                                 m[11] += (pose6s[2] * originscale) * lerp;
185                         }
186                         VectorNormalize(m       );
187                         VectorNormalize(m + 4);
188                         VectorNormalize(m + 8);
189                         if (i == r_skeletal_debugbone.integer)
190                                 m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value;
191                         m[3] *= r_skeletal_debugtranslatex.value;
192                         m[7] *= r_skeletal_debugtranslatey.value;
193                         m[11] *= r_skeletal_debugtranslatez.value;
194                         if (model->data_bones[i].parent >= 0)
195                                 R_ConcatTransforms(bonepose[model->data_bones[i].parent], m, bonepose[i]);
196                         else
197                                 memcpy(bonepose[i], m, sizeof(m));
198                         // create a relative deformation matrix to describe displacement
199                         // from the base mesh, which is used by the actual weighting
200                         R_ConcatTransforms(bonepose[i], model->data_baseboneposeinverse + i * 12, boneposerelative[i]);
201                 }
202         }
203         
204         // generate matrices for all blend combinations
205         weights = model->surfmesh.data_blendweights;
206         for (i = 0;i < model->surfmesh.num_blends;i++, weights++)
207         {
208                 float * RESTRICT b = boneposerelative[model->num_bones + i];
209                 const float * RESTRICT m = boneposerelative[weights->index[0]];
210                 float f = weights->influence[0] * (1.0f / 255.0f);
211                 b[ 0] = f*m[ 0]; b[ 1] = f*m[ 1]; b[ 2] = f*m[ 2]; b[ 3] = f*m[ 3];
212                 b[ 4] = f*m[ 4]; b[ 5] = f*m[ 5]; b[ 6] = f*m[ 6]; b[ 7] = f*m[ 7];
213                 b[ 8] = f*m[ 8]; b[ 9] = f*m[ 9]; b[10] = f*m[10]; b[11] = f*m[11];
214                 for (k = 1;k < 4 && weights->influence[k];k++)
215                 {
216                         m = boneposerelative[weights->index[k]];
217                         f = weights->influence[k] * (1.0f / 255.0f);
218                         b[ 0] += f*m[ 0]; b[ 1] += f*m[ 1]; b[ 2] += f*m[ 2]; b[ 3] += f*m[ 3];
219                         b[ 4] += f*m[ 4]; b[ 5] += f*m[ 5]; b[ 6] += f*m[ 6]; b[ 7] += f*m[ 7];
220                         b[ 8] += f*m[ 8]; b[ 9] += f*m[ 9]; b[10] += f*m[10]; b[11] += f*m[11];
221                 }
222         }
223
224         // transform vertex attributes by blended matrices
225         if (vertex3f)
226         {
227                 const float * RESTRICT v = model->surfmesh.data_vertex3f;
228                 const unsigned short * RESTRICT b = model->surfmesh.blends;
229                 // special case common combinations of attributes to avoid repeated loading of matrices
230                 if (normal3f)
231                 {
232                         const float * RESTRICT n = model->surfmesh.data_normal3f;
233                         if (svector3f && tvector3f)
234                         {
235                                 const float * RESTRICT sv = model->surfmesh.data_svector3f;
236                                 const float * RESTRICT tv = model->surfmesh.data_tvector3f;
237                                 for (i = 0;i < model->surfmesh.num_vertices;i++, v += 3, n += 3, sv += 3, tv += 3, b++, vertex3f += 3, normal3f += 3, svector3f += 3, tvector3f += 3)
238                                 {
239                                         const float * RESTRICT m = boneposerelative[*b];
240                                         vertex3f[0] = (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]);
241                                         vertex3f[1] = (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]);
242                                         vertex3f[2] = (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]);
243                                         normal3f[0] = (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]);
244                                         normal3f[1] = (n[0] * m[4] + n[1] * m[5] + n[2] * m[ 6]);
245                                         normal3f[2] = (n[0] * m[8] + n[1] * m[9] + n[2] * m[10]);
246                                         svector3f[0] = (sv[0] * m[0] + sv[1] * m[1] + sv[2] * m[ 2]);
247                                         svector3f[1] = (sv[0] * m[4] + sv[1] * m[5] + sv[2] * m[ 6]);
248                                         svector3f[2] = (sv[0] * m[8] + sv[1] * m[9] + sv[2] * m[10]);
249                                         tvector3f[0] = (tv[0] * m[0] + tv[1] * m[1] + tv[2] * m[ 2]);
250                                         tvector3f[1] = (tv[0] * m[4] + tv[1] * m[5] + tv[2] * m[ 6]);
251                                         tvector3f[2] = (tv[0] * m[8] + tv[1] * m[9] + tv[2] * m[10]);
252                                 }
253                                 return;
254                         }
255                         for (i = 0;i < model->surfmesh.num_vertices;i++, v += 3, n += 3, b++, vertex3f += 3, normal3f += 3)
256                         {
257                                 const float * RESTRICT m = boneposerelative[*b];
258                                 vertex3f[0] = (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]);
259                                 vertex3f[1] = (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]);
260                                 vertex3f[2] = (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]);
261                                 normal3f[0] = (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]);
262                                 normal3f[1] = (n[0] * m[4] + n[1] * m[5] + n[2] * m[ 6]);
263                                 normal3f[2] = (n[0] * m[8] + n[1] * m[9] + n[2] * m[10]);
264                         }
265                 }
266                 else
267                 {
268                         for (i = 0;i < model->surfmesh.num_vertices;i++, v += 3, b++, vertex3f += 3)
269                         {
270                                 const float * RESTRICT m = boneposerelative[*b];
271                                 vertex3f[0] = (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]);
272                                 vertex3f[1] = (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]);
273                                 vertex3f[2] = (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]);
274                         }
275                 }
276         }
277         else if (normal3f)
278         {
279                 const float * RESTRICT n = model->surfmesh.data_normal3f;
280                 const unsigned short * RESTRICT b = model->surfmesh.blends;
281                 for (i = 0;i < model->surfmesh.num_vertices;i++, n += 3, b++, normal3f += 3)
282                 {
283                         const float * RESTRICT m = boneposerelative[*b];
284                         normal3f[0] = (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]);
285                         normal3f[1] = (n[0] * m[4] + n[1] * m[5] + n[2] * m[ 6]);
286                         normal3f[2] = (n[0] * m[8] + n[1] * m[9] + n[2] * m[10]);
287                 }
288         }
289
290         if (svector3f)
291         {
292                 const float * RESTRICT sv = model->surfmesh.data_svector3f;
293                 const unsigned short * RESTRICT b = model->surfmesh.blends;
294                 for (i = 0;i < model->surfmesh.num_vertices;i++, sv += 3, b++, svector3f += 3)
295                 {
296                         const float * RESTRICT m = boneposerelative[*b];
297                         svector3f[0] = (sv[0] * m[0] + sv[1] * m[1] + sv[2] * m[ 2]);
298                         svector3f[1] = (sv[0] * m[4] + sv[1] * m[5] + sv[2] * m[ 6]);
299                         svector3f[2] = (sv[0] * m[8] + sv[1] * m[9] + sv[2] * m[10]);
300                 }
301         }
302
303         if (tvector3f)
304         {
305                 const float * RESTRICT tv = model->surfmesh.data_tvector3f;
306                 const unsigned short * RESTRICT b = model->surfmesh.blends;
307                 for (i = 0;i < model->surfmesh.num_vertices;i++, tv += 3, b++, tvector3f += 3)
308                 {
309                         const float * RESTRICT m = boneposerelative[*b];
310                         tvector3f[0] = (tv[0] * m[0] + tv[1] * m[1] + tv[2] * m[ 2]);
311                         tvector3f[1] = (tv[0] * m[4] + tv[1] * m[5] + tv[2] * m[ 6]);
312                         tvector3f[2] = (tv[0] * m[8] + tv[1] * m[9] + tv[2] * m[10]);
313                 }
314         }
315 }
316
317 void Mod_MD3_AnimateVertices(const dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, float *vertex3f, float *normal3f, float *svector3f, float *tvector3f)
318 {
319         // vertex morph
320         int i, numblends, blendnum;
321         int numverts = model->surfmesh.num_vertices;
322         numblends = 0;
323         for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
324         {
325                 //VectorMA(translate, model->surfmesh.num_morphmdlframetranslate, frameblend[blendnum].lerp, translate);
326                 if (frameblend[blendnum].lerp > 0)
327                         numblends = blendnum + 1;
328         }
329         // special case for the first blend because it avoids some adds and the need to memset the arrays first
330         for (blendnum = 0;blendnum < numblends;blendnum++)
331         {
332                 const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].subframe;
333                 if (vertex3f)
334                 {
335                         float scale = frameblend[blendnum].lerp * (1.0f / 64.0f);
336                         if (blendnum == 0)
337                         {
338                                 for (i = 0;i < numverts;i++)
339                                 {
340                                         vertex3f[i * 3 + 0] = verts[i].origin[0] * scale;
341                                         vertex3f[i * 3 + 1] = verts[i].origin[1] * scale;
342                                         vertex3f[i * 3 + 2] = verts[i].origin[2] * scale;
343                                 }
344                         }
345                         else
346                         {
347                                 for (i = 0;i < numverts;i++)
348                                 {
349                                         vertex3f[i * 3 + 0] += verts[i].origin[0] * scale;
350                                         vertex3f[i * 3 + 1] += verts[i].origin[1] * scale;
351                                         vertex3f[i * 3 + 2] += verts[i].origin[2] * scale;
352                                 }
353                         }
354                 }
355                 // the yaw and pitch stored in md3 models are 8bit quantized angles
356                 // (0-255), and as such a lookup table is very well suited to
357                 // decoding them, and since cosine is equivilant to sine with an
358                 // extra 45 degree rotation, this uses one lookup table for both
359                 // sine and cosine with a +64 bias to get cosine.
360                 if (normal3f)
361                 {
362                         float lerp = frameblend[blendnum].lerp;
363                         if (blendnum == 0)
364                         {
365                                 for (i = 0;i < numverts;i++)
366                                 {
367                                         normal3f[i * 3 + 0] = mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch     ] * lerp;
368                                         normal3f[i * 3 + 1] = mod_md3_sin[verts[i].yaw     ] * mod_md3_sin[verts[i].pitch     ] * lerp;
369                                         normal3f[i * 3 + 2] =                                  mod_md3_sin[verts[i].pitch + 64] * lerp;
370                                 }
371                         }
372                         else
373                         {
374                                 for (i = 0;i < numverts;i++)
375                                 {
376                                         normal3f[i * 3 + 0] += mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch     ] * lerp;
377                                         normal3f[i * 3 + 1] += mod_md3_sin[verts[i].yaw     ] * mod_md3_sin[verts[i].pitch     ] * lerp;
378                                         normal3f[i * 3 + 2] +=                                  mod_md3_sin[verts[i].pitch + 64] * lerp;
379                                 }
380                         }
381                 }
382                 if (svector3f)
383                 {
384                         const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
385                         float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
386                         if (blendnum == 0)
387                         {
388                                 for (i = 0;i < numverts;i++, texvecvert++)
389                                 {
390                                         VectorScale(texvecvert->svec, f, svector3f + i*3);
391                                         VectorScale(texvecvert->tvec, f, tvector3f + i*3);
392                                 }
393                         }
394                         else
395                         {
396                                 for (i = 0;i < numverts;i++, texvecvert++)
397                                 {
398                                         VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
399                                         VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
400                                 }
401                         }
402                 }
403         }
404 }
405
406 void Mod_MDL_AnimateVertices(const dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, float *vertex3f, float *normal3f, float *svector3f, float *tvector3f)
407 {
408         // vertex morph
409         int i, numblends, blendnum;
410         int numverts = model->surfmesh.num_vertices;
411         float translate[3];
412         VectorClear(translate);
413         numblends = 0;
414         // blend the frame translates to avoid redundantly doing so on each vertex
415         // (a bit of a brain twister but it works)
416         for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
417         {
418                 if (model->surfmesh.data_morphmd2framesize6f)
419                         VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6 + 3, translate);
420                 else
421                         VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.num_morphmdlframetranslate, translate);
422                 if (frameblend[blendnum].lerp > 0)
423                         numblends = blendnum + 1;
424         }
425         // special case for the first blend because it avoids some adds and the need to memset the arrays first
426         for (blendnum = 0;blendnum < numblends;blendnum++)
427         {
428                 const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].subframe;
429                 if (vertex3f)
430                 {
431                         float scale[3];
432                         if (model->surfmesh.data_morphmd2framesize6f)
433                                 VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6, frameblend[blendnum].lerp, scale);
434                         else
435                                 VectorScale(model->surfmesh.num_morphmdlframescale, frameblend[blendnum].lerp, scale);
436                         if (blendnum == 0)
437                         {
438                                 for (i = 0;i < numverts;i++)
439                                 {
440                                         vertex3f[i * 3 + 0] = translate[0] + verts[i].v[0] * scale[0];
441                                         vertex3f[i * 3 + 1] = translate[1] + verts[i].v[1] * scale[1];
442                                         vertex3f[i * 3 + 2] = translate[2] + verts[i].v[2] * scale[2];
443                                 }
444                         }
445                         else
446                         {
447                                 for (i = 0;i < numverts;i++)
448                                 {
449                                         vertex3f[i * 3 + 0] += verts[i].v[0] * scale[0];
450                                         vertex3f[i * 3 + 1] += verts[i].v[1] * scale[1];
451                                         vertex3f[i * 3 + 2] += verts[i].v[2] * scale[2];
452                                 }
453                         }
454                 }
455                 // the vertex normals in mdl models are an index into a table of
456                 // 162 unique values, this very crude quantization reduces the
457                 // vertex normal to only one byte, which saves a lot of space but
458                 // also makes lighting pretty coarse
459                 if (normal3f)
460                 {
461                         float lerp = frameblend[blendnum].lerp;
462                         if (blendnum == 0)
463                         {
464                                 for (i = 0;i < numverts;i++)
465                                 {
466                                         const float *vn = m_bytenormals[verts[i].lightnormalindex];
467                                         VectorScale(vn, lerp, normal3f + i*3);
468                                 }
469                         }
470                         else
471                         {
472                                 for (i = 0;i < numverts;i++)
473                                 {
474                                         const float *vn = m_bytenormals[verts[i].lightnormalindex];
475                                         VectorMA(normal3f + i*3, lerp, vn, normal3f + i*3);
476                                 }
477                         }
478                 }
479                 if (svector3f)
480                 {
481                         const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
482                         float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
483                         if (blendnum == 0)
484                         {
485                                 for (i = 0;i < numverts;i++, texvecvert++)
486                                 {
487                                         VectorScale(texvecvert->svec, f, svector3f + i*3);
488                                         VectorScale(texvecvert->tvec, f, tvector3f + i*3);
489                                 }
490                         }
491                         else
492                         {
493                                 for (i = 0;i < numverts;i++, texvecvert++)
494                                 {
495                                         VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
496                                         VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
497                                 }
498                         }
499                 }
500         }
501 }
502
503 int Mod_Alias_GetTagMatrix(const dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, matrix4x4_t *outmatrix)
504 {
505         matrix4x4_t temp;
506         matrix4x4_t parentbonematrix;
507         matrix4x4_t tempbonematrix;
508         matrix4x4_t bonematrix;
509         matrix4x4_t blendmatrix;
510         int blendindex;
511         int parenttagindex;
512         int k;
513         float lerp;
514         const float *input;
515         float blendtag[12];
516         *outmatrix = identitymatrix;
517         if (skeleton && skeleton->relativetransforms)
518         {
519                 if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
520                         return 4;
521                 *outmatrix = skeleton->relativetransforms[tagindex];
522                 while ((tagindex = model->data_bones[tagindex].parent) >= 0)
523                 {
524                         temp = *outmatrix;
525                         Matrix4x4_Concat(outmatrix, &skeleton->relativetransforms[tagindex], &temp);
526                 }
527         }
528         else if (model->num_bones)
529         {
530                 if (tagindex < 0 || tagindex >= model->num_bones)
531                         return 4;
532                 Matrix4x4_Clear(&blendmatrix);
533                 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
534                 {
535                         lerp = frameblend[blendindex].lerp;
536                         Matrix4x4_FromBonePose6s(&bonematrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + tagindex));
537                         parenttagindex = tagindex;
538                         while ((parenttagindex = model->data_bones[parenttagindex].parent) >= 0)
539                         {
540                                 Matrix4x4_FromBonePose6s(&parentbonematrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + parenttagindex));
541                                 tempbonematrix = bonematrix;
542                                 Matrix4x4_Concat(&bonematrix, &parentbonematrix, &tempbonematrix);
543                         }
544                         Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
545                 }
546                 *outmatrix = blendmatrix;
547         }
548         else if (model->num_tags)
549         {
550                 if (tagindex < 0 || tagindex >= model->num_tags)
551                         return 4;
552                 for (k = 0;k < 12;k++)
553                         blendtag[k] = 0;
554                 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
555                 {
556                         lerp = frameblend[blendindex].lerp;
557                         input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
558                         for (k = 0;k < 12;k++)
559                                 blendtag[k] += input[k] * lerp;
560                 }
561                 Matrix4x4_FromArray12FloatGL(outmatrix, blendtag);
562         }
563
564         if(!mod_alias_supporttagscale.integer)
565                 Matrix4x4_Normalize3(outmatrix, outmatrix);
566
567         return 0;
568 }
569
570 int Mod_Alias_GetExtendedTagInfoForIndex(const dp_model_t *model, unsigned int skin, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
571 {
572         int blendindex;
573         int k;
574         float lerp;
575         matrix4x4_t bonematrix;
576         matrix4x4_t blendmatrix;
577         const float *input;
578         float blendtag[12];
579
580         if (skeleton && skeleton->relativetransforms)
581         {
582                 if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
583                         return 1;
584                 *parentindex = skeleton->model->data_bones[tagindex].parent;
585                 *tagname = skeleton->model->data_bones[tagindex].name;
586                 *tag_localmatrix = skeleton->relativetransforms[tagindex];
587                 return 0;
588         }
589         else if (model->num_bones)
590         {
591                 if (tagindex < 0 || tagindex >= model->num_bones)
592                         return 1;
593                 *parentindex = model->data_bones[tagindex].parent;
594                 *tagname = model->data_bones[tagindex].name;
595                 Matrix4x4_Clear(&blendmatrix);
596                 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
597                 {
598                         lerp = frameblend[blendindex].lerp;
599                         Matrix4x4_FromBonePose6s(&bonematrix, model->num_posescale, model->data_poses6s + 6 * (frameblend[blendindex].subframe * model->num_bones + tagindex));
600                         Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
601                 }
602                 *tag_localmatrix = blendmatrix;
603                 return 0;
604         }
605         else if (model->num_tags)
606         {
607                 if (tagindex < 0 || tagindex >= model->num_tags)
608                         return 1;
609                 *parentindex = -1;
610                 *tagname = model->data_tags[tagindex].name;
611                 for (k = 0;k < 12;k++)
612                         blendtag[k] = 0;
613                 for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
614                 {
615                         lerp = frameblend[blendindex].lerp;
616                         input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
617                         for (k = 0;k < 12;k++)
618                                 blendtag[k] += input[k] * lerp;
619                 }
620                 Matrix4x4_FromArray12FloatGL(tag_localmatrix, blendtag);
621                 return 0;
622         }
623
624         return 2;
625 }
626
627 int Mod_Alias_GetTagIndexForName(const dp_model_t *model, unsigned int skin, const char *tagname)
628 {
629         int i;
630         if(skin >= (unsigned int)model->numskins)
631                 skin = 0;
632         if (model->num_bones)
633                 for (i = 0;i < model->num_bones;i++)
634                         if (!strcasecmp(tagname, model->data_bones[i].name))
635                                 return i + 1;
636         if (model->num_tags)
637                 for (i = 0;i < model->num_tags;i++)
638                         if (!strcasecmp(tagname, model->data_tags[i].name))
639                                 return i + 1;
640         return 0;
641 }
642
643 static void Mod_BuildBaseBonePoses(void)
644 {
645         int boneindex;
646         matrix4x4_t *basebonepose;
647         float *outinvmatrix = loadmodel->data_baseboneposeinverse;
648         matrix4x4_t bonematrix;
649         matrix4x4_t tempbonematrix;
650         if (!loadmodel->num_bones)
651                 return;
652         basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
653         for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
654         {
655                 Matrix4x4_FromBonePose6s(&bonematrix, loadmodel->num_posescale, loadmodel->data_poses6s + 6 * boneindex);
656                 if (loadmodel->data_bones[boneindex].parent >= 0)
657                 {
658                         tempbonematrix = bonematrix;
659                         Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
660                 }
661                 basebonepose[boneindex] = bonematrix;
662                 Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
663                 Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
664         }
665         Mem_Free(basebonepose);
666 }
667
668 static void Mod_Alias_CalculateBoundingBox(void)
669 {
670         int vnum;
671         qboolean firstvertex = true;
672         float dist, yawradius, radius;
673         float *v;
674         float *vertex3f;
675         frameblend_t frameblend[MAX_FRAMEBLENDS];
676         memset(frameblend, 0, sizeof(frameblend));
677         frameblend[0].lerp = 1;
678         vertex3f = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
679         VectorClear(loadmodel->normalmins);
680         VectorClear(loadmodel->normalmaxs);
681         yawradius = 0;
682         radius = 0;
683         for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++)
684         {
685                 loadmodel->AnimateVertices(loadmodel, frameblend, NULL, vertex3f, NULL, NULL, NULL);
686                 for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
687                 {
688                         if (firstvertex)
689                         {
690                                 firstvertex = false;
691                                 VectorCopy(v, loadmodel->normalmins);
692                                 VectorCopy(v, loadmodel->normalmaxs);
693                         }
694                         else
695                         {
696                                 if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
697                                 if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
698                                 if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
699                                 if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
700                                 if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
701                                 if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
702                         }
703                         dist = v[0] * v[0] + v[1] * v[1];
704                         if (yawradius < dist)
705                                 yawradius = dist;
706                         dist += v[2] * v[2];
707                         if (radius < dist)
708                                 radius = dist;
709                 }
710         }
711         if (vertex3f)
712                 Mem_Free(vertex3f);
713         radius = sqrt(radius);
714         yawradius = sqrt(yawradius);
715         loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius;
716         loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = yawradius;
717         loadmodel->yawmins[2] = loadmodel->normalmins[2];
718         loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
719         loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
720         loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
721         loadmodel->radius = radius;
722         loadmodel->radius2 = radius * radius;
723 }
724
725 static void Mod_Alias_MorphMesh_CompileFrames(void)
726 {
727         int i, j;
728         frameblend_t frameblend[MAX_FRAMEBLENDS];
729         unsigned char *datapointer;
730         memset(frameblend, 0, sizeof(frameblend));
731         frameblend[0].lerp = 1;
732         datapointer = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * (sizeof(float[3]) * 4 + loadmodel->surfmesh.num_morphframes * sizeof(texvecvertex_t)));
733         loadmodel->surfmesh.data_vertex3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
734         loadmodel->surfmesh.data_svector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
735         loadmodel->surfmesh.data_tvector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
736         loadmodel->surfmesh.data_normal3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
737         loadmodel->surfmesh.data_morphtexvecvertex = (texvecvertex_t *)datapointer;datapointer += loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices * sizeof(texvecvertex_t);
738         // this counts down from the last frame to the first so that the final data in surfmesh is for frame zero (which is what the renderer expects to be there)
739         for (i = loadmodel->surfmesh.num_morphframes-1;i >= 0;i--)
740         {
741                 frameblend[0].subframe = i;
742                 loadmodel->AnimateVertices(loadmodel, frameblend, NULL, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_normal3f, NULL, NULL);
743                 Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
744                 // encode the svector and tvector in 3 byte format for permanent storage
745                 for (j = 0;j < loadmodel->surfmesh.num_vertices;j++)
746                 {
747                         VectorScaleCast(loadmodel->surfmesh.data_svector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].svec);
748                         VectorScaleCast(loadmodel->surfmesh.data_tvector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].tvec);
749                 }
750         }
751 }
752
753 static void Mod_MDLMD2MD3_TraceLine(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask)
754 {
755         int i;
756         float segmentmins[3], segmentmaxs[3];
757         msurface_t *surface;
758         static int maxvertices = 0;
759         static float *vertex3f = NULL;
760         memset(trace, 0, sizeof(*trace));
761         trace->fraction = 1;
762         trace->realfraction = 1;
763         trace->hitsupercontentsmask = hitsupercontentsmask;
764         if (maxvertices < model->surfmesh.num_vertices)
765         {
766                 if (vertex3f)
767                         Z_Free(vertex3f);
768                 maxvertices = (model->surfmesh.num_vertices + 255) & ~255;
769                 vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3]));
770         }
771         segmentmins[0] = min(start[0], end[0]) - 1;
772         segmentmins[1] = min(start[1], end[1]) - 1;
773         segmentmins[2] = min(start[2], end[2]) - 1;
774         segmentmaxs[0] = max(start[0], end[0]) + 1;
775         segmentmaxs[1] = max(start[1], end[1]) + 1;
776         segmentmaxs[2] = max(start[2], end[2]) + 1;
777         model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
778         for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
779                 Collision_TraceLineTriangleMeshFloat(trace, start, end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
780 }
781
782 static int maxvertices = 0;
783 static float *vertex3f = NULL;
784
785 static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask)
786 {
787         int i;
788         vec3_t shiftstart, shiftend;
789         float segmentmins[3], segmentmaxs[3];
790         msurface_t *surface;
791         colboxbrushf_t thisbrush_start, thisbrush_end;
792         vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
793
794         if (VectorCompare(boxmins, boxmaxs))
795         {
796                 VectorAdd(start, boxmins, shiftstart);
797                 VectorAdd(end, boxmins, shiftend);
798                 Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask);
799                 VectorSubtract(trace->endpos, boxmins, trace->endpos);
800                 return;
801         }
802
803         // box trace, performed as brush trace
804         memset(trace, 0, sizeof(*trace));
805         trace->fraction = 1;
806         trace->realfraction = 1;
807         trace->hitsupercontentsmask = hitsupercontentsmask;
808         if (maxvertices < model->surfmesh.num_vertices)
809         {
810                 if (vertex3f)
811                         Z_Free(vertex3f);
812                 maxvertices = (model->surfmesh.num_vertices + 255) & ~255;
813                 vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3]));
814         }
815         segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1;
816         segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1;
817         segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1;
818         segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1;
819         segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1;
820         segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1;
821         VectorAdd(start, boxmins, boxstartmins);
822         VectorAdd(start, boxmaxs, boxstartmaxs);
823         VectorAdd(end, boxmins, boxendmins);
824         VectorAdd(end, boxmaxs, boxendmaxs);
825         Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL);
826         Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL);
827         if (maxvertices < model->surfmesh.num_vertices)
828         {
829                 if (vertex3f)
830                         Z_Free(vertex3f);
831                 maxvertices = (model->surfmesh.num_vertices + 255) & ~255;
832                 vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3]));
833         }
834         model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
835         for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
836                 Collision_TraceBrushTriangleMeshFloat(trace, &thisbrush_start.brush, &thisbrush_end.brush, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
837 }
838
839 static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap)
840 {
841         int i, j;
842         for (i = 0;i < inverts;i++)
843         {
844                 if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
845                         continue;
846                 j = vertremap[i]; // not onseam
847                 if (j >= 0)
848                         out[j] = v[i];
849                 j = vertremap[i+inverts]; // onseam
850                 if (j >= 0)
851                         out[j] = v[i];
852         }
853 }
854
855 static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *vertremap)
856 {
857         int i, f, pose, groupframes;
858         float interval;
859         daliasframetype_t *pframetype;
860         daliasframe_t *pinframe;
861         daliasgroup_t *group;
862         daliasinterval_t *intervals;
863         animscene_t *scene;
864         pose = 0;
865         scene = loadmodel->animscenes;
866         for (f = 0;f < loadmodel->numframes;f++)
867         {
868                 pframetype = (daliasframetype_t *)datapointer;
869                 datapointer += sizeof(daliasframetype_t);
870                 if (LittleLong (pframetype->type) == ALIAS_SINGLE)
871                 {
872                         // a single frame is still treated as a group
873                         interval = 0.1f;
874                         groupframes = 1;
875                 }
876                 else
877                 {
878                         // read group header
879                         group = (daliasgroup_t *)datapointer;
880                         datapointer += sizeof(daliasgroup_t);
881                         groupframes = LittleLong (group->numframes);
882
883                         // intervals (time per frame)
884                         intervals = (daliasinterval_t *)datapointer;
885                         datapointer += sizeof(daliasinterval_t) * groupframes;
886
887                         interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
888                         if (interval < 0.01f)
889                         {
890                                 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
891                                 interval = 0.1f;
892                         }
893                 }
894
895                 // get scene name from first frame
896                 pinframe = (daliasframe_t *)datapointer;
897
898                 strlcpy(scene->name, pinframe->name, sizeof(scene->name));
899                 scene->firstframe = pose;
900                 scene->framecount = groupframes;
901                 scene->framerate = 1.0f / interval;
902                 scene->loop = true;
903                 scene++;
904
905                 // read frames
906                 for (i = 0;i < groupframes;i++)
907                 {
908                         pinframe = (daliasframe_t *)datapointer;
909                         datapointer += sizeof(daliasframe_t);
910                         Mod_ConvertAliasVerts(inverts, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphmdlvertex + pose * loadmodel->surfmesh.num_vertices, vertremap);
911                         datapointer += sizeof(trivertx_t) * inverts;
912                         pose++;
913                 }
914         }
915 }
916
917 static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *skinframe)
918 {
919         if (cls.state == ca_dedicated)
920                 return;
921         // hack
922         if (!skinframe)
923                 skinframe = R_SkinFrame_LoadMissing();
924         memset(texture, 0, sizeof(*texture));
925         texture->currentframe = texture;
926         //texture->animated = false;
927         texture->numskinframes = 1;
928         texture->skinframerate = 1;
929         texture->skinframes[0] = skinframe;
930         texture->currentskinframe = skinframe;
931         //texture->backgroundnumskinframes = 0;
932         //texture->customblendfunc[0] = 0;
933         //texture->customblendfunc[1] = 0;
934         //texture->surfaceflags = 0;
935         //texture->supercontents = 0;
936         //texture->surfaceparms = 0;
937         //texture->textureflags = 0;
938
939         texture->basematerialflags = MATERIALFLAG_WALL;
940         if (texture->currentskinframe->hasalpha)
941                 texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
942         texture->currentmaterialflags = texture->basematerialflags;
943         texture->specularscalemod = 1;
944         texture->specularpowermod = 1;
945 }
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 }