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