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