]> icculus.org git repositories - divverent/darkplaces.git/blob - model_alias.c
fix model scaling on old zym and dpm files where the root bone was
[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, tempvec[3], modelscale;
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         // figure out scale of model from root bone, for compatibility with old zmodel versions
1886         tempvec[0] = BigFloat(poses[0]);
1887         tempvec[1] = BigFloat(poses[1]);
1888         tempvec[2] = BigFloat(poses[2]);
1889         modelscale = VectorLength(tempvec);
1890         biggestorigin = 0;
1891         for (i = 0;i < loadmodel->num_bones * numposes * 12;i++)
1892         {
1893                 f = fabs(BigFloat(poses[i]));
1894                 biggestorigin = max(biggestorigin, f);
1895         }
1896         loadmodel->num_posescale = biggestorigin / 32767.0f;
1897         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
1898         for (i = 0;i < numposes;i++)
1899         {
1900                 const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones;
1901                 for (j = 0;j < loadmodel->num_bones;j++)
1902                 {
1903                         float pose[12];
1904                         matrix4x4_t posematrix;
1905                         for (k = 0;k < 12;k++)
1906                                 pose[k] = BigFloat(frameposes[j*12+k]);
1907                         //if (j < loadmodel->num_bones)
1908                         //      Con_Printf("%s: bone %i = %f %f %f %f : %f %f %f %f : %f %f %f %f : scale = %f\n", loadmodel->name, j, pose[0], pose[1], pose[2], pose[3], pose[4], pose[5], pose[6], pose[7], pose[8], pose[9], pose[10], pose[11], VectorLength(pose));
1909                         // scale child bones to match the root scale
1910                         if (loadmodel->data_bones[j].parent >= 0)
1911                         {
1912                                 pose[3] *= modelscale;
1913                                 pose[7] *= modelscale;
1914                                 pose[11] *= modelscale;
1915                         }
1916                         // normalize rotation matrix
1917                         VectorNormalize(pose + 0);
1918                         VectorNormalize(pose + 4);
1919                         VectorNormalize(pose + 8);
1920                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
1921                         Matrix4x4_ToBonePose6s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses6s + 6*(i*loadmodel->num_bones+j));
1922                 }
1923         }
1924
1925         //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
1926         verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
1927         vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
1928         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
1929         // (converting from weight-blending skeletal animation to
1930         //  deformation-based skeletal animation)
1931         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
1932         for (i = 0;i < loadmodel->num_bones;i++)
1933         {
1934                 float m[12];
1935                 for (k = 0;k < 12;k++)
1936                         m[k] = BigFloat(poses[i*12+k]);
1937                 if (loadmodel->data_bones[i].parent >= 0)
1938                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
1939                 else
1940                         for (k = 0;k < 12;k++)
1941                                 bonepose[12*i+k] = m[k];
1942         }
1943         for (j = 0;j < pheader->numverts;j++)
1944         {
1945                 // this format really should have had a per vertexweight weight value...
1946                 // but since it does not, the weighting is completely ignored and
1947                 // only one weight is allowed per vertex
1948                 int boneindex = BigLong(vertdata[j].bonenum);
1949                 const float *m = bonepose + 12 * boneindex;
1950                 float relativeorigin[3];
1951                 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
1952                 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
1953                 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
1954                 // transform the vertex bone weight into the base mesh
1955                 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
1956                 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
1957                 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
1958                 // store the weight as the primary weight on this vertex
1959                 loadmodel->surfmesh.data_vertexweightindex4i[j*4+0] = boneindex;
1960                 loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+0] = 1;
1961         }
1962         Z_Free(bonepose);
1963         // normals and tangents are calculated after elements are loaded
1964
1965         //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
1966         outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
1967         intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
1968         for (i = 0;i < pheader->numverts;i++)
1969         {
1970                 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
1971                 // flip T coordinate for OpenGL
1972                 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
1973         }
1974
1975         //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
1976         //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
1977         //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
1978
1979         //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
1980         //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)
1981         // byteswap, validate, and swap winding order of tris
1982         count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
1983         if (pheader->lump_render.length != count)
1984                 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
1985         renderlist = (int *) (pheader->lump_render.start + pbase);
1986         renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
1987         meshtriangles = 0;
1988         for (i = 0;i < loadmodel->num_surfaces;i++)
1989         {
1990                 int firstvertex, lastvertex;
1991                 if (renderlist >= renderlistend)
1992                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
1993                 count = BigLong(*renderlist);renderlist++;
1994                 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
1995                         Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
1996
1997                 loadmodel->sortedmodelsurfaces[i] = i;
1998                 surface = loadmodel->data_surfaces + i;
1999                 surface->texture = loadmodel->data_textures + i;
2000                 surface->num_firsttriangle = meshtriangles;
2001                 surface->num_triangles = count;
2002                 meshtriangles += surface->num_triangles;
2003
2004                 // load the elements
2005                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2006                 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
2007                 {
2008                         outelements[j*3+2] = BigLong(renderlist[0]);
2009                         outelements[j*3+1] = BigLong(renderlist[1]);
2010                         outelements[j*3+0] = BigLong(renderlist[2]);
2011                 }
2012                 // validate the elements and find the used vertex range
2013                 firstvertex = meshvertices;
2014                 lastvertex = 0;
2015                 for (j = 0;j < surface->num_triangles * 3;j++)
2016                 {
2017                         if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
2018                                 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
2019                         firstvertex = min(firstvertex, outelements[j]);
2020                         lastvertex = max(lastvertex, outelements[j]);
2021                 }
2022                 surface->num_firstvertex = firstvertex;
2023                 surface->num_vertices = lastvertex + 1 - firstvertex;
2024
2025                 // since zym models do not have named sections, reuse their shader
2026                 // name as the section name
2027                 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
2028                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
2029         }
2030         Mod_FreeSkinFiles(skinfiles);
2031         Mem_Free(vertbonecounts);
2032         Mem_Free(verts);
2033         Mod_MakeSortedSurfaces(loadmodel);
2034
2035         // compute all the mesh information that was not loaded from the file
2036         if (loadmodel->surfmesh.data_element3s)
2037                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2038                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2039         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2040         Mod_BuildBaseBonePoses();
2041         Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, true);
2042         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);
2043         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2044
2045         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
2046 }
2047
2048 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2049 {
2050         dpmheader_t *pheader;
2051         dpmframe_t *frames;
2052         dpmbone_t *bone;
2053         dpmmesh_t *dpmmesh;
2054         unsigned char *pbase;
2055         int i, j, k, meshvertices, meshtriangles;
2056         skinfile_t *skinfiles;
2057         unsigned char *data;
2058         float *bonepose;
2059         float biggestorigin, tempvec[3], modelscale;
2060         float f;
2061         float *poses;
2062
2063         pheader = (dpmheader_t *)buffer;
2064         pbase = (unsigned char *)buffer;
2065         if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
2066                 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
2067         if (BigLong(pheader->type) != 2)
2068                 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
2069
2070         loadmodel->modeldatatypestring = "DPM";
2071
2072         loadmodel->type = mod_alias;
2073         loadmodel->synctype = ST_RAND;
2074
2075         // byteswap header
2076         pheader->type = BigLong(pheader->type);
2077         pheader->filesize = BigLong(pheader->filesize);
2078         pheader->mins[0] = BigFloat(pheader->mins[0]);
2079         pheader->mins[1] = BigFloat(pheader->mins[1]);
2080         pheader->mins[2] = BigFloat(pheader->mins[2]);
2081         pheader->maxs[0] = BigFloat(pheader->maxs[0]);
2082         pheader->maxs[1] = BigFloat(pheader->maxs[1]);
2083         pheader->maxs[2] = BigFloat(pheader->maxs[2]);
2084         pheader->yawradius = BigFloat(pheader->yawradius);
2085         pheader->allradius = BigFloat(pheader->allradius);
2086         pheader->num_bones = BigLong(pheader->num_bones);
2087         pheader->num_meshs = BigLong(pheader->num_meshs);
2088         pheader->num_frames = BigLong(pheader->num_frames);
2089         pheader->ofs_bones = BigLong(pheader->ofs_bones);
2090         pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
2091         pheader->ofs_frames = BigLong(pheader->ofs_frames);
2092
2093         if (pheader->num_bones < 1 || pheader->num_meshs < 1)
2094         {
2095                 Con_Printf("%s has no geometry\n", loadmodel->name);
2096                 return;
2097         }
2098         if (pheader->num_frames < 1)
2099         {
2100                 Con_Printf("%s has no frames\n", loadmodel->name);
2101                 return;
2102         }
2103
2104         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2105         loadmodel->DrawSky = NULL;
2106         loadmodel->DrawAddWaterPlanes = NULL;
2107         loadmodel->Draw = R_Q1BSP_Draw;
2108         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2109         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2110         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2111         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2112         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2113         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2114         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2115         loadmodel->DrawLight = R_Q1BSP_DrawLight;
2116         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2117         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2118         loadmodel->PointSuperContents = NULL;
2119
2120         // model bbox
2121         for (i = 0;i < 3;i++)
2122         {
2123                 loadmodel->normalmins[i] = pheader->mins[i];
2124                 loadmodel->normalmaxs[i] = pheader->maxs[i];
2125                 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
2126                 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
2127                 loadmodel->rotatedmins[i] = -pheader->allradius;
2128                 loadmodel->rotatedmaxs[i] = pheader->allradius;
2129         }
2130         loadmodel->radius = pheader->allradius;
2131         loadmodel->radius2 = pheader->allradius * pheader->allradius;
2132
2133         // load external .skin files if present
2134         skinfiles = Mod_LoadSkinFiles();
2135         if (loadmodel->numskins < 1)
2136                 loadmodel->numskins = 1;
2137
2138         meshvertices = 0;
2139         meshtriangles = 0;
2140
2141         // gather combined statistics from the meshes
2142         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2143         for (i = 0;i < (int)pheader->num_meshs;i++)
2144         {
2145                 int numverts = BigLong(dpmmesh->num_verts);
2146                 meshvertices += numverts;
2147                 meshtriangles += BigLong(dpmmesh->num_tris);
2148                 dpmmesh++;
2149         }
2150
2151         loadmodel->numframes = pheader->num_frames;
2152         loadmodel->num_bones = pheader->num_bones;
2153         loadmodel->num_poses = loadmodel->numframes;
2154         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
2155         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2156         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2157         // do most allocations as one merged chunk
2158         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));
2159         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2160         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2161         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2162         loadmodel->surfmesh.num_vertices = meshvertices;
2163         loadmodel->surfmesh.num_triangles = meshtriangles;
2164         loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2165         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
2166         loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
2167         loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2168         loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
2169         loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
2170         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
2171         loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += meshvertices * sizeof(int[4]);
2172         loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += meshvertices * sizeof(float[4]);
2173         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2174         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2175         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2176         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2177         if (meshvertices <= 65536)
2178                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
2179         loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
2180
2181         for (i = 0;i < loadmodel->numskins;i++)
2182         {
2183                 loadmodel->skinscenes[i].firstframe = i;
2184                 loadmodel->skinscenes[i].framecount = 1;
2185                 loadmodel->skinscenes[i].loop = true;
2186                 loadmodel->skinscenes[i].framerate = 10;
2187         }
2188
2189         // load the bone info
2190         bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
2191         for (i = 0;i < loadmodel->num_bones;i++)
2192         {
2193                 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
2194                 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
2195                 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
2196                 if (loadmodel->data_bones[i].parent >= i)
2197                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2198         }
2199
2200         // load the frames
2201         frames = (dpmframe_t *) (pbase + pheader->ofs_frames);
2202         // figure out scale of model from root bone, for compatibility with old dpmodel versions
2203         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2204         tempvec[0] = BigFloat(poses[0]);
2205         tempvec[1] = BigFloat(poses[1]);
2206         tempvec[2] = BigFloat(poses[2]);
2207         modelscale = VectorLength(tempvec);
2208         biggestorigin = 0;
2209         for (i = 0;i < loadmodel->numframes;i++)
2210         {
2211                 memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name));
2212                 loadmodel->animscenes[i].firstframe = i;
2213                 loadmodel->animscenes[i].framecount = 1;
2214                 loadmodel->animscenes[i].loop = true;
2215                 loadmodel->animscenes[i].framerate = 10;
2216                 // load the bone poses for this frame
2217                 poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2218                 for (j = 0;j < loadmodel->num_bones*12;j++)
2219                 {
2220                         f = fabs(BigFloat(poses[j]));
2221                         biggestorigin = max(biggestorigin, f);
2222                 }
2223                 // stuff not processed here: mins, maxs, yawradius, allradius
2224         }
2225         loadmodel->num_posescale = biggestorigin / 32767.0f;
2226         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2227         for (i = 0;i < loadmodel->numframes;i++)
2228         {
2229                 const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions));
2230                 for (j = 0;j < loadmodel->num_bones;j++)
2231                 {
2232                         float pose[12];
2233                         matrix4x4_t posematrix;
2234                         for (k = 0;k < 12;k++)
2235                                 pose[k] = BigFloat(frameposes[j*12+k]);
2236                         // scale child bones to match the root scale
2237                         if (loadmodel->data_bones[j].parent >= 0)
2238                         {
2239                                 pose[3] *= modelscale;
2240                                 pose[7] *= modelscale;
2241                                 pose[11] *= modelscale;
2242                         }
2243                         // normalize rotation matrix
2244                         VectorNormalize(pose + 0);
2245                         VectorNormalize(pose + 4);
2246                         VectorNormalize(pose + 8);
2247                         Matrix4x4_FromArray12FloatD3D(&posematrix, pose);
2248                         Matrix4x4_ToBonePose6s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses6s + 6*(i*loadmodel->num_bones+j));
2249                 }
2250         }
2251
2252         // load the meshes now
2253         dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2254         meshvertices = 0;
2255         meshtriangles = 0;
2256         // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2257         // (converting from weight-blending skeletal animation to
2258         //  deformation-based skeletal animation)
2259         poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions));
2260         bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2261         for (i = 0;i < loadmodel->num_bones;i++)
2262         {
2263                 float m[12];
2264                 for (k = 0;k < 12;k++)
2265                         m[k] = BigFloat(poses[i*12+k]);
2266                 if (loadmodel->data_bones[i].parent >= 0)
2267                         R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2268                 else
2269                         for (k = 0;k < 12;k++)
2270                                 bonepose[12*i+k] = m[k];
2271         }
2272         for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2273         {
2274                 const int *inelements;
2275                 int *outelements;
2276                 const float *intexcoord;
2277                 msurface_t *surface;
2278
2279                 loadmodel->sortedmodelsurfaces[i] = i;
2280                 surface = loadmodel->data_surfaces + i;
2281                 surface->texture = loadmodel->data_textures + i;
2282                 surface->num_firsttriangle = meshtriangles;
2283                 surface->num_triangles = BigLong(dpmmesh->num_tris);
2284                 surface->num_firstvertex = meshvertices;
2285                 surface->num_vertices = BigLong(dpmmesh->num_verts);
2286                 meshvertices += surface->num_vertices;
2287                 meshtriangles += surface->num_triangles;
2288
2289                 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2290                 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2291                 for (j = 0;j < surface->num_triangles;j++)
2292                 {
2293                         // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2294                         outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
2295                         outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
2296                         outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
2297                         inelements += 3;
2298                         outelements += 3;
2299                 }
2300
2301                 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2302                 for (j = 0;j < surface->num_vertices*2;j++)
2303                         loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2304
2305                 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2306                 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2307                 {
2308                         float sum;
2309                         int l;
2310                         int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2311                         data += sizeof(dpmvertex_t);
2312                         for (k = 0;k < numweights;k++)
2313                         {
2314                                 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2315                                 int boneindex = BigLong(vert->bonenum);
2316                                 const float *m = bonepose + 12 * boneindex;
2317                                 float influence = BigFloat(vert->influence);
2318                                 float relativeorigin[3], relativenormal[3];
2319                                 relativeorigin[0] = BigFloat(vert->origin[0]);
2320                                 relativeorigin[1] = BigFloat(vert->origin[1]);
2321                                 relativeorigin[2] = BigFloat(vert->origin[2]);
2322                                 relativenormal[0] = BigFloat(vert->normal[0]);
2323                                 relativenormal[1] = BigFloat(vert->normal[1]);
2324                                 relativenormal[2] = BigFloat(vert->normal[2]);
2325                                 // blend the vertex bone weights into the base mesh
2326                                 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2327                                 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2328                                 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2329                                 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2330                                 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2331                                 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2332                                 if (!k)
2333                                 {
2334                                         // store the first (and often only) weight
2335                                         loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+0] = influence;
2336                                         loadmodel->surfmesh.data_vertexweightindex4i[j*4+0] = boneindex;
2337                                 }
2338                                 else
2339                                 {
2340                                         // sort the new weight into this vertex's weight table
2341                                         // (which only accepts up to 4 bones per vertex)
2342                                         for (l = 0;l < 4;l++)
2343                                         {
2344                                                 if (loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] < influence)
2345                                                 {
2346                                                         // move weaker influence weights out of the way first
2347                                                         int l2;
2348                                                         for (l2 = 3;l2 > l;l2--)
2349                                                         {
2350                                                                 loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l2] = loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l2-1];
2351                                                                 loadmodel->surfmesh.data_vertexweightindex4i[j*4+l2] = loadmodel->surfmesh.data_vertexweightindex4i[j*4+l2-1];
2352                                                         }
2353                                                         // store the new weight
2354                                                         loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] = influence;
2355                                                         loadmodel->surfmesh.data_vertexweightindex4i[j*4+l] = boneindex;
2356                                                         break;
2357                                                 }
2358                                         }
2359                                 }
2360                                 data += sizeof(dpmbonevert_t);
2361                         }
2362                         sum = 0;
2363                         for (l = 0;l < 4;l++)
2364                                 sum += loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l];
2365                         if (sum && fabs(sum - 1) > (1.0f / 256.0f))
2366                         {
2367                                 float f = 1.0f / sum;
2368                                 for (l = 0;l < 4;l++)
2369                                         loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] *= f;
2370                         }
2371                 }
2372
2373                 // since dpm models do not have named sections, reuse their shader name as the section name
2374                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2375
2376                 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2377         }
2378         Z_Free(bonepose);
2379         Mod_FreeSkinFiles(skinfiles);
2380         Mod_MakeSortedSurfaces(loadmodel);
2381
2382         // compute all the mesh information that was not loaded from the file
2383         if (loadmodel->surfmesh.data_element3s)
2384                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2385                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2386         Mod_BuildBaseBonePoses();
2387         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);
2388         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2389
2390         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
2391 }
2392
2393 // no idea why PSK/PSA files contain weird quaternions but they do...
2394 #define PSKQUATNEGATIONS
2395 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2396 {
2397         int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2398         int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2399         fs_offset_t filesize;
2400         pskpnts_t *pnts;
2401         pskvtxw_t *vtxw;
2402         pskface_t *faces;
2403         pskmatt_t *matts;
2404         pskboneinfo_t *bones;
2405         pskrawweights_t *rawweights;
2406         pskboneinfo_t *animbones;
2407         pskaniminfo_t *anims;
2408         pskanimkeys_t *animkeys;
2409         void *animfilebuffer, *animbuffer, *animbufferend;
2410         unsigned char *data;
2411         pskchunk_t *pchunk;
2412         skinfile_t *skinfiles;
2413         char animname[MAX_QPATH];
2414         size_t size;
2415         float biggestorigin;
2416
2417         pchunk = (pskchunk_t *)buffer;
2418         if (strcmp(pchunk->id, "ACTRHEAD"))
2419                 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2420
2421         loadmodel->modeldatatypestring = "PSK";
2422
2423         loadmodel->type = mod_alias;
2424         loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2425         loadmodel->DrawSky = NULL;
2426         loadmodel->DrawAddWaterPlanes = NULL;
2427         loadmodel->Draw = R_Q1BSP_Draw;
2428         loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2429         loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2430         loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
2431         loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
2432         loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
2433         loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2434         loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2435         loadmodel->DrawLight = R_Q1BSP_DrawLight;
2436         loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2437         loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
2438         loadmodel->PointSuperContents = NULL;
2439         loadmodel->synctype = ST_RAND;
2440
2441         FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2442         strlcat(animname, ".psa", sizeof(animname));
2443         animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2444         animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2445         if (animbuffer == NULL)
2446                 Host_Error("%s: can't find .psa file (%s)", loadmodel->name, animname);
2447
2448         numpnts = 0;
2449         pnts = NULL;
2450         numvtxw = 0;
2451         vtxw = NULL;
2452         numfaces = 0;
2453         faces = NULL;
2454         nummatts = 0;
2455         matts = NULL;
2456         numbones = 0;
2457         bones = NULL;
2458         numrawweights = 0;
2459         rawweights = NULL;
2460         numanims = 0;
2461         anims = NULL;
2462         numanimkeys = 0;
2463         animkeys = NULL;
2464
2465         while (buffer < bufferend)
2466         {
2467                 pchunk = (pskchunk_t *)buffer;
2468                 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2469                 version = LittleLong(pchunk->version);
2470                 recordsize = LittleLong(pchunk->recordsize);
2471                 numrecords = LittleLong(pchunk->numrecords);
2472                 if (developer_extra.integer)
2473                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2474                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2475                         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);
2476                 if (!strcmp(pchunk->id, "ACTRHEAD"))
2477                 {
2478                         // nothing to do
2479                 }
2480                 else if (!strcmp(pchunk->id, "PNTS0000"))
2481                 {
2482                         pskpnts_t *p;
2483                         if (recordsize != sizeof(*p))
2484                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2485                         // byteswap in place and keep the pointer
2486                         numpnts = numrecords;
2487                         pnts = (pskpnts_t *)buffer;
2488                         for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2489                         {
2490                                 p->origin[0] = LittleFloat(p->origin[0]);
2491                                 p->origin[1] = LittleFloat(p->origin[1]);
2492                                 p->origin[2] = LittleFloat(p->origin[2]);
2493                         }
2494                         buffer = p;
2495                 }
2496                 else if (!strcmp(pchunk->id, "VTXW0000"))
2497                 {
2498                         pskvtxw_t *p;
2499                         if (recordsize != sizeof(*p))
2500                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2501                         // byteswap in place and keep the pointer
2502                         numvtxw = numrecords;
2503                         vtxw = (pskvtxw_t *)buffer;
2504                         for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2505                         {
2506                                 p->pntsindex = LittleShort(p->pntsindex);
2507                                 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2508                                 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2509                                 if (p->pntsindex >= numpnts)
2510                                 {
2511                                         Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2512                                         p->pntsindex = 0;
2513                                 }
2514                         }
2515                         buffer = p;
2516                 }
2517                 else if (!strcmp(pchunk->id, "FACE0000"))
2518                 {
2519                         pskface_t *p;
2520                         if (recordsize != sizeof(*p))
2521                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2522                         // byteswap in place and keep the pointer
2523                         numfaces = numrecords;
2524                         faces = (pskface_t *)buffer;
2525                         for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2526                         {
2527                                 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2528                                 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2529                                 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2530                                 p->group = LittleLong(p->group);
2531                                 if (p->vtxwindex[0] >= numvtxw)
2532                                 {
2533                                         Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2534                                         p->vtxwindex[0] = 0;
2535                                 }
2536                                 if (p->vtxwindex[1] >= numvtxw)
2537                                 {
2538                                         Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2539                                         p->vtxwindex[1] = 0;
2540                                 }
2541                                 if (p->vtxwindex[2] >= numvtxw)
2542                                 {
2543                                         Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2544                                         p->vtxwindex[2] = 0;
2545                                 }
2546                         }
2547                         buffer = p;
2548                 }
2549                 else if (!strcmp(pchunk->id, "MATT0000"))
2550                 {
2551                         pskmatt_t *p;
2552                         if (recordsize != sizeof(*p))
2553                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2554                         // byteswap in place and keep the pointer
2555                         nummatts = numrecords;
2556                         matts = (pskmatt_t *)buffer;
2557                         for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2558                         {
2559                                 // nothing to do
2560                         }
2561                         buffer = p;
2562                 }
2563                 else if (!strcmp(pchunk->id, "REFSKELT"))
2564                 {
2565                         pskboneinfo_t *p;
2566                         if (recordsize != sizeof(*p))
2567                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2568                         // byteswap in place and keep the pointer
2569                         numbones = numrecords;
2570                         bones = (pskboneinfo_t *)buffer;
2571                         for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2572                         {
2573                                 p->numchildren = LittleLong(p->numchildren);
2574                                 p->parent = LittleLong(p->parent);
2575                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2576                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2577                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2578                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2579                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2580                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2581                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2582                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2583                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2584                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2585                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2586 #ifdef PSKQUATNEGATIONS
2587                                 if (index)
2588                                 {
2589                                         p->basepose.quat[0] *= -1;
2590                                         p->basepose.quat[1] *= -1;
2591                                         p->basepose.quat[2] *= -1;
2592                                 }
2593                                 else
2594                                 {
2595                                         p->basepose.quat[0] *=  1;
2596                                         p->basepose.quat[1] *= -1;
2597                                         p->basepose.quat[2] *=  1;
2598                                 }
2599 #endif
2600                                 if (p->parent < 0 || p->parent >= numbones)
2601                                 {
2602                                         Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2603                                         p->parent = 0;
2604                                 }
2605                         }
2606                         buffer = p;
2607                 }
2608                 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2609                 {
2610                         pskrawweights_t *p;
2611                         if (recordsize != sizeof(*p))
2612                                 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2613                         // byteswap in place and keep the pointer
2614                         numrawweights = numrecords;
2615                         rawweights = (pskrawweights_t *)buffer;
2616                         for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2617                         {
2618                                 p->weight = LittleFloat(p->weight);
2619                                 p->pntsindex = LittleLong(p->pntsindex);
2620                                 p->boneindex = LittleLong(p->boneindex);
2621                                 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2622                                 {
2623                                         Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2624                                         p->pntsindex = 0;
2625                                 }
2626                                 if (p->boneindex < 0 || p->boneindex >= numbones)
2627                                 {
2628                                         Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2629                                         p->boneindex = 0;
2630                                 }
2631                         }
2632                         buffer = p;
2633                 }
2634         }
2635
2636         while (animbuffer < animbufferend)
2637         {
2638                 pchunk = (pskchunk_t *)animbuffer;
2639                 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2640                 version = LittleLong(pchunk->version);
2641                 recordsize = LittleLong(pchunk->recordsize);
2642                 numrecords = LittleLong(pchunk->numrecords);
2643                 if (developer_extra.integer)
2644                         Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2645                 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2646                         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);
2647                 if (!strcmp(pchunk->id, "ANIMHEAD"))
2648                 {
2649                         // nothing to do
2650                 }
2651                 else if (!strcmp(pchunk->id, "BONENAMES"))
2652                 {
2653                         pskboneinfo_t *p;
2654                         if (recordsize != sizeof(*p))
2655                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2656                         // byteswap in place and keep the pointer
2657                         numanimbones = numrecords;
2658                         animbones = (pskboneinfo_t *)animbuffer;
2659                         // NOTE: supposedly psa does not need to match the psk model, the
2660                         // bones missing from the psa would simply use their base
2661                         // positions from the psk, but this is hard for me to implement
2662                         // and people can easily make animations that match.
2663                         if (numanimbones != numbones)
2664                                 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2665                         for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2666                         {
2667                                 p->numchildren = LittleLong(p->numchildren);
2668                                 p->parent = LittleLong(p->parent);
2669                                 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2670                                 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2671                                 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2672                                 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2673                                 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2674                                 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2675                                 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2676                                 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2677                                 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2678                                 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2679                                 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2680 #ifdef PSKQUATNEGATIONS
2681                                 if (index)
2682                                 {
2683                                         p->basepose.quat[0] *= -1;
2684                                         p->basepose.quat[1] *= -1;
2685                                         p->basepose.quat[2] *= -1;
2686                                 }
2687                                 else
2688                                 {
2689                                         p->basepose.quat[0] *=  1;
2690                                         p->basepose.quat[1] *= -1;
2691                                         p->basepose.quat[2] *=  1;
2692                                 }
2693 #endif
2694                                 if (p->parent < 0 || p->parent >= numanimbones)
2695                                 {
2696                                         Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2697                                         p->parent = 0;
2698                                 }
2699                                 // check that bones are the same as in the base
2700                                 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2701                                         Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2702                         }
2703                         animbuffer = p;
2704                 }
2705                 else if (!strcmp(pchunk->id, "ANIMINFO"))
2706                 {
2707                         pskaniminfo_t *p;
2708                         if (recordsize != sizeof(*p))
2709                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2710                         // byteswap in place and keep the pointer
2711                         numanims = numrecords;
2712                         anims = (pskaniminfo_t *)animbuffer;
2713                         for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2714                         {
2715                                 p->numbones = LittleLong(p->numbones);
2716                                 p->playtime = LittleFloat(p->playtime);
2717                                 p->fps = LittleFloat(p->fps);
2718                                 p->firstframe = LittleLong(p->firstframe);
2719                                 p->numframes = LittleLong(p->numframes);
2720                                 if (p->numbones != numbones)
2721                                         Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2722                         }
2723                         animbuffer = p;
2724                 }
2725                 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2726                 {
2727                         pskanimkeys_t *p;
2728                         if (recordsize != sizeof(*p))
2729                                 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2730                         numanimkeys = numrecords;
2731                         animkeys = (pskanimkeys_t *)animbuffer;
2732                         for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2733                         {
2734                                 p->origin[0] = LittleFloat(p->origin[0]);
2735                                 p->origin[1] = LittleFloat(p->origin[1]);
2736                                 p->origin[2] = LittleFloat(p->origin[2]);
2737                                 p->quat[0] = LittleFloat(p->quat[0]);
2738                                 p->quat[1] = LittleFloat(p->quat[1]);
2739                                 p->quat[2] = LittleFloat(p->quat[2]);
2740                                 p->quat[3] = LittleFloat(p->quat[3]);
2741                                 p->frametime = LittleFloat(p->frametime);
2742 #ifdef PSKQUATNEGATIONS
2743                                 if (index % numbones)
2744                                 {
2745                                         p->quat[0] *= -1;
2746                                         p->quat[1] *= -1;
2747                                         p->quat[2] *= -1;
2748                                 }
2749                                 else
2750                                 {
2751                                         p->quat[0] *=  1;
2752                                         p->quat[1] *= -1;
2753                                         p->quat[2] *=  1;
2754                                 }
2755 #endif
2756                         }
2757                         animbuffer = p;
2758                         // TODO: allocate bonepose stuff
2759                 }
2760                 else
2761                         Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2762         }
2763
2764         if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights || !numanims || !anims || !numanimkeys || !animkeys)
2765                 Host_Error("%s: missing required chunks", loadmodel->name);
2766
2767         loadmodel->numframes = 0;
2768         for (index = 0;index < numanims;index++)
2769                 loadmodel->numframes += anims[index].numframes;
2770
2771         if (numanimkeys != numbones * loadmodel->numframes)
2772                 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2773
2774         meshvertices = numvtxw;
2775         meshtriangles = numfaces;
2776
2777         // load external .skin files if present
2778         skinfiles = Mod_LoadSkinFiles();
2779         if (loadmodel->numskins < 1)
2780                 loadmodel->numskins = 1;
2781         loadmodel->num_bones = numbones;
2782         loadmodel->num_poses = loadmodel->numframes;
2783         loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2784         loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2785         loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2786         loadmodel->surfmesh.num_vertices = meshvertices;
2787         loadmodel->surfmesh.num_triangles = meshtriangles;
2788         // do most allocations as one merged chunk
2789         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);
2790         data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2791         loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2792         loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2793         loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2794         loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2795         loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2796         loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2797         loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2798         loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2799         loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2800         loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2801         loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += loadmodel->surfmesh.num_vertices * sizeof(int[4]);
2802         loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[4]);
2803         loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2804         loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2805         loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2806         loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2807         if (loadmodel->surfmesh.num_vertices <= 65536)
2808                 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2809         loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
2810
2811         for (i = 0;i < loadmodel->numskins;i++)
2812         {
2813                 loadmodel->skinscenes[i].firstframe = i;
2814                 loadmodel->skinscenes[i].framecount = 1;
2815                 loadmodel->skinscenes[i].loop = true;
2816                 loadmodel->skinscenes[i].framerate = 10;
2817         }
2818
2819         // create surfaces
2820         for (index = 0, i = 0;index < nummatts;index++)
2821         {
2822                 // since psk models do not have named sections, reuse their shader name as the section name
2823                 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2824                 loadmodel->sortedmodelsurfaces[index] = index;
2825                 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2826                 loadmodel->data_surfaces[index].num_firstvertex = 0;
2827                 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2828         }
2829
2830         // copy over the vertex locations and texcoords
2831         for (index = 0;index < numvtxw;index++)
2832         {
2833                 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
2834                 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
2835                 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
2836                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
2837                 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
2838         }
2839
2840         // loading the faces is complicated because we need to sort them into surfaces by mattindex
2841         for (index = 0;index < numfaces;index++)
2842                 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
2843         for (index = 0, i = 0;index < nummatts;index++)
2844         {
2845                 loadmodel->data_surfaces[index].num_firsttriangle = i;
2846                 i += loadmodel->data_surfaces[index].num_triangles;
2847                 loadmodel->data_surfaces[index].num_triangles = 0;
2848         }
2849         for (index = 0;index < numfaces;index++)
2850         {
2851                 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
2852                 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
2853                 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
2854                 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
2855         }
2856
2857         // copy over the bones
2858         for (index = 0;index < numbones;index++)
2859         {
2860                 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
2861                 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
2862                 if (loadmodel->data_bones[index].parent >= index)
2863                         Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
2864         }
2865
2866         // sort the psk point weights into the vertex weight tables
2867         // (which only accept up to 4 bones per vertex)
2868         for (index = 0;index < numvtxw;index++)
2869         {
2870                 int l;
2871                 float sum;
2872                 for (j = 0;j < numrawweights;j++)
2873                 {
2874                         if (rawweights[j].pntsindex == vtxw[index].pntsindex)
2875                         {
2876                                 int boneindex = rawweights[j].boneindex;
2877                                 float influence = rawweights[j].weight;
2878                                 for (l = 0;l < 4;l++)
2879                                 {
2880                                         if (loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] < influence)
2881                                         {
2882                                                 // move lower influence weights out of the way first
2883                                                 int l2;
2884                                                 for (l2 = 3;l2 > l;l2--)
2885                                                 {
2886                                                         loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l2] = loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l2-1];
2887                                                         loadmodel->surfmesh.data_vertexweightindex4i[index*4+l2] = loadmodel->surfmesh.data_vertexweightindex4i[index*4+l2-1];
2888                                                 }
2889                                                 // store the new weight
2890                                                 loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] = influence;
2891                                                 loadmodel->surfmesh.data_vertexweightindex4i[index*4+l] = boneindex;
2892                                                 break;
2893                                         }
2894                                 }
2895                         }
2896                 }
2897                 sum = 0;
2898                 for (l = 0;l < 4;l++)
2899                         sum += loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l];
2900                 if (sum && fabs(sum - 1) > (1.0f / 256.0f))
2901                 {
2902                         float f = 1.0f / sum;
2903                         for (l = 0;l < 4;l++)
2904                                 loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] *= f;
2905                 }
2906         }
2907
2908         // set up the animscenes based on the anims
2909         for (index = 0, i = 0;index < numanims;index++)
2910         {
2911                 for (j = 0;j < anims[index].numframes;j++, i++)
2912                 {
2913                         dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
2914                         loadmodel->animscenes[i].firstframe = i;
2915                         loadmodel->animscenes[i].framecount = 1;
2916                         loadmodel->animscenes[i].loop = true;
2917                         loadmodel->animscenes[i].framerate = 10;
2918                 }
2919         }
2920
2921         // calculate the scaling value for bone origins so they can be compressed to short
2922         biggestorigin = 0;
2923         for (index = 0;index < numanimkeys;index++)
2924         {
2925                 pskanimkeys_t *k = animkeys + index;
2926                 biggestorigin = max(biggestorigin, fabs(k->origin[0]));
2927                 biggestorigin = max(biggestorigin, fabs(k->origin[1]));
2928                 biggestorigin = max(biggestorigin, fabs(k->origin[2]));
2929         }
2930         loadmodel->num_posescale = biggestorigin / 32767.0f;
2931         loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
2932
2933         // load the poses from the animkeys
2934         for (index = 0;index < numanimkeys;index++)
2935         {
2936                 pskanimkeys_t *k = animkeys + index;
2937                 float quat[4];
2938                 Vector4Copy(k->quat, quat);
2939                 if (quat[3] > 0)
2940                         Vector4Negate(quat, quat);
2941                 Vector4Normalize2(quat, quat);
2942                 // compress poses to the short[6] format for longterm storage
2943                 loadmodel->data_poses6s[index*6+0] = k->origin[0] * loadmodel->num_poseinvscale;
2944                 loadmodel->data_poses6s[index*6+1] = k->origin[1] * loadmodel->num_poseinvscale;
2945                 loadmodel->data_poses6s[index*6+2] = k->origin[2] * loadmodel->num_poseinvscale;
2946                 loadmodel->data_poses6s[index*6+3] = quat[0] * 32767.0f;
2947                 loadmodel->data_poses6s[index*6+4] = quat[1] * 32767.0f;
2948                 loadmodel->data_poses6s[index*6+5] = quat[2] * 32767.0f;
2949         }
2950         Mod_FreeSkinFiles(skinfiles);
2951         Mem_Free(animfilebuffer);
2952         Mod_MakeSortedSurfaces(loadmodel);
2953
2954         // compute all the mesh information that was not loaded from the file
2955         // TODO: honor smoothing groups somehow?
2956         if (loadmodel->surfmesh.data_element3s)
2957                 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2958                         loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2959         Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2960         Mod_BuildBaseBonePoses();
2961         Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, true);
2962         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);
2963         Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2964         Mod_Alias_CalculateBoundingBox();
2965
2966         loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
2967 }