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