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