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