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