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