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