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