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