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