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