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