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