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