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