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