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